# Rotating a child shape relative to its parent's orientation

When rotating a shape using a quaternion value I also wish rotate its child shape.

The parent and child shapes both start with different orientations but their relative orientations should always be the same.

How can I use the difference between the previous and current quaternions of the parent shape in order to transform the child segment and rotate it relative to its parent shape?

    public Quaternion Orientation
{
get { return entity.Orientation; }
set
{
Quaternion previousValue = entity.Orientation;
entity.Orientation = value;

// Use the difference between the quaternion values to update child orientation
}
}


EDIT:

If I have understood teodron correctly then this is what I must do

// Qc' = Qp' * Inv(Qp) * Qc
//
// Where:
// Qp   = Parent orientation last frame
// Qp'  = Parent orientation this frame
// Qc   = Child orientation last frame
// Qc'  = Child orientation this frame

set
{
Quaternion previousValue = entity.Orientation;

entity.Orientation = value;

Quaternion childOrienation = value * Quaternion.Inverse(previousValue) * childOrientationPrev;
//Quaternion childOrienation = childOrientationPrev * Quaternion.Inverse(previousValue) * value;
}


I have tried both multiplication orders but neither method rotates the child object correctly and instead it spins very quickly.

• do you somehow synchronize the previousOrientation/value in another method in your code? Try making those values fixed (i.e. as if they describe the object at start-up). If it doesn't work, let me know, I'll try to code them myself and get back to you with a verified concept (it might not be C#, but pseudocode since I do not use C# libraries for quat math and rendering). – teodron Oct 5 '12 at 11:35
• The only place the orientation is ever changed is via the Orientation property using the set method. There is currently nowhere else in the code that changes the orientation outside this method. – user1423893 Oct 5 '12 at 12:05
• so previousValue is not tampered with after its creation? In this case, I'll try shortly to update the answer with a working, tested, pseudocoded solution. – teodron Oct 5 '12 at 13:30
• so previousValue is not tampered with after its creation? That is correct. – user1423893 Oct 5 '12 at 14:03

Just store the static orientation difference between parent and child once at startup, lets call it qDiff.

Whenever you set the new parent orientation, set child's orientation like this:

qChild = qNewParentOrientation * qDiff

• This sounds like a very good idea. I shall implement it after returning from work. – user1423893 Oct 5 '12 at 14:03
• How do I calculate the orientation difference between the parent and child object? – user1423893 Oct 5 '12 at 14:11
• qDiff = conjugate(qParent) * qChild – Maik Semder Oct 5 '12 at 14:58
• It is like @MaikSemder suggests: your code snippet seems to be mathematically correct. Your update equation is: Qc = Qp * conj(Qp0) * Qc0. Maik suggests you do: Qc = Qp * dQ, meaning Qc = Qp * conj(Qp0) * Qc. Again, if your dQ quotient quaternion (difference sounds odd in a multiplicative field ;) ) is not changing, the maths are completely right. – teodron Oct 5 '12 at 15:56

Update:

Tested and confirmed to work:

Say you have two objects: a source and a target object.

The target must keep a certain relative orientation with respect to a source object. This is really the case with most fundamental camera tracking scenarios (e.g. camera behind a flying entity - plane, spaceship, etc.).

If a given reference pose of this binary system is given, say at start-up, then we must grab hold on the orientations of the source and target objects:

• Qtgt0 = the quaternion describing how the frame of the target relates to the world frame
• Qsrc0 = the quaternion describing how the frame of the source object relates to the world frame

The 0 suffix denotes the initial state. These two quats shouldn't change from now on, they remain untouched. The relative orientation of a target with respect to a source is not the difference of the quaternions, but this guy: Qsrc0.inverse * Qtgt0 (something similar to a division operator for quaternions - but since the quaternion multiplication does not commute, such an operator is "left or right handed").

At a certain time instance, the source has the Qsrc orientation. To couple the orientation of the target to that of the source, set the orientation of the target to be:

Qtgt = Qsrc * Qrelative = Qsrc * Qsrc0.inverse * Qtgt0

The picture below illustrates an experiment where a cube gets the camera's quat and a parabolic tube springing from one of the cube's faces rotates with the cube although they are not attached to the same scene node, nor is the cube's node a child of the cube's node (talking hierarchical node transformations in a scene graph). Both objects are linked to the world independently, but when the scene is created, their relative orientation is stored separately for future updates.

An example:

Say you have a ship and a camera object in a simple scene.

Let Qs be the ship's current quat and Qc the camera's current quaternion. Let this configuration Qs,Qc be the initial, reference position you are talking about.

If the ship changes its orientation from Qs to Qs', then you could write:

Qs' = Qs' * inv(Qs) * Qs

Qs' * Qs is a relative rotation transformation. If you apply it to the camera's initial orientation, you get a new camera orientation that should be in tune to your ship's change in orientation, as desired. The inv(Qs) factor tells us that there is an intricate orientation coupling that is initially set, between our camera and ship objects.

inv(q) denotes the inverse of a quat, which is the same as its conjugate q* if the quat is normalized.

Further explanation:

To get a result, the camera's orientation, when the ship changes heading, should look like:

Qc' = Qs' * inv(Qs) * Qc

Be aware that the _ operator is the quaternion multiplication. When rotating vectors, you will multiply the orientation quat q with (0,_v_) and then right multiply it by q.

• I have studied your answer but I cannot get it to work correctly. I've edited the original question to show how I am using your advice in code form. However, it is not working for me and the object spins very quickly rather than rotating slowly. – user1423893 Oct 5 '12 at 10:25