Rotate to look ahead

I’m trying to get an object to rotate so that it is always “looking ahead” as it moves. I’m doing so like this:

float Transform[16];

// cross
Transform[0] = 1.0f;
Transform[1] = 0.0f;
Transform[2] = 0.0f;
Transform[3] = 0;

// up
Transform[4] = 0.0f;
Transform[5] = 1.0f;
Transform[6] = 0.0f;
Transform[7] = 0;

// dir
Vector3 dir( m_Position - m_OldPosition );
dir.Normalize();
Transform[8] = dir.x;
Transform[9] = dir.y;
Transform[10] = dir.z;
Transform[11] = 0;

// pos
Transform[12] = m_Position.x;
Transform[13] = m_Position.y;
Transform[14] = m_Position.z;
Transform[15] = 1;

glPushMatrix();
glMultMatrixf( &Transform[0] );	

// draw it

glPopMatrix();

It’s working, but it can get distorted, with what looks like the normals getting screwed up.

Any ideas?

Okay, I looked around and came up with another way to do it (see end of post if you’re interested), but I’d still like to know what’s going wrong with this method.

Here’s my working alternative:

Vector3 lookahead( 0.0f, 0.0f, 1.0f );
Vector3 dir( pA->m_Position - pA->m_OldPosition );
dir.Normalize();

Vector3 up = lookahead.Cross( dir );
float cosangle = lookahead.Dot( dir );

glTranslatef( pA->m_Position.x, pA->m_Position.y, pA->m_Position.z );
glRotatef( Rad2Deg( acos(cosangle) ), up.x, up.y, up.z );	

Your coordinate system in the first case was non-ortho-normal. I.e. the vector dir was not necessarily orthogonal to up and cross.

What you should have done:

  Vector p;     // your position
  Vector front; // your movement direction
  Vector up;    // your world's up vector (0, 1, 0)

  // construct ortho-normal coordinate system from movement and world-y
  Vector z = normalize(front);
  Vector x = normalize(cross(z, up));
  Vector y = cross(x, z); // already unit length

  // construct transformation matrix from base vectors
  float tf[16] = {
    x.x, x.y, x.z, 0,
    y.x, y.y, y.z, 0,
    z.x, z.y, z.z, 0,
    p.x, p.y, p.z, 1
  };

  glMultMatrixf(tf);

EDIT: Keep in mind that “front” must not be collinear (parallel or anti-parallel) to “up”.