2

I have implemented a small scene graph to be rendered by OpenGL, all the objects derive from a common Node class and during OpenGL frame rendering I just call the visit method of the root node and it traverses the graph recursively. The first matrix I pass when beginning traversal is the camera matrix.

The visit method looks like this:

void Node::visit(const QMatrix4x4 &mv) {
    QMatrix4x4 m = mv;
    m.rotate(m_rot);
    m.translate(m_pos);
    m.scale(m_scale);

    m_effectiveMV = m;

    for (int i = 0; i < m_children.size(); i++) {
        m_children[i]->visit(m_effectiveMV);
    }

    draw(); // draws if this node has anything to draw,
            // otherwise just transformation.
}

The problem I experience is, when I set rotation for a child node, the rotation happens relative to the parent node, not around the node itself. Can anyone spot what I'm doing wrong here?

rgngl
  • 5,353
  • 3
  • 30
  • 34
  • I assume it is like this: a man is holding a gun, the gun rotates around the man instead of 'turning' on its own origin. Is this correct? – ssell Jul 12 '11 at 21:15

2 Answers2

6

Assuming your matrix methods are doing the right thing, translation should be the first one in the list:

m.translate(m_pos);
m.rotate(m_rot);
m.scale(m_scale);

This will first scale and rotate the vertex, then translate it into the parents system and so on.

kvark
  • 5,291
  • 2
  • 24
  • 33
  • doing like this seem to fix the rotation axis problem, but then it totally messes up with my camera position. When I have have put my camera in (0, 0, 8) and the root node in the same position it still looks like the objects are 8 units ahead of the camera position. I was checking the QMatrix4x4 source code(http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/math3d/qmatrix4x4.cpp) to see if it's doing anything nasty but I couln't spot anything weird. – rgngl Jul 13 '11 at 06:05
  • Could you post your spatial hierarchy in some way? It's hard to tell what's going on on your end. – kvark Jul 13 '11 at 11:46
  • I turned out to be a total noob and realized that I was constructing the default rotations in the default constructor as QQuaternion(0, 0, 0, 1) as I didn't totally get how the quaternions worked. After initializing quaternions with QQuaternion::fromAxisAndAngle everything works. And thanks again for the suggestion about transformation order. – rgngl Jul 13 '11 at 14:22
4

Matrix operations are not commutative, i.e. the order in which matrix multiplication happens does matter. Rotating something first, then translate it, is different to first translating and then rotate/orbit around the original center.

Instead of creating the transformation by successive application of various transformations I recommend building it directly. The upper left 3×3 is the rotation part, which you can copy directly from the rotation matrix. Scaling multiplies x,y,z factors to the 1st, 2nd and 3rd column of the matrix. Translation is the 4th column. The rotation is either stored as a 3×3 matrix or a quaternion. Don't use Euler angles, they are numerically instable.

datenwolf
  • 159,371
  • 13
  • 185
  • 298