PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Rotationseigenschaft von VOBs



Fizzban
12.06.2004, 09:22
Weiß zufällig jemand, wie die Rotation-Eigenschaft trafoOSToWSRot von VOBs codiert ist?

Ich konnte nur herausbekommen, dass es sich dabei um 36 Bytes handelt, die als Folge von zweistelligen hexadezimalen Zahlen dargestellt werden.

Was die einzelnen Bytes bedeuten, entzieht sich aber meinen Verständnis. :confused:

HornOx
12.06.2004, 11:02
Ist die Transformations Matrix Objectspace to Worldspace. 3x3 Floats, jeweils 4 Byte.
fn raw2float raw=( --nicht optimiert, halbwegs leserlich ;)
--24 Bits Zahl, 1 Bit vorzeichen, 7 Bit Exponent
--(zahl+2^23)*2^(exponent-128-22)
--bitordnung siehe code
local raw1=("0x"+raw[5]+raw[6]+raw[3]+raw[4]+raw[1]+raw[2]) as integer
local raw2=("0x"+raw[7]+raw[8]) as integer
local vorzeichen=bit.get raw2 8
raw2=bit.shift (bit.and raw2 0x7f) 1
if (bit.get raw1 24) do ( --unschön aber shift nach rechts funktioniert nicht :(
raw2=bit.or raw2 1
raw1=bit.and raw1 0x7fffff
)
-- print raw1
-- print raw2
-- print vorzeichen
if vorzeichen then
-(raw1+8388608)*(pow 2 (raw2-150))
else
(raw1+8388608)*(pow 2 (raw2-150))
)
Ist ein alte 3ds max skript funktion von mir die die einzelnen raw werte(jeweils 8 Zeichen bzw. 4 Byte bzw 1 float Wert) in eine normale Flieskommazahl umwandelt (_sehr_ umständlich um Bugs von 3ds max 4.0 zu umgehn), daraus kannst du dir die Umwandlung raw->float rauslesen und ich spar mir die umständlichen Erklärungen ;). Wenn man noch trafoOSToWSPos an die Matrix anhängt bekommt man übrigends etwas das mit <node>.transform von 3ds max kompatibel ist...

Fizzban
12.06.2004, 17:05
Danke, funktioniert wunderbar.. Endlich kann ich mit dem Wert auch außerhalb vom Spacer etwas anfangen.. :D

HornOx
12.06.2004, 22:41
Aus purer neugier (und weil ich deine ICQ UIN nicht habe im Forum): Was willst du mit dem Wert anfangen?

Fizzban
12.06.2004, 23:31
Es geht um die Perfektionierung meines ZEN<->CEN-Konvertierungsprogrammes.. CEN ist ein an ZEN angelehntes Format, welches aber vernünftig von CVS verwaltet werden kann.

Also nicht mehr 50% veränderte Zeilen, wenn man nur ein neues VOB hinzufügt. Dadurch können auch mehrere Personen gleichzeitig an einer Welt arbeiten und CVS verschmilzt die Änderungen automatisch.

MrMilti
12.02.2005, 04:29
DANKE, DANKE, DANKE
Endlich funktioniert es.
Hat mal jemand einen Weg, um diesen Vorgang umzukehren?
Also aus floats raws zu machen?
Ich hab mir das script angesehen, aber an den bit.shifts verzweifel ich total

EDIT:
Ok, ich schreib mir selber grad ein Programm und da nun meine Frage:
Wie kommt man auf den raw2 wert?
das bit.shift verwirrt mich nämlich zusehendst. Ichhab versucht das nachzuvollziehen, aber irgendwie check ich das nicht

HornOx
12.02.2005, 18:24
Uralt Threadabonierung...

