   skeletal animation
  I'm wondering about skeletal animation. I've started drawing up some basic classes.class CJoint{private:util::array<scene::CBone*> m_boneList;unsigned int m_jointId;util::CVector3d m_translation;util::CVector3d m_rotation;util::CVector3d m_scale;};class CBone{private:util::array<scene::CVertex3d*> m_boneVertices;unsigned int m_boneId;Joint* m_firstJoint;Joint* m_secondJoint;};Where the array object is a dynamic array.Here's my little dilema. The translation should be in the joint, right, but what about the rotation? Or scale? Should there even be scale? Because as far as I can see, it doens't really make sense in the context.I was thinking that the bone has to have the rotation, but, what should it have? Is this something I can do without quaternions? Because I don't really have quternions incorporated into my engine yet even through it seems that quaternions are fairly suited for this, and all my rotations in the model space are constructed with matrices.But, if I did it without quaternions, I'm having trouble visualizing how the rotations would work.   
  In my class, I store three Euler angles to create my matrix, recalculating everytime it's changed. I've never messed with quaternions. I bet they would solve alot of problems I didn't realize were problems, and just dealt with as another "bitch" of programing. So maybe they are worth looking into, but not required.As far as scaling. I have no idea what it would do. I've never experimented with it and so it is not included in my class. It might have been useful in a program I wrote with many different unit conversion factors. It would have been nice if I could have scaled my skeleton to match the graphics, physics and picking. Instead of everything getting converted back to the skeleton's scale. I'd leave it in, it would be intersting to see what happens, most likely it will just scale. If it goes crazy or is un-used, take it out and save some time building matrices.edit: I annoy even myself by putting that extra line at the top.   ;  Okay, I don't know if what I'm using for rotations are Euler angles.I have a matrix class that I use to construct rotation matrices for the x,y,z axes, which I then multiply by the world matrix. Are these Euler angles?   ;  Does the code look something like this? Then it is Euler, most likely it is since you said XYZ..double cr = cos( angles[0] );double sr = sin( angles[0] );double cp = cos( angles[1] );double sp = sin( angles[1] );double cy = cos( angles[2] );double sy = sin( angles[2] );m_matrix[0] = ( float )( cp*cy );m_matrix[1] = ( float )( cp*sy );m_matrix[2] = ( float )( -sp );double srsp = sr*sp;double crsp = cr*sp;m_matrix[4] = ( float )( srsp*cy-cr*sy );m_matrix[5] = ( float )( srsp*sy+cr*cy );m_matrix[6] = ( float )( sr*cp );m_matrix[8] = ( float )( crsp*cy+sr*sy );m_matrix[9] = ( float )( crsp*sy-sr*cy );m_matrix[10] = ( float )( cr*cp );My quaternion code looks like this. (un-used)m_matrix[0] = ( float )( 1.0 - 2.0*quat[1]*quat[1] - 2.0*quat[2]*quat[2] );m_matrix[1] = ( float )( 2.0*quat[0]*quat[1] + 2.0*quat[3]*quat[2] );m_matrix[2] = ( float )( 2.0*quat[0]*quat[2] - 2.0*quat[3]*quat[1] );m_matrix[4] = ( float )( 2.0*quat[0]*quat[1] - 2.0*quat[3]*quat[2] );m_matrix[5] = ( float )( 1.0 - 2.0*quat[0]*quat[0] - 2.0*quat[2]*quat[2] );m_matrix[6] = ( float )( 2.0*quat[1]*quat[2] + 2.0*quat[3]*quat[0] );m_matrix[8] = ( float )( 2.0*quat[0]*quat[2] + 2.0*quat[3]*quat[1] );m_matrix[9] = ( float )( 2.0*quat[1]*quat[2] - 2.0*quat[3]*quat[0] );m_matrix[10] = ( float )( 1.0 - 2.0*quat[0]*quat[0] - 2.0*quat[1]*quat[1] );My matrix class is essentialy Real Soon Now's, with my additions.   ;  you shouldnt need scale unless you want to do what UT does when you chop off an arm, it scales the arm to 0 to become a stub and spawns a gib.Personally I dont have scale in my skinning implmentation...   ;  honayboyz: I think so, you're doing it a different way, but, just to make sure:void CMatrix::setRotationZ(float rad){/*where t == thetacos(t)-sin(t)00sin(t)cos(t)0000100001*/setIdentity();float cosine = (float)cos(rad);float sine = (float)sin(rad);m_mat[0] = cosine;m_mat[1] = sine;m_mat[4] = -sine;m_mat[5] = cosine;}void CMatrix::setRotationX(float rad){/*where t == theta10000cos(t)-sin(t)00sin(t)cos(t)00001*/setIdentity();float cosine = (float)cos(rad);float sine = (float)sin(rad);m_mat[5] = cosine;m_mat[6] = sine;m_mat[9] = -sine;m_mat[10] = cosine;}void CMatrix::setRotationY(float rad){/*where t == thetacos(t)0sin(t)00100-sin(t)0cos(t)00001*/setIdentity();float cosine = (float)cos(rad);float sine = (float)sin(rad);m_mat[0] = cosine;m_mat[2] = -sine;m_mat[8] = sine;m_mat[10] = cosine;}The matrix has column vectors.   ;  Don't worry about that. You're not using Euler Angles in the "please never ever think about doing it by storing three angles"-way. You could probably add a function to return a rotation matrix for an arbitrary axis.Where quaternions are concerned, if they help to visualize what you're doing, use them. In the end it doesn't matter if you store a 4x1 quaternion or a 3x3 matrix (or 3x4 if you throw the translation in.. or 4x4 if you don't mind the wasted space).But the classes seem weird to me, mostly because I'm minimalistic by nature. In my world "bones" don't exist, only joints. They have a position and orientation and bones only matter when the skeleton should be visualized (connecting a parents joint position with the childrens positions.. and just use orientation and unit length if there is no child). Note that a skeleton is usually nothing but a tree and your approach seems like a tree that instead of storing children and parent for each node/joint is storing the edges between nodes as seperate entities.But typically I'm evil and use bone and joint as the same thing.In return, joints store more than one set of translation/rotation. There are a bunch of ways to do it and deciding on one before implementing away would help.How do you plan to store your vertices? One way is storing them in their bind position, but that requires extra work on the skeleton. The other stores a position per joint relative to this joint. Less work, more data.The latter means you only care about a joints absolute position, while the former needs to apply the inverse bind pose to the absolute position (the combination of bringing a vertex into a joints space and then transforming, obviously the first part isn't necessary with the other approach). Unfortunately it doesn't really work out if you want to do hardware skinning.   ;Quote:Original post by TriencoIn return, joints store more than one set of translation/rotation."In return"? Huh?   ;Quote:Original post by Endar"In return"? Huh?In return for not having any "bones" at all. And only in my case. If you decide to go with ids md5 format and do it "their" way you wouldn't need more than the absolute positions.   