XML:OBAN: Difference between revisions

292 bytes added ,  6 January 2024
m
replaced matrix GIF with Math markup; had to change guide colors to suit what's available with Math's Tex implementation
No edit summary
m (replaced matrix GIF with Math markup; had to change guide colors to suit what's available with Math's Tex implementation)
 
(32 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{XML_File_Header | type=OBAN | prev=Mtrl | next=OBOA | name=Object Animation }}
{{XML_File_Header | prev=Mtrl | type=OBAN | next=OFGA | name=Object Animation}}


===general information===
==General information==
* The xml code on this page was tested with onisplit '''v0.9.61.0''', '''v0.9.68.0''', '''v0.9.82.0'''
* 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#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==
* 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 triggers]] and [[XML:DOOR|door]] files use '''global''' OBAN files
* some cutscene TRAM, animated cutscene objects and camera shots/animations use '''level specific''' OBAN files
* if you want to update level-specific OBANs used by ONLV, you must provide the ONLV along the OBANs in the package
* 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 56: 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 115: 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.


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


  <?xml version="1.0" encoding="utf-8"?>
  <?xml version="1.0" encoding="utf-8"?>
Line 137: 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 143: 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 149: 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]]


==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.


===wish list===
{| style="float:right;"
* TRAM import: dae + xml
!Single rotation matrices
** the dae section in the xml file should have an option to create a pelvis OBAN along with the TRAM (see [[XML:TRAM]], RealWorld flag for details)
|-
* dae to oni creation should also allow for OBANs (currently OBANs can only be imported via level master xml file)
|<math>R_x(\theta)=\begin{bmatrix}
** this would be very useful for editing/creating single OBAN files if the rest of the level don't need changes
\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}
===calculating a transform matrix step by step===
</math>
In some scenarios we need to build a new transform matrix, e.g. when making a new weapon particle emitter.
 
Those commands can be used to examine OniSplit's matrix calculation.
onisplit -create:oban OBAN OBAN/file.dae
onisplit -extract:xml OBAN OBAN/OBANfile.oni
 
Let's test some values.
 
xyz = 0
<InitialTransform>1 0 0 0 1 0 0 0 1 0 0 0</InitialTransform>
This doesn't tell us very much, at least we know that the last 3 value are positions.
{| class="wikitable" style="float:right; text-align:right"
| This formula is involved in building such matrix.
https://dl.dropboxusercontent.com/u/139715/OniGalore/rotation_of_transform_matrix.png
|}
|}
So the first 9 values have to contain the rotation.


x = 60
x = 60
  <InitialTransform><span style="background-color:#F77">1 0 0</span> <span style="background-color:#7F7">0 0.5    0.8660254</span> <span style="background-color:#77F">0 -0.8660254 0.5</span>    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
  <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:#F77">1 0 0</span> <span style="background-color:#7F7">0 cos(x) sin(x)</span>    <span style="background-color:#77F">0 -sin(x)    cos(x)<span>
                   <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>


y = 60
y = 60
  <InitialTransform><span style="background-color:#FF7">0.5    0 -0.8660254</span> <span style="background-color:#F7F">0 1 0</span> <span style="background-color:#7FF">0.8660254 0 0.5</span>    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
{| style="float:right;"
                   <span style="background-color:#FF7">cos(y) 0 -sin(y)</span>    <span style="background-color:#F7F">0 1 0</span> <span style="background-color:#7FF">sin(y)    0 cos(y)</span>
|-
|<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>


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>


z = 60
{| class="wikitable" style="float:right;"
<InitialTransform><span style="background-color:#777">0.5    0.8660254 0</span> <span style="background-color:#AAA">-0.8660254 0.5    0</span> <span style="background-color:#DDD">0 0 1</span> <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
|
                  <span style="background-color:#777">cos(z) sin(z)    0</span> <span style="background-color:#AAA">-sin(z)    cos(z) 0</span> <span style="background-color:#DDD">0 0 1</span>
[[User:Neo|Neo]] provided a little '''[http://mods.oni2.net/node/381 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'''


x = 60; y = 40
So the transform matrix is:
<InitialTransform>0.7660444 0.5566704      -0.321393818  0 0.5    0.8660254 0.6427877 -0.663413942  0.3830222    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
                  cos(y)    sin(x)*sin(y)  -cos(x)*sin(y) 0 cos(x)  sin(x)    sin(y)    -sin(x)*cos(y) cos(x)*cos(y)
                  cos(y)    -sin(x)*-sin(y) -cos(x)*sin(y) 0 cos(x)  sin(x)    sin(y)    -sin(x)*cos(y) cos(x)*cos(y)


x = 60; z = 40
: '''final rotation matrix; position X; position Y; position Z'''
<InitialTransform>0.7660444 0.321393818  0.5566704      -0.6427877 0.3830222        0.663413942  0 -0.8660254  0.5    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
                  cos(z)    cos(x)*sin(z) sin(x)*sin(z)  -sin(z)    cos(x)*cos(z)    sin(x)*cos(z) 0 -sin(x)    cos(x)
                  cos(z)    cos(x)*sin(z) -sin(x)*-sin(z) -sin(z)    cos(x)*cos(z)    sin(x)*cos(z) 0 -sin(x)    cos(x)


y = 60; z = 40
Mod Tool VBS code (rotations only):
<InitialTransform>0.3830222    0.6427877 -0.663413942  -0.321393818  0.7660444 0.5566704      0.8660254 0 0.5    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
* [[Mod_Tool/Scripting#Euler_rotation_-.3E_matrix|Euler rotation to matrix]]
                  cos(y)*cos(z) sin(z)    -sin(y)*cos(z) cos(y)*-sin(z) cos(z)    sin(y)*sin(z)  sin(y)    0 cos(y)
* [[Mod_Tool/Scripting#Matrix_-.3E_Euler_rotation|matrix to Euler rotation]]
                  cos(x)*cos(z) sin(z)    -sin(y)*cos(z) cos(y)*-sin(z) cos(z)    -sin(y)*-sin(z) sin(y)    0 cos(y)


x = 60; y = 40; z = 20
==Wish list==
<InitialTransform>0.719846249  0.6941092 -0.005813241 -0.262002677 0.279453874 0.9237208 0.642787635 -0.6634138 0.3830223    <font style="color:#AAAAAA">0 0 0</font></InitialTransform>
* 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).
                  cos(y)*cos(z)                                                                                  cos(x)*cos(y)
* 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}}
{{XML}}