fn float2raw zahl=(
if (zahl==0) do return "00000000" --kommt häufig vor...
local vorzeichen,exponent
vorzeichen=(zahl<0)
exponent=floor (log (abs zahl)/log 2)+127
zahl=((abs(zahl)*(pow 2 (150-exponent)))-2^23) as integer
if zahl < 0 do zahl=0 --wegen fließkommafehlern bei der log-rechnung...
if zahl > 2^23 do zahl=0x7fffff
if (bit.get exponent 1) do zahl+=0x800000
exponent=(exponent/2) as integer
if vorzeichen do exponent+=0x80
zahl=bit.intashex zahl
exponent=bit.intashex exponent
while (zahl.count<6) do zahl="0"+zahl
while (exponent.count<2) do exponent="0"+exponent
--print (raw2float (zahl[5]+zahl[6]+zahl[3]+zahl[4]+zahl[1]+zahl[2]+exponent[1]+exponent[2]))
zahl[5]+zahl[6]+zahl[3]+zahl[4]+zahl[1]+zahl[2]+exponent[1]+exponent[2]
)
Die Funktion ist vermutlich schon älter als ein Jahr alt (Code altert zwar nicht aber mein Stil hat sich geändert, ich erkenne das Teil kaum wieder("zahl==0" bei float? Wie konnte ich nur?) aber sollte wenn ich mich recht erinnere bei 3ds max 4 funktionieren. 3ds max 7 sollte auch gehn, aber da gibts die oben erwähnten Bugs nicht mehr, also ggf umschreiben/optimieren damit's schneller wird. Oder gleich eine C++ dll schreiben, da sollte das sehr leicht und sehr schnell gehn.

Wird das auch ein Versuch per Maxscript *.zens in 3ds Max lesen, bearbeiten, erstellen und schreiben zu können? Meiner ist damals gescheitert weil 3ds max und mein PC bei mehreren tausend Objekten sehr langsam wurde, aber das sollte mit einer aktuallisierten 3ds Max Version und besserer Hardware besser aussehn :)

MrMilti
12.02.2005, 18:29
Also ursprünglich ging es mir nur darum, mein Stadttor präzise in das dafür vorgesehene Loch zu setzen, aber mittlerweile will ich einfach mal programmieren mit c++ lernen.
Und dann verpack ich das in eine hübsche Form und hab dann hoffentlich was zum drauf stolz sein *g*

jedenfalls danke für deine hilfe

gothicfan359
12.02.2005, 19:30
@MrMilti: Mich würde interessieren, warum du das Stadttor nicht einfach in das Mesh einfügst, oder gibt es da einen guten Grund. Den würde ich aber dann nämlich hören, da ich es so einfach nicht verstehe, warum du das Stadttor nicht einfach im 3dsmax in die gewünschte Position bringst?

MrMilti
12.02.2005, 21:11
Da gibts einen sehr sehr einfachen grund.
das soll ja schliesslich auf und zu gehen können!

Würd ich es ins levelmesh integrieren, würde das ja völlig statisch sein, das in unserem Storyverlauf eher ungünstig wäre

gothicfan359
13.02.2005, 06:40
Achso, das ist natürlich ein guter Grund, von den bisherigen Screens von Morgendämmerung kann man da ja noch nichts sehen, was darauf hinweist und man erfährt es auch nicht, aber egal.

Sektenspinner
15.11.2007, 16:33
*buddel*

Ich bin wie Fizzban in der Lage, dass ich die Rotationsinformation auswerten muss.
Ich brauche es für ein Tool, das Zens verschieben und drehen können soll.

Leider habe ich schon direkt zu Beginn das Problem, dass ich entweder das Format des Hex-Strings nicht verstehe, oder aber das Prinzip einer Transformationsmatrix falsch verstanden habe.

Meine Ansicht nach müsste ein ungedrehtes Objekt im Spacer die Transformationsmatrix:

1 0 0
0 1 0
0 0 1besitzen (also die Einheitsmatrix). Der Vektor eines Punktes in dem Objekt wird mit der Matrix multipliziert und siehe da, es kommt der selbe Vektor heraus.

Der Hex-String, den ich für ein ungedrehtes Objekt bekomme, ist aber folgender:

0000803f0000000000000000000000000000803f0000000000000000000000000000803f
Der erste float, der meiner Ansicht nach eine 1 sein müsste, ist: 0000803f
Nach meinem Verständnis von floats und folgendem Hinweis von HornOx
--24 Bits Zahl, 1 Bit vorzeichen, 7 Bit Exponent ist das aber:
Mantisse: 1.5 (eine Eins ist immer da und mit der "8" ist die erste nachkommastelle gesetzt)
Vorzeichen: + (bei der "3" ist das erste bit nicht gesetzt)
Exponent: "3f" ???

