How to calculate the new global position of a child object according to a relative variation in the parent?

advertisements

I have a spatial structure where I keep a few objects. All the positions of the objects are global.

I'm now trying to create a parent/child system but I'm having trouble with the math. What I tried at first was, everytime I move an object, I also move all of its children by the same amount. That works but I also need rotation, so I tried using matrixes. I built a model matrix for the child. It was built using the relative position/rotation/scale to the parent:

glm::mat4 child_model;
//"this" is the parent
child_model = glm::translate(child_model, child_spatial.position - this->m_position);
child_model = child_model * glm::toMat4(glm::inverse(this->m_rotation) * child_spatial.rotation);
child_model = glm::scale(child_model, child_spatial.scale - this->m_scale);

I would then rotate/translate/scale the child matrix by the amount the parent was rotated/moved/scaled and then I would decompose the resulting matrix back to the global child:

child_model = child_model * glm::toMat4(this->m_rotation * rotation);
child_model = glm::translate(child_model, this->m_position + position);
child_model = glm::scale(child_model, this->m_scale * scale);

where position/rotation/scale are defined as:

//How much the parent changed
position = this->position - m_position;
rotation = glm::inverse(m_rotation) * this->rotation;
scale = this->scale - m_scale;

and:

glm::decompose(child_model, d_scale, d_rotation, d_translation, d_skew, d_perspective);
child_spatial.position = d_translation;
child_spatial.rotation = d_rotation;
child_spatial.scale = d_scale;

But it doesn't work and I'm not sure what is wrong. Everything just spins/moves out of control. What am I missing here?


This problem is similar to joint animation used for computer animations. First you have to use or construct transformation matrices for each object. However, the transformation matrix of each child object should be with respect to their parent's coordinate system (i.e., child coordinate should be in parent's coordinate space). We'll call this matrix a ToParentMatrix. In addition, each object needs to have another matrix which transforms it all the way to the root (which is in world space). We'll call this matrix aToRootMatrix. When we multiply these two matrices we get a 'ToWorldMatrix' which contains the position and orientation in world space. So the transformation of each object to world space is as follows in a 2-joint hierarchie (root, child1 (of root) and child2 (of child1)):

RootTransform = ToWorldMatrix; // The root object is allready in world space;
Child1.ToRootMatrix = RootTransform;
Child1.ToWorldMatrix = Child1.ToRootMatrix*Child1.ToParentMatrix;

Child2.ToRootMatrix = Child1.ToWorldMatrix;
Child2.ToWorldMatrix = Child2.ToRootMatrix*Child2.ToParentMatrix;

For more information, search for joint (or skeletal) animation and forward kinematics. Also Frank Luna's book has two nice chapters about skeletal animation.