Notifications
Clear all

[Closed] Converting animation data from Y-up to Z-up

I’m currently working on an importer plugin using the Max SDK, and have run into a little trouble. The file format that I’m attempting to import uses a Y-up Z-forward coordinate system compared to Max’s Z-up. This isn’t a problem for vertices and bones, as I can easily swap the z and y values, but animations are another thing…
The file format actually has 2 versions, which both store the animation data in a slightly different way (1 stores the rotation and translation values of each frame in world space, the other in local/parent space). When importing the animations, I’m using the node’s default PRS controller, adding keyframes and setting the values on the Position and Rotation controllers. Here’s some code to show what I mean:


for (int k = 0; k < translationCount; k++) {
	Trans* t = translation[k];
	int kt = t->frame * 4800;
	Point3 p = Point3(t->val);

	if (isWorldSpace) {
		Matrix3 tm(1);
		tm.SetTrans(p);
		tm *= Inverse(parentTM);

		p = tm.GetTrans();
	}

	SuspendAnimate();
	AnimateOn();
	// pc = position controller
	pc->AddNewKey(TimeValue(kt), ADDKEY_SELECT);
	pc->SetValue(TimeValue(kt), p);
	ResumeAnimate();
}

// .. do the same for rotations, using quats ...
}

How would I go about converting the animation data I read in from the files into the correct coordinate system? I’ve tried multiplying the data by a rotation matrix, but to no avail. Any help would be appreciated.

Thanks in advance.

1 Reply

Your file format sounds like it uses the exact same coordinate system as my dotXSI file importer (Maxscript based).

You need to do a proper coordinate transformation on the file data… it’s not a simple matter of swapping Y and Z values– and this will apply to both bones and mesh data objects!

3ds Max Matrix = [ inverse 90 degree X rotation matrix ] * [ object world matrix ] * [ 90 deg X rotation matrix ]

If you’re setting the 3ds Max controller values then you’ll have to do things in parent space.

What I did was create custom attribute on each 3ds Max node (created when I come across an XSI “SI_Model” template) to read and store the animation data (pos, rot, scale) on each XSI “SI_Model” template (i.e., node). ***This data is stored in the custom attribute in XSI coordinate system!

I then wrote a recursive function to do coordinate transformation on this animation data to 3ds Max coordinate system for the hierarchy:

fn SetAnimation o frameTime = (
  	if classOf o == Point do ( --only write animation data for Point Helpers (i.e., bones)
  		if custAttributes.count o > 0 do (
  			with animate on
  			( 
  				at time frameTime 
  				(
  					--key position
  					if o.keysPos[frameTime] != undefined do (
  						o.pos.controller.value = (tmX90Inv * (transMatrix o.keysPos[frameTime]) * tmX90).row4
  					)
  					--key scale
  					if o.keysScale[frameTime] != undefined do (
  						o.scale.controller.value = o.keysScale[frameTime]
  					)
  					--key rotation
  					--convert XSI Euler angles to 3dsMax Quaternion
  					if o.keysRot[frameTime] != undefined do (
  						xsiXrot = o.keysRot[frameTime].x
  						xsiYrot = o.keysRot[frameTime].y
  						xsiZrot = o.keysRot[frameTime].z
  						xsiAngles2Quat = (eulerAngles xsiXrot xsiYrot xsiZrot) as quat
  						_3dsMaxQuat = ( transform (xsiAngles2Quat) tmX90 ) * (-1)
  						--set controller value
  						o.rotation.controller.value = _3dsMaxQuat
  						--store the SRT transform at frameTime 
  						  --(note: tmSRT is not saved for time 0 in order to keep array index matching frame time)
  						--o.tmSRT[frameTime] = (scaleMatrix o.scale.controller.value)*(_3dsMaxQuat as matrix3)*(transMatrix o.pos.controller.value)
  					)
  				)
  			)
  		)
  		if o.children.count > 0 do (
  			for i = 1 to o.children.count do (
  				SetAnimation o.children[i] frameTime
  			)
  		)
  	)
  )

I hope this helps! What file format are you trying to import?