Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to implement a simple scene graph on iOS using GLKit but handling origin/anchor points is giving me fits. The requirements are pretty straightforward:

  • There is a graph of nodes each with translation, rotation, scale and origin point.
  • Each node combines the properties above into a single matrix (which is multiplied by it's parent's matrix if it has a parent).
  • Nodes need to honor their parent's coordinate system - including the origin point (i.e. a child's origin should line up with the parent's origin)

So the question is:

What operations (e.g. scaleMatrix * rotationMatrix * translationMatrix, etc.) need to be performs and in what order so as to achieve the proper handling of origin/anchor points?

P.S. - If you are kind enough to post an answer please mention whether your answer is based on column or row major matrices - that's a perennial source of confusion for me.

share|improve this question
add comment

1 Answer

up vote 2 down vote accepted

You might not need an anchor point in each node. When you make the 3D model, you can place it so that the origin is at the anchor point. For example, if you're making a human model, and you want the anchor point to be between the feet, then just make sure the origin is between the feet when you export from Blender, or whatever you are using.

If you do want anchor points, then the matrix for each node must include an additional translation step, which comes before scaling/rotation/etc.

So, if you have a node that looks something like this:

struct Node {
    vec3 position;
    vec3 anchor; //in model coordinates, stored as an offset/displacement from the model's origin
    vec3 scale;
    matrix rotation; //could also be a quaternion, axis + angle, euler angles, etc.
};

Then you would calculate the matrix of each node like this:

Node n = whatever();
matrix m = translate(n.position) * scale(n.scale) * n.rotation * translate(-n.anchor)

Pretend that the scale and translate functions return a matrix. So the transformations, in order (right to left), are:

  1. Translate by -anchor
  2. Rotate
  3. Scale
  4. Translate by position

Because the translation by -anchor comes first, all subsequent transformations will treat the anchor as the origin.

When it comes to the parent node, it looks like you already know how to do this. Just multiply the matrix of the parent by the matrix of the child, which will put the child into the parent's coordinate system.

It doesn't really matter whether the matrices are column or row major. That is only important when you are handing off the matrices to a third party, such as using glUniformMatrix4f in OpenGL (which requires column-major order).

share|improve this answer
    
Thanks for the very detailed answer, but I have to apologize for not giving enough information in my question. I'm working in 2D, and the main issue that I was running into was that I couldn't get children to honor their parent's origin. E.g., if I had a parent node with it's origin at {10, 10} the rotations etc. would work properly but any children that were added would be registered at the parent's {0, 0} point. I fixed it by adding a translation to the parent's origin (e.g. translate(parent.origin.x, parent.origin.y). If you incorporate the above in your answer I'll be happy to accept it. –  Huhwha Jan 23 '13 at 20:24
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.