Und mit einer Mantisse von 1.5 kommt man niemals auf den Zahlenwert 1. Auch verstehe ich nicht, wie ich den Exponenten zu interpretieren habe.

Leider kann ich auch kein Java und verstehe den Quelltext (http://forum.worldofplayers.de/forum/showthread.php?p=570420&#post570420) von HornOx nicht. :dnuhr:

Ich hoffe ihr könnt mir weiterhelfen, auch wenn das Thema nun schon seit fast drei Jahren ruht.:gratz

NicoDE
15.11.2007, 17:55
Der erste float, der meiner Ansicht nach eine 1 sein müsste, ist: 0000803fDer hexadezimale Wert der ersten (32-Bit) Fließkommazahl ist 0x3F800000.
Rohdaten werden von Gothic als Oktett(8-Bit Byte)-Array gespeichert. Da Gothic nur auf LittleEndian-Systemen läuft, befindet sich das niederwertigste Oktett an der ersten Position des Arrays.

Für die erste 32-Bit Fließkommazahl:
"0000803f" -> 0x00 0x00 0x80 0x3F -> 0x3F800000

Auf LittleEndian-Systemen kann man also die Oktetts nacheinander direkt in die Variable schreiben (oder ein temporäres Array verwenden und die Daten in die Variable schreiben).

http://de.wikipedia.org/wiki/IEEE_754

ps: Welche Sprache/Entwicklungsumgebung verwendest du denn?

Sektenspinner
15.11.2007, 20:52
http://de.wikipedia.org/wiki/IEEE_754§ice

Ich habs! Da war das Problem! Die Mantisse ist 23 bit lang und der Exponent 8 bit und nicht die Mantisse 24 bit und der Exponent nur 7.
Das hat HornOx verkehrt im Kommentar seines Algorithmus stehen! Böse Verwirrungstaktik! ;)


ps: Welche Sprache/Entwicklungsumgebung verwendest du denn?Delphi.
Ich weiß nicht ob es da eine Möglichkeit gibt die floats automatisiert einzulesen, eigentlich hatte ich vor, das von Hand zu machen, also Exponent und Mantisse berechnen und dann den float ausrechnen. Aber wenn du eine viel einfachere Idee hast... Immer her damit!


Da Gothic nur auf LittleEndian-Systemen läuft, befindet sich das niederwertigste Oktett an der ersten Position des Arrays.Ist das nicht andersherum? Die BigEndian Systeme sind doch die gewöhnungsbedürftigen, oder nicht? Little Endian sind die, die man von vorne nach hinten chronologisch lesen kann. Da bei Gothic umsortiert wird, müsste das doch Big Endian sein?

