[Closed] Export rotations to game engine
Hi everybody,
I’m working on some import/export tools for animations for certain game engine.
It’s the first time I put my hands into such a task, and I was actually surprised to discover that all the rotation values need to be applied in the character’s root space, not in the local space. (maybe because it was a mo-cap).
For importing I have just used rotate command:
rotate in coordsys <Root node> <joint> <eulerAngles>
But the question is – how do I read rotations of bones in the character’s root space, instead of their local space? Most of the bones in Max have their own inital orientation, which makes things complex.
What I did so far I created a helper for every joint, which has the same orientation as the default joint orientation. Then, while exporting I can read the angle between them by multiplying joint.transform by inverse of the refernce helper’s transform.
The problem is that it gives me the angle in local space.
Any ideas or suggestions how I can get the angle in character root space?
Thanks,
Juliusz
if the character root space = worldspace
object.transform will give you the absolute transform in world space
object.transform.rotationPart gives you the quaternion rotation
quatToEuler (object.transform.rotationPart) gives you the euler rotation
Thanks Mambo for your reply.
Yes, I do use these functions to read the angles.
However it's not enough to read the rotation part of matrix only. What I need to export to the file is bone's > relative < rotation in World Space. So eulerAngles 0 0 0 should mean the joint stays in its default position ( T pose).
In the default pose, bones already have some orientation. I use a point helpers, which hold the default orientations for each joint. I use this equation to get relative angles:
RelRot = joint.transform * inverse referenceHelper.transform
But the above gives me the bone’s rotation in its local space.
That means that if I rotate my bone around one of the axes in World Space (e.g. eulerAngles 90 0 0 ), I actually get rotations in all of bone’s three axes, because they’re not aligned to the world. –> (eulerAngles -26.4611 -22.0891 -79.3985).
See the image:
[img] http://img.photobucket.com/albums/v305/TodKnip/Arms_Rotation_zps41cb6853.jpg [/img]
What I need to export to the engine is the 90 0 0 rotation value, because that's what happened in a character Root space (which is World, in this case)
So my problem is how to turn this: -26.4611 -22.0891 -79.3985 into that: 90 0 0 …
if you want to export absolute (world space) rotation you have to export a point what this rotation was made about as well. so it’s much easier to export whole transformation matrix.
but nevertheless the right way is to store relative (local) rotations, and convert them to world space multiplying by parent transformation matrix.
Hmm… I’m not sure if I am using the correct terms. The rotations need to be relative as in the difference between the T pose and the animated pose. So these are not the absolute rotations as seen on the screen.
But at the same time, the axes orientation for these rotations need to match the world axes – not the bone’s axes orientation. Hope that makes sense.
I’m starting to think, that I should actually ignore reading bone’s orientation from its transform matrix. And instead, I should just read angles between points, which are being rotated by the particular joint (=position of its child). After all the skeleton definition was just points offsets – no orientation values for the bones.
So the question would be – how to get the matrix that transforms vector (point) V1 into V2, using the world coordinate system…?
the answer is simple:
translation_vector = pointB - pointA
pointB == pointA + translation_vector
translation_matrix = (transmatrix pointB) * inverse (transmatrix pointA)
pointB == pointA * translation_matrix
Just read this closer now. Sorry, I meant rotation matrix – not translation matrix.
So we have a point C at 0,0,0 which is our center of rotation and we have two points A and B. Is there any way of building a matrix that rotates point A around C to point B?
I know how to get the angle between the two points (it’s in the MaxScript Documentation), but that seems to give me an angle in the plane formed by the above mentioned three points…
I’m probably being chaotic or confusing in my question, as I don’t fully understand rotations and 3D math. The more I appreciate anyone giving me some answers!
but i don’t believe you are doing everything right. i still think you have to store ‘rotation’ offset from initial ‘rotation’ in parent coordinate space.
Thanks for that – I’ll try to incorporate these when I’m back home.
I had an idea of creating a hierarchical set of temp helpers for the time of the export only. All helpers would be created in the positions of the joints. Then starting from the root, exporting rotation, zeroing out the rotations before I move to its children etc… Finally helpers would form a default T pose. This way I would be dealing with the rotations of a currently processed joint only.
But maybe what you’re saying about the parent space does the same, but in a simpler way?
I have some food for a thought and experimenting anyway…
yes, we can… using a quaternion
q_axis = cross (normalize pointA) (normalize pointB)
q_angle = acos (dot (normalize pointA) (normalize pointB))
rot_quat = quat q_angle q_axis
rot_mat = translate (rot_quat as matrix) rot_center
that’s a basic idea… i don’t have max now to test it
Thanks Denis.
I had to normalize the q_axis vector in order to use it to create quaternion. And the order of vectors in the cross product needed to be inverted, to get the same rotation values as seen in UI.
However that wasn’t the right path to go. But I seem to have found the method that works.
Basically, I created a point helper at every joint, reset their rotation to 0 0 0 so they match the World Space and gave it an Orientation Constraint to the joint. The ‘Keep Initial Offset’ parameter needs to be checked. This way, at the default orientation, my refernce helper shows 0 0 0 rotation, but as the bone gets rotated, it rotates as well, in relation to the world. I can just read the rotation value from its transform property.
And in order to read these rotations in the parent space, as you mentioned, I had to multiply point helper’s transform by inverse of the transform of the point helper of the parent joint.
Thanks again for help!