I am exporting some simple animation of a rotating box using 1 bone. Because of the differences in the coordinate systems between Max and OpenGL, im getting incorrect results.
There could be any number of things going wrong. Can you post the code you’re using to pull the transform in from Collada and apply it in OpenGL? In particular, are you using glRotate, glMultMatrix, or glLoadMatrix? Remember that glMultMatrix and glLoadMatrix want a column-major memory layout, whereas C/C++ is row-major, so if you’re using a 2-d array as in float m[4][4], you’re going to have to transpose that before passing it along to glMultMatrix/glLoadMatrix, or use the transpose matrix functions (glMultMatrixTranspose iirc).
A straight up export from max will most likely be exporting geometry and animations and everything using the z axis as the up axis.
If you have set up your openGL cameras to see things Y up then all your rotations would look wierd… your geometry would be sideways too but since you are using a cube you can’t notice that.
When loading a COLLADA document you should pay attention to the <asset> tag. It holds some inportant information such as <up_axis> and <units> which you should pay attention to if you don’t want to experience things looking or acting different then your DCC tool.
I believe switching between the two axis is as simple as a 90 degree rotation around x for all the nodes upon loading.
//The Quaternion which will transform Max transformations to OpenGL
AngleAxis MaxToGL;
MaxToGL.x = 1.0f;
MaxToGL.w = -90.0f * (PI/180.0f);//convert to radian
MaxToGL = MaxToGL.convertToQuat();
MaxToGL.Normalize();
//For every Bone
for(PInt sfb=0;sfb<BoneNameArray.size();++sfb)
{
domNode* dn;
//Try to get the Node with the same name
myDae->getDatabase()->getElement((daeElement**)&dn, 0, e.c_str(), COLLADA_ELEMENT_NODE);
e = dn->getName();
cout<<"
Now processing : "<<e<<"
";
PInt similj = dn->getTranslate_array().getCount();
//I get my position vector of the bone here, i swap the y and z manually.
float x = dn->getTranslate_array().get(0)->getValue().get(0);
float z = -dn->getTranslate_array().get(0)->getValue().get(1);
float y = dn->getTranslate_array().get(0)->getValue().get(2);
b.setPosition(x,y,z);
//Here we get the Bone's initial orientation
Quat Final;
//for every Rotate array
for(PInt oiu = 0;oiu<dn->getRotate_array().getCount();++oiu)
{
//YZ SWAP
Quat q1;
q1.x = dn->getRotate_array().get(oiu)->getValue().get(0);
q1.y = dn->getRotate_array().get(oiu)->getValue().get(1);
q1.z = dn->getRotate_array().get(oiu)->getValue().get(2);
q1.w = dn->getRotate_array().get(oiu)->getValue().get(3);
//Values read in are angle-axis, therefore we must convert it to a quaternion.
q1.w = q1.w * (PI/180.0f);//change to radians becos values are in degrees
q1 = q1.convertToQuat();
q1.Normalize();
//Combine all rotation arrays into 1 quaternion
Final = Final * q1;
Final.Normalize();
}
//Finally apply MaxToGL to reorient coordinate system.
Final = Final * MaxToGL ;
In the same way, MaxToGL is applied to all animation keyframes, i can post the code if needed. But this is basically what im doing in order to reorient the animation.
I can see you swap y and z manually in translation array, then how about the rotation array? The most important thing is what you’ve done in Quat::convertToQuat(). Hope you did the right thing in this function:)
I think that’s handled by the final *MaxToGL in the last line.
Some things you might want to check:
(1) “MaxToGL.w = -90.0f * (PI/180.0f);” Shouldn’t that be 90 instead of -90?
(2) Is your convertToQuat function correct?
(3) Are you sure you want
Final = Final * q1;
...
Final = Final * MaxToGL ;
instead of
Final = q1 * Final;
...
Final = MaxToGL * Final;
(4) Are you passing the transform to OpenGL correctly?
Without actually being able to sit down and debug your code with a simple test case, it’s hard :(. (1) and (3) are my best guesses as to what’s going wrong.
//The Quaternion which will transform Max transformations to OpenGL
AngleAxis MaxToGL;
MaxToGL.x = 1.0f;
MaxToGL.w = -90.0f * (PI/180.0f);//convert to radian
MaxToGL = MaxToGL.convertToQuat();
MaxToGL.Normalize();
With alot of tinkering around and looking through everything, i think i have managed to solve the rotation problem, or so i thought. My current problem is Collada related, how do i find out the orientation of a bone during binding(Bone added to skin modifier)?
To get a basic example working, i created a bone with 0 0 0 rotation. My mesh was a teapot on which i applied the skin modifier and added the bone to the skin modifier. So now, my bone was bound with a rotation of 0 0 0. If i rotate the bone, the mesh will rotate with it, meaning if i set the bone’s rotation to -90 0 0, my mesh will be rotated -90 degrees around the x axis as well. Everything is fine.
Now this is when it screws up, Say i created a bone with -90 0 0 and then bound it to my mesh, my mesh would not be affected by the -90 x axis rotation because that is the rotation with which the bone was bound to the skin. This is expected in Max. But how can i tell from the Collada file?
If i were to export my mesh, both cases give me the same result in the resulting collada file, whereas in Max, the latter case shows the mesh unaffected by the Bone’s default rotation.
The transform matrix at which the mesh was bound to the skin is saved in the COLLADA file, within the <bind_shape_matrix> element of the skin controller. I think that’s the extra information you are currently missing.