HornOx
15.11.2007, 21:34
Uralt Threadabonierung...Déjà-vu :rolleyes:
Das hat HornOx verkehrt im Kommentar seines Algorithmus stehen! Böse Verwirrungstaktik! AFAIR hab ich damals noch keine Ahnung gehabt das es ein Hidden Bit (http://de.wikipedia.org/wiki/Gleitkomma#Hidden_Bit) gibt und habe deshalb nicht nur falsch kommentiert sondern einen Fehler im Code eingebaut - aber der scheint sich bei den für Gothic üblichen Werten nicht auszuwirken, zumindest waren meine Vobs auch in 3DS Max immer da wo sie auch im Spacer waren :)

NicoDE
16.11.2007, 14:52
Delphi.
Ich weiß nicht ob es da eine Möglichkeit gibt die floats automatisiert einzulesen, eigentlich hatte ich vor, das von Hand zu machen, also Exponent und Mantisse berechnen und dann den float ausrechnen. Aber wenn du eine viel einfachere Idee hast... Immer her damit!C/C++ "float" entspricht dem Typ "Single" in Delphi32.
Wenn man die Datentypen entsprechend definiert, dann kann man den Raw-Text einlesen und direkt in die Struktur schreiben.

Hier ein Beispiel:
function RawTextToBuffer(AText: PChar; ABuff: PByte; ASize: Cardinal): Boolean;
{$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
begin
Result := (ASize = 0);
if Result or not Assigned(ABuff) or not Assigned(AText) then
Exit;
while ASize > 0 do
begin
case AText^ of
'0'..'9':
ABuff^ := (Ord(AText^) - Ord('0')) shl 4;
'A'..'F':
ABuff^ := (Ord(AText^) - (Ord('A') - 10)) shl 4;
'a'..'f':
ABuff^ := (Ord(AText^) - (Ord('a') - 10)) shl 4;
else
Exit;
end;
Inc(AText);
case AText^ of
'0'..'9':
ABuff^ := ABuff^ or (Ord(AText^) - Ord('0'));
'A'..'F':
ABuff^ := ABuff^ or (Ord(AText^) - (Ord('A') - 10));
'a'..'f':
ABuff^ := ABuff^ or (Ord(AText^) - (Ord('a') - 10));
else
Exit;
end;
Inc(AText);
Inc(ABuff);
Dec(ASize);
end;
Result := True;
end;

type
PFloat = ^TFloat;
TFloat = Single;
PVector3F = ^TVector3F;
TVector3F = array [0..2] of TFloat;
PMatrix33F = ^TMatrix33F;
TMatrix33F = array [0..2] of TVector3F;

function RawTextToMatrix33F(AText: PChar; out AMatrix: TMatrix33F): Boolean;
{$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
begin
Result := RawTextToBuffer(AText, PByte(Addr(AMatrix)), SizeOf(TMatrix33F));
end;

const
IdentityMatrix33F: TMatrix33F = (
(1.0, 0.0, 0.0),
(0.0, 1.0, 0.0),
(0.0, 0.0, 1.0)
);

function CompareMatrix33F(const AMatrix1, AMatrix2: TMatrix33F): Boolean;
{$IFDEF SUPPORTS_INLINE} inline; {$ENDIF}
var
Val1: PLongWord;
Val2: PLongWord;
Loop: Integer;
begin
Val1 := PLongWord(Addr(AMatrix1));
Val2 := PLongWord(Addr(AMatrix2));
for Loop := 1 to SizeOf(TMatrix33F) div SizeOf(LongWord) do
begin
Result := (Val1^ = Val2^);
if not Result then
Exit;
Inc(Val1);
Inc(Val2);
end;
end;

////////////////////////////////////////////////////////////////////////////////

function UnitTest(): Boolean;
const
RawText =
'0000803f' + '00000000' + '00000000' +
'00000000' + '0000803f' + '00000000' +
'00000000' + '00000000' + '0000803f';
var
Matrix: TMatrix33F;
begin
Result := RawTextToMatrix33F(RawText, Matrix);
if Result then
Result := CompareMatrix33F(Matrix, IdentityMatrix33F);
end;Das Beispiel ist auf Geschwindigkeit optimiert. Deswegen sehen Teile des Quellcodes etwas kryptisch aus. Es wird aber nichts anderes gemacht, als die zwei Zeichen eines Bytes im RawText in ein Byte zu konvertieren und in die Variable zu schreiben.

edit: inline-Support für neuere Delphi-Versionen.

Sektenspinner
17.11.2007, 19:34
@NicoDE: Vielen Dank! Du hast mir mal wieder ordentlich weitergeholfen! Dein Weg ist deutlich einfacher und wohl auch schneller als das, was ich versucht habe!

Eine Sache hat allerdings nicht gestimmt: Gothic notiert die Drehmatrix nicht so wie von dir vermutet, also nicht Zeilenweise sondern Spaltenweise. Ich musste sie also hinterher nochmal drehen.

Das Programm funktioniert soweit zu meiner Zufriedenheit, eine Sache bekomme ich jedoch nicht hin: Mover drehen und verschieben!
Ich habe mich zwar noch nicht so sehr damit beschäftigt, aber mangelns konkreter Ideen frage ich lieber jetzt anstatt nach ein paar Stunden festzustellen, dass ichs nicht herausbekomme:

Wie ist der keyframes Wert beschaffen? Er ist pro Frame anscheinend 28 Bytes, also sieben floats lang. Ein Mover im Ursprung mit einem Keyframe hat als Floats die Werte:
0 0 0 0 0 0 1

Mir leuchtet das nicht ein.

Edit: Ich habe eine ZEN spaßeshalber mal um 90 Grad um die X Achse gedreht um zu testen ob auch alles funktioniert. Nunja, das meiste funktioniert, aber einige wenige Vobs wurden falsch platziert. Das konnte ich bei der Drehung um die Y-Achse bislang nicht beoabachten. Woran könnten solche sporadischen Fehler liegen? Gibt es noch irgendwelche Besonderheiten des ZEN-Formats, die beachtet werden müssen?

NicoDE
17.11.2007, 23:53
Ein KeyFrame dürfte einen Vector (xyz) für die Position und ein Quaternion (xyzw) für die Bewegung enthalten.

Sektenspinner
18.11.2007, 14:27
Schon mal danke soweit. Ich habe mich jetzt ein paar Stunden mit dem Stoff auseinandergesetzt, fühle mich aber mit meiner Schulmathematik auf der weiten Flur ein wenig alleingelassen.
Ich kann mir nur grob vorstellen, was Quaternionen sind und kann die Umwandlung eines Quaternions in eine Drehmatrix nicht nachvollziehen.

Auf dieser (http://www.calc3d.com/help/gquaternion.html) Seite habe ich allerdings die Formeln gefunden, die ich anscheinend brauche. (Umwalndung Rotationsmatrix <-> Quaternion)

Gehe ich richtig in der Annahme, dass ich für eine gegebene Drehmatrix R (um die ich den Mover drehen will) und ein gegebenes Quaternion Q des Movers das neue Quaternion Q' folgendermaßen ausrechene:

1.) Q in die Drehmatrix M umwandeln
2.) Das Produkt R*M ausrechnen.
3.) R*M in das Quaternion Q' umwalnden.

?

Sektenspinner
20.11.2007, 18:09
Ich bin nun ein Stückchen weitergekommen, und war eigentlich der Meinung, alles richtig gemacht zu haben. Auf dieser (http://www.cprogramming.com/tutorial/3d/quaternions.html) (und anderen) Seiten habe ich folgendes gefunden:
Let Q1 and Q2 be two quaternions, which are defined, respectively, as (w1, x1, y1, z1) and (w2, x2, y2, z2).
(Q1 * Q2).w = (w1w2 - x1x2 - y1y2 - z1z2)
(Q1 * Q2).x = (w1x2 + x1w2 + y1z2 - z1y2)
(Q1 * Q2).y = (w1y2 - x1z2 + y1w2 + z1x2)
(Q1 * Q2).z = (w1z2 + x1y2 - y1x2 + z1w2]Das habe ich so angewendet. Der Algorithmus funktioniert, wenn der Mover vor der Drehung in der Ausgangssituation steht (als Drehung das Einheitsquarternion besitzt). Ansonsten ist das Ergebnis meist falsch.

Könnte das daran liegen, dass Gothic in einem linkshändigen Koordinatensystem arbeitet? Gibt es sonst irgendwelche Fallen? Ich bin mit meinem Latein am Ende.

Auch weiß ich nicht, was die "originalPose" Eigenschaft von Kamerakeyframes soll. Was bei allen Göttern ist das:

originalPose=raw:5e30203e0000000020d97cbfa44aecc1000000000000803f00000000b7e6ef4 220d97c3f000000005e30203ed6435ec00000000000000000000000000000803f

NicoDE
20.11.2007, 18:29
Auch weiß ich nicht, was die "originalPose" Eigenschaft von Kamerakeyframes soll.Das könnte die Matrix(4x4) des referenzierten (vorherigen) Frames sein.

Mit 3D-Mathematik kann ich dir leider nicht weiterhelfen. Kenne mich damit nicht sonderlich aus (und mir fehlt die Zeit es wieder aufzufrischen).