XML:OBAN: Difference between revisions

From OniGalore
Jump to navigation Jump to search
m (Iritscen moved page OBD talk:OBAN to XML:OBAN without leaving a redirect)
m (replaced matrix GIF with Math markup; had to change guide colors to suit what's available with Math's Tex implementation)
 
(43 intermediate revisions by 4 users not shown)
Line 1: Line 1:
__TOC__
{{XML_File_Header | prev=Mtrl | type=OBAN | next=OFGA | name=Object Animation}}


{{Template:XMLModdingHints}}
==General information==
{| border=0 cellspacing=20 cellpadding=0 align=center
* The XML on this page was tested with OniSplit '''v0.9.61.0''', '''v0.9.68.0''', '''v0.9.82.0''', '''v0.9.96.0'''.
| The xml code on this page is compatible with onisplit '''v0.9.61.0''' and '''v0.9.68.0'''
** With v0.9.82.0, you can also convert the OBAN into a DAE file:
|}
:: "-extract:dae output src\OBANElevator.oni" exports the animation with a null node
::: In [[Mod_Tool#Scripting|Mod Tool]] the null node is named "unique" and holds keyframes; it can be replicated with ''activesceneroot.AddModel , "unique"''
:: "-extract:dae output src\OBANElevator.oni -geom:M3GMdebris.oni" exports animation with specified geometry
:: "-extract:dae output src\OBANElevator.oni -geom:camera" exports animation with camera
:* With v0.9.90.0, you can convert a camera DAE to OBAN (a camera root is not supported)
:: "-create:oban output src\file.dae"
* [[XML:TRIG|Laser trigger]] and [[XML:DOOR|door]] files use '''global''' OBANs.
* Some cutscene TRAMs, animated cutscene objects and camera shots/animations use '''level-specific''' OBANs.
* If you want to update level-specific OBANs used by an ONLV, you must provide the ONLV along with the OBANs in the package.
* Trivia: the [[:Image:Dream_obj_images_spawned.jpg|Dream Lab images]] use OBANs.
* Tutorial: [[Authoring_custom_camera_animations|Creating camera animations]]


 
==BSL support==
==[[OBD:OBAN|OBAN]]: Object Animation==
 
===general information===
* [[OBD_talk:TRIG|laser triggers]] and [[OBD:DOOR|door]] files use '''global''' OBAN files
* some cutscene TRAM, animated cutscene objects and camera shots/animations use '''level specific''' OBAN files
* trivia: also the [http://i305.photobucket.com/albums/nn207/unknownfuture/Oni_Galore_Images/XML_modding/dream_obj_images_spawned.jpg dream lab images] use OBANs
* tutorial: making [[AE:Authoring_custom_camera_animations|camera interpolations]]
 
 
===BSL support===
{| class="wikitable" width=100%
{| class="wikitable" width=100%
| '''animate object'''
| '''Animate object'''
| '''animate character'''
| '''Animate character'''
| '''animate camera'''
| '''Animate camera'''
|-
|-
| valign="top" | env_setanim ''object_id oban_name''
| valign="top" |
| chr_animate ''ai_name'' ''anim_name'' [''num_frames''] [''interp_frames'']<br> chr_animate ''script_id'' ''anim_name'' [''num_frames''] [''interp_frames'']
env_setanim ''object_id oban_name''
| valign="top" | cm_anim <nowiki>[look|move|both]</nowiki> ''oban_name''
|
<nowiki>chr_animate</nowiki> [''ai_name'' | ''script_id''] ''anim_name'' [''num_frames''] [''interp_frames'']<br>chr_envanim [''ai_name'' | ''script_id''] ''anim_name'' [norotation]<br>chr_envanim_block [''ai_name'' | ''script_id''] ''anim_name'' [norotation]
| valign="top" |
cm_anim <nowiki>[look | move | both]</nowiki> ''oban_name''
|-
|-
| '''animate object (range)'''
| '''Animate object (range)'''
| '''stop animated character'''
| '''Stop animating character'''
| '''interpolat between current and new camera position'''
| '''Interpolate between current and new camera position'''
|-
|-
| valign="top" | env_anim ''object_id'' [''object_id'']
| valign="top" |
| chr_envanim_stop ''ai_name''<br>chr_envanim_stop ''script_id''
env_anim ''object_id'' [''object_id'']
| valign="top" | cm_interpolate ''oban_name frame_number''
|
chr_envanim_stop ''ai_name''<br>chr_envanim_stop ''script_id''
| valign="top" |
cm_interpolate ''oban_name frame_number''
|}
|}


 
==XML structure==
===XML===
{| class="wikitable" width=100%
{| class="wikitable" width=100%
|width=120px| '''tag'''
|width=120px| '''Tag'''
|width=60px| '''type'''
|width=60px| '''Type'''
| '''description'''
| '''Description'''
|-
| <OBAN id="0">
|
| ID required. Unlike OBJC collections, this tag needs its ID attribute to be set. Since it's the first and only instance, it should be 0.
|-
|-
|valign=top| <Flags>
|valign=top| <Flags>
Line 49: Line 58:
: RandomStartFrame
: RandomStartFrame
: Autostart
: Autostart
:: autostart animation (after an animated object is created
:: autostart animation (after an animated object is created)
: ZAxisUp
: ZAxisUp
:: 3DSMax generated animation (has Z axis pointing up), all original door OBANs seem to have this flag
:: door OBANs use this
:: has Z axis pointing up
:: OBAN rotations and translations are treated relatively (as changes to the door's spawn rotation/position)
|-
|-
|valign=top| <InitialTransform>
|valign=top| <InitialTransform>
|valign=top| matrix4x3
|valign=top| matrix4x3
| Initial position transform matrix, last 3 values are X, Y, Z position values. X, Y, Z seem to be always 0 (or nearly 0) in door OBAN files. That would make sense because of their global use.
| Initial position transform matrix. Last 3 values are the position in X, Y, Z. The position seem to be always {0, 0, 0} (or nearly so) in door OBANs. That would make sense because of their global use.
|-
|-
| <BaseTransform>
| <BaseTransform>
| matrix4x3  
| matrix4x3  
| fixed transform matrix  
| Fixed transform matrix  
|-
|-
|valign=top| <FrameLength>
|valign=top| <FrameLength>
|valign=top| int16
|valign=top| int16
| the value must be equal to the last <Time> value plus 1 because <Time>0</Time> is also a frame; Oni crashes if you use a wrong value for <FrameLength>
| fubared animation frame length (in 1/60 seconds); does not work
|-
|-
| <FrameCount>
| <FrameCount>
| int16
| int16
| fubared animation frame length (in 1/60 seconds); does not work
| The value must be equal to the last &lt;Time> value plus 1, because &lt;Time>0&lt;/Time> is also a frame; Oni crashes if you use a wrong value for <FrameCount>.
|-
|-
| <HalfStopFrame>
| <HalfStopFrame>
| int16
| int16
| stop frame for the first "half" of the animation; used by door animations to distinguish between open and close sequences
| Stop frame for the first "half" of the animation; used by door animations to distinguish between open and close sequences.
|-
|-
| <KeyFrames>
| <KeyFrames>
|
|
| holds <OBANKeyFrame> tags
| Holds <OBANKeyFrame> tags.
|-
|-
| <Rotation>
|valign=top| <Rotation>
| quaternion
|valign=top| quaternion
| object rotation, can harvested from TRAM files
| Object rotation. (In the old days we harvested quaternions from TRAM files whereby a special version (0.9.54.0) of OniSplit was needed. Nowadays OBAN creation is fully supported by OniSplit. No more headaches.)
|-
|-
| <Translation>
| <Translation>
| vector3
| vector3
| x y z object position
| {X, Y, Z} object position
|-
|-
| <Time>
| &lt;Time>
| int32
| int32
| elapsed time in frames, use short intervals for smooth animations
| Elapsed time in frames; use short intervals for smooth animations.
|}
|}


;Transform matrices
;Transform matrices
:Like all matrices in Oni, they are composed of 3 vectors defining rotation/scaling/shearing and a 4th vector defining a translation.
:Like all matrices in Oni, they are composed of 3 vectors defining rotation/scaling/shearing and a 4th vector defining a translation.
:In the above table the 4 vectors are presented as rows ([[Wikipedia:row-major_order|Direct 3D convention]]), although OpenGL and Oni use them as columns.
:In the above table, the 4 vectors are presented as rows per [[wp:Row-_and_column-major_order|Direct3D convention]], although OpenGL and Oni use them as columns.
:[[Wikipedia:Transformation_matrix#Affine_transformations|Affine transformations]] use a 4x4 matrix with 4 extra coefficients (in the presentation above, one would add one column on the right):
:[[wp:Transformation_matrix#Affine_transformations|Affine transformations]] use a 4x4 matrix with 4 extra coefficients (in the presentation above, one would add one column on the right):
::three [[Wikipedia:3D_projection|projection transform]] coefficients (all of them are zero here); one final coefficient (always 1.0 for an affine transform matrix).
::Three [[wp:3D_projection|projection transform]] coefficients (all of them are zero here); one final coefficient (always 1.0 for an affine transform matrix).
:Alternatively, one can think of the 3x4 matrix as a 3x3 rotation/scaling matrix and a position vector
:Alternately, one can think of the 3x4 matrix as a 3x3 rotation/scaling matrix and a position vector:
::*Let X=(x, y, z) be the position of a vertex in the M3GM
::*Let X=(x, y, z) be the position of a vertex in the M3GM
::*Let M=(m11, m21, m31; m12, m22, m32; m13, m23, m33) be the 3x3 matrix
::*Let M=(m11, m21, m31; m12, m22, m32; m13, m23, m33) be the 3x3 matrix
Line 108: Line 119:
:The only transform that can't be handled by the quaternion+position is scaling/mirroring.
:The only transform that can't be handled by the quaternion+position is scaling/mirroring.
:Thus, the fixed transform is a scaling matrix most of the time (no rotation or translation).
:Thus, the fixed transform is a scaling matrix most of the time (no rotation or translation).
:On the [[OBD:OBAN|hex page]], the fixed transform scales the van up by 1.82 (along all three axes).
:In the example on the [[OBD:OBAN|OBD page]], the fixed transform scales the van up by 1.82 (along all three axes).
;Quaternions
;Quaternions
:Those are used in Oni whenever interpolation of 3D rotation is involved (e.g., [[OBD_talk:TRAM/raw0x34#Quaternions|TRAM rotation]])
:Those are used in Oni whenever interpolation of 3D rotation is involved (e.g. [[OBD_talk:TRAM/raw0x34#Quaternions|TRAM rotation]]).
:In this case, rotation at intermediate frames is interpolated from the keyframe quaternions.
:In this case, the rotation in intermediate frames is interpolated from the keyframe quaternions.
 


===code sample===
==XML sample==
'''''[...]''''' means other code blocks of <OBANKeyFrame>...</OBANKeyFrame>
Below, '''''[...]''''' means other blocks of <OBANKeyFrame>...</OBANKeyFrame>.


  <?xml version="1.0" encoding="utf-8"?>
  <?xml version="1.0" encoding="utf-8"?>
Line 130: Line 140:
                 <Rotation>1 1 1 1</Rotation>
                 <Rotation>1 1 1 1</Rotation>
                 <Translation>-225 9.3 -778.5</Translation>
                 <Translation>-225 9.3 -778.5</Translation>
                 <Time>0</Time>
                 <nowiki><Time>0</Time></nowiki>
             </OBANKeyFrame>
             </OBANKeyFrame>
             '''''[...]'''''
             '''''[...]'''''
Line 136: Line 146:
                 <Rotation>1 1 1 1</Rotation>
                 <Rotation>1 1 1 1</Rotation>
                 <Translation>-217 34.5 -778.5</Translation>
                 <Translation>-217 34.5 -778.5</Translation>
                 <Time>'''70'''</Time>
                 <nowiki><Time></nowiki>'''70'''<nowiki></Time></nowiki>
             </OBANKeyFrame>
             </OBANKeyFrame>
         </KeyFrames>
         </KeyFrames>
Line 142: Line 152:
  </Oni>
  </Oni>


==Calculating a quaternion==
An early attempt to harvest quaternions and positions from TRAM files with OniSplit [http://mods.oni2.net/node/38 v0.9.54.0] can be found [http://oni.bungie.org/forum/viewtopic.php?id=2276 over here]. But that script runs inside an Excel file, and Excel isn't a free program, nor is the code compatible with OpenOffice.


===data harvest from TRAM files===
VBS code snippets for use with Mod Tool can be found here:
It's possible to create animations in Mod Tool and making TRAM files out of them. Then you can extract the quaternions and rotations with onisplit [http://mods.oni2.net/node/38 v0.9.54.0] and use them for OBANs.
* [[Mod_Tool/Scripting#Euler_rotation_-.3E_quaternion|Euler rotation to quaternion]]
: [http://oni.bungie.org/community/forum/viewtopic.php?id=2276 HERE's] an excel macro to harvest such data for camera animations.
* [[Mod_Tool/Scripting#Quaternion_-.3E_Euler_rotation|quaternion to Euler rotation]]
 


===the dream lab riddle===
==Calculating a transform matrix==
The current AE fails to update the OBAN files for the dream lab photos.
In some scenarios we need to build a new transform matrix, e.g. when making a new weapon particle emitter. The first 9 values belong to a 3x3 rotation matrix. The last 3 values are the start positions.


{| class="wikitable"
{| style="float:right;"
! file
!Single rotation matrices
! old size
! new size
|-
|-
|width=140px|
|<math>R_x(\theta)=\begin{bmatrix}
OBANImage01
\color{Salmon}1 & \color{YellowGreen}0 &          \color{CornflowerBlue}0 \\
\color{Salmon}0 & \color{YellowGreen}\cos\theta & \color{CornflowerBlue}-\sin\theta \\
\color{Salmon}0 & \color{YellowGreen}\sin\theta & \color{CornflowerBlue}\cos\theta\end{bmatrix}
</math>
|}


OBANImage02
x = 60
<InitialTransform><span style="background-color:#F69289">1 0 0</span> <span style="background-color:#98CC70">0 0.5    0.8660254</span> <span style="background-color:#41B0E4">0 -0.8660254 0.5</span>    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
                  <span style="background-color:#F69289">1 0 0</span> <span style="background-color:#98CC70">0 cos(x) sin(x)</span>    <span style="background-color:#41B0E4">0 -sin(x)    cos(x)<span>


OBANImage03
y = 60
{| style="float:right;"
|-
|<math>R_x(\theta)=\begin{bmatrix}
\color{YellowOrange}\cos\theta  & \color{SpringGreen}0 & \color{ProcessBlue}\sin\theta \\
\color{YellowOrange}0          & \color{SpringGreen}1 & \color{ProcessBlue}0 \\
\color{YellowOrange}-\sin\theta & \color{SpringGreen}0 & \color{ProcessBlue}\cos\theta\end{bmatrix}
</math>
|}
<InitialTransform><span style="background-color:#FAA21A">0.5    0 -0.8660254</span> <span style="background-color:#C6DC67">0 1 0</span> <span style="background-color:#00B0F0">0.8660254 0 0.5</span>    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
                  <span style="background-color:#FAA21A">cos(y) 0 -sin(y)</span>    <span style="background-color:#C6DC67">0 1 0</span> <span style="background-color:#00B0F0">sin(y)    0 cos(y)</span>


OBANImage04
z = 60
{| style="float:right;"
|-
|<math>R_x(\theta)=\begin{bmatrix}
\color{OrangeRed}1 & \color{SeaGreen}0 &          \color{RoyalBlue}0 \\
\color{OrangeRed}0 & \color{SeaGreen}\cos\theta & \color{RoyalBlue}-\sin\theta \\
\color{OrangeRed}0 & \color{SeaGreen}\sin\theta & \color{RoyalBlue}\cos\theta\end{bmatrix}
</math>
|}
<InitialTransform><span style="background-color:#ED135A">0.5    0.8660254 0</span> <span style="background-color:#3FBC9D">-0.8660254 0.5    0</span> <span style="background-color:#0071BC">0 0 1</span> <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
                  <span style="background-color:#ED135A">cos(z) sin(z)    0</span> <span style="background-color:#3FBC9D">-sin(z)    cos(z) 0</span> <span style="background-color:#0071BC">0 0 1</span>


OBANImage05
{| class="wikitable" style="float:right;"
 
|  
OBANImage06
[[User:Neo|Neo]] provided a little '''[http://mods.oni2.net/node/381 matrix program]'''.
 
|}
OBANImage07
|width=140px|
5,93 KB (6.080 Bytes)
 
5,93 KB (6.080 Bytes)
 
5,93 KB (6.080 Bytes)
 
5,93 KB (6.080 Bytes)
 
5,93 KB (6.080 Bytes)
 
5,93 KB (6.080 Bytes)
 
5,93 KB (6.080 Bytes)
|width=140px|
6,56 KB (6.720 Bytes)
 
-
 
6,87 KB (7.040 Bytes)
 
5,90 KB (6.048 Bytes)
 
-
 
6,56 KB (6.720 Bytes)


-
The final rotation matrix becomes calculated from multiplication of all single rotation matrices whereby the order must be Z, then Y, then X.
|}


: '''Rotation matrix Z * rotation matrix Y * Rotation matrix X'''


====test 1: exchanging only the OBANs====
So the transform matrix is:
step by step:
* Let's use onisplit to export the original Oni\GameDataFolder\level13_Final archives.
* The dream lab photo OBANs are really inside that level. (OBANImage01.oni up to 07)
* Now we exchange those OBANs with the updated ones and rebuilding the raw/dat level archives of level 13.
* When playing the first dream lab cutscene, the photos are animated correctly.
* Conclusion: the new OBANs are okay.


====test2: comparing the OBAN AE install locations====
: '''final rotation matrix; position X; position Y; position Z'''
* 1) the OBANs are stored inside Edition\install\packages\Globalize\oni\level0_Final\level0_Final
* after package installation
** exported level0_Final contains: 1,3,4, 6 - the updated OBANs
** exported level13_Final contains: 1 - 7 - the old OBANs


* 2) the OBANs are stored inside Edition\install\packages\Globalize\oni\level13_Final
Mod Tool VBS code (rotations only):
* after package installation
* [[Mod_Tool/Scripting#Euler_rotation_-.3E_matrix|Euler rotation to matrix]]
** exported level0_Final contains: no OBANImage0X.oni as expected
* [[Mod_Tool/Scripting#Matrix_-.3E_Euler_rotation|matrix to Euler rotation]]
** exported level13_Final contains:
*** Image01 // 6,56 KB (6.720 Bytes) // new
*** Image02 // 5,93 KB (6.080 Bytes) // old
*** Image03 // 6,87 KB (7.040 Bytes) // new
*** Image04 // 5,90 KB (6.048 Bytes) // new
*** Image05 // 5,93 KB (6.080 Bytes) // old
*** Image06 // 6,56 KB (6.720 Bytes) // new
*** Image07 // 5,93 KB (6.080 Bytes) // old


The new files are in place. Why doesn't the cutscene work?
==Wish list==
* TRAM import: DAE + XML. The DAE section in the XML file should have an option to create a pelvis OBAN along with the TRAM (see [[XML:TRAM]]'s RealWorld flag for details).
* DAE to .oni creation should also allow for OBANs (currently OBANs can only be imported via the level's master XML file). This would be very useful for editing/creating single OBAN files if the rest of the level doesn't need changes.


[...]
{{XML}}

Latest revision as of 15:47, 6 January 2024

OBAN : Object Animation
XML modding tips
  • See HERE to start learning about XML modding.
  • See HERE if you are searching for information on how to handle object coordinates.
  • See HERE for some typical modding errors and their causes.
XML.png
XML

Mtrl << Other file types >> OFGA

switch to OBD page

General information

  • The XML on this page was tested with OniSplit v0.9.61.0, v0.9.68.0, v0.9.82.0, v0.9.96.0.
    • With v0.9.82.0, you can also convert the OBAN into a DAE file:
"-extract:dae output src\OBANElevator.oni" exports the animation with a null node
In Mod Tool the null node is named "unique" and holds keyframes; it can be replicated with activesceneroot.AddModel , "unique"
"-extract:dae output src\OBANElevator.oni -geom:M3GMdebris.oni" exports animation with specified geometry
"-extract:dae output src\OBANElevator.oni -geom:camera" exports animation with camera
  • With v0.9.90.0, you can convert a camera DAE to OBAN (a camera root is not supported)
"-create:oban output src\file.dae"
  • Laser trigger and door files use global OBANs.
  • Some cutscene TRAMs, animated cutscene objects and camera shots/animations use level-specific OBANs.
  • If you want to update level-specific OBANs used by an ONLV, you must provide the ONLV along with the OBANs in the package.
  • Trivia: the Dream Lab images use OBANs.
  • Tutorial: Creating camera animations

BSL support

Animate object Animate character Animate camera

env_setanim object_id oban_name

chr_animate [ai_name | script_id] anim_name [num_frames] [interp_frames]
chr_envanim [ai_name | script_id] anim_name [norotation]
chr_envanim_block [ai_name | script_id] anim_name [norotation]

cm_anim [look | move | both] oban_name

Animate object (range) Stop animating character Interpolate between current and new camera position

env_anim object_id [object_id]

chr_envanim_stop ai_name
chr_envanim_stop script_id

cm_interpolate oban_name frame_number

XML structure

Tag Type Description
<OBAN id="0"> ID required. Unlike OBJC collections, this tag needs its ID attribute to be set. Since it's the first and only instance, it should be 0.
<Flags> flag
NormalLoop
BackToBackLoop
RandomStartFrame
Autostart
autostart animation (after an animated object is created)
ZAxisUp
door OBANs use this
has Z axis pointing up
OBAN rotations and translations are treated relatively (as changes to the door's spawn rotation/position)
<InitialTransform> matrix4x3 Initial position transform matrix. Last 3 values are the position in X, Y, Z. The position seem to be always {0, 0, 0} (or nearly so) in door OBANs. That would make sense because of their global use.
<BaseTransform> matrix4x3 Fixed transform matrix
<FrameLength> int16 fubared animation frame length (in 1/60 seconds); does not work
<FrameCount> int16 The value must be equal to the last <Time> value plus 1, because <Time>0</Time> is also a frame; Oni crashes if you use a wrong value for <FrameCount>.
<HalfStopFrame> int16 Stop frame for the first "half" of the animation; used by door animations to distinguish between open and close sequences.
<KeyFrames> Holds <OBANKeyFrame> tags.
<Rotation> quaternion Object rotation. (In the old days we harvested quaternions from TRAM files whereby a special version (0.9.54.0) of OniSplit was needed. Nowadays OBAN creation is fully supported by OniSplit. No more headaches.)
<Translation> vector3 {X, Y, Z} object position
<Time> int32 Elapsed time in frames; use short intervals for smooth animations.
Transform matrices
Like all matrices in Oni, they are composed of 3 vectors defining rotation/scaling/shearing and a 4th vector defining a translation.
In the above table, the 4 vectors are presented as rows per Direct3D convention, although OpenGL and Oni use them as columns.
Affine transformations use a 4x4 matrix with 4 extra coefficients (in the presentation above, one would add one column on the right):
Three projection transform coefficients (all of them are zero here); one final coefficient (always 1.0 for an affine transform matrix).
Alternately, one can think of the 3x4 matrix as a 3x3 rotation/scaling matrix and a position vector:
  • Let X=(x, y, z) be the position of a vertex in the M3GM
  • Let M=(m11, m21, m31; m12, m22, m32; m13, m23, m33) be the 3x3 matrix
  • Let R=(m14, m24, m34) be the translation vector
Then the absolute position of the vertex in the 3D world will be: X M + R
(left multiplication is used because of the row-major notation above)
Initial transform matrix
It is used to position the object in the environment before the animation is played.
When the animation is played, they use the fixed transform matrix and a quaternion.
Fixed transform matrix
This transformation is applied before the quaternion+position transform at every keyframe.
The only transform that can't be handled by the quaternion+position is scaling/mirroring.
Thus, the fixed transform is a scaling matrix most of the time (no rotation or translation).
In the example on the OBD page, the fixed transform scales the van up by 1.82 (along all three axes).
Quaternions
Those are used in Oni whenever interpolation of 3D rotation is involved (e.g. TRAM rotation).
In this case, the rotation in intermediate frames is interpolated from the keyframe quaternions.

XML sample

Below, [...] means other blocks of <OBANKeyFrame>...</OBANKeyFrame>.

<?xml version="1.0" encoding="utf-8"?>
<Oni>
   <OBAN id="0">
       <Flags></Flags>
       <InitialTransform>1 0 0 0 1 0 0 0 1 -225 9.3 -778.5</InitialTransform>
       <BaseTransform>-1 0 0 0 -1 0 0 0 1 0 0 0</BaseTransform>
       <FrameLength>80</FrameLength>
       <FrameCount>71</FrameCount>
       <HalfStopFrame>0</HalfStopFrame>
       <KeyFrames>
           <OBANKeyFrame>
               <Rotation>1 1 1 1</Rotation>
               <Translation>-225 9.3 -778.5</Translation>
               <Time>0</Time>
           </OBANKeyFrame>
           [...]
           <OBANKeyFrame>
               <Rotation>1 1 1 1</Rotation>
               <Translation>-217 34.5 -778.5</Translation>
               <Time>70</Time>
           </OBANKeyFrame>
       </KeyFrames>
   </OBAN>
</Oni>

Calculating a quaternion

An early attempt to harvest quaternions and positions from TRAM files with OniSplit v0.9.54.0 can be found over here. But that script runs inside an Excel file, and Excel isn't a free program, nor is the code compatible with OpenOffice.

VBS code snippets for use with Mod Tool can be found here:

Calculating a transform matrix

In some scenarios we need to build a new transform matrix, e.g. when making a new weapon particle emitter. The first 9 values belong to a 3x3 rotation matrix. The last 3 values are the start positions.

Single rotation matrices

x = 60

<InitialTransform>1 0 0 0 0.5    0.8660254 0 -0.8660254 0.5    0 0 0</InitialTransform>
                  1 0 0 0 cos(x) sin(x)    0 -sin(x)    cos(x)

y = 60

<InitialTransform>0.5    0 -0.8660254 0 1 0 0.8660254 0 0.5    0 0 0</InitialTransform>
                  cos(y) 0 -sin(y)    0 1 0 sin(y)    0 cos(y)

z = 60

<InitialTransform>0.5    0.8660254 0 -0.8660254 0.5    0 0 0 1 0 0 0</InitialTransform>
                  cos(z) sin(z)    0 -sin(z)    cos(z) 0 0 0 1

Neo provided a little matrix program.

The final rotation matrix becomes calculated from multiplication of all single rotation matrices whereby the order must be Z, then Y, then X.

Rotation matrix Z * rotation matrix Y * Rotation matrix X

So the transform matrix is:

final rotation matrix; position X; position Y; position Z

Mod Tool VBS code (rotations only):

Wish list

  • TRAM import: DAE + XML. The DAE section in the XML file should have an option to create a pelvis OBAN along with the TRAM (see XML:TRAM's RealWorld flag for details).
  • DAE to .oni creation should also allow for OBANs (currently OBANs can only be imported via the level's master XML file). This would be very useful for editing/creating single OBAN files if the rest of the level doesn't need changes.