Request for help with 3D vector math

I can't seem to get the steering for my ship to work right. Here's the problem:
  1. I want to use glRotate() to rotate the ship around the y-axis a certain number of degrees so that the ship faces the direction (in the x-z plane) it's traveling.
  2. I have two vectors: the direction vector represents the direction I'm currently going, and the goal vector represents the direction I want to go.
  3. I want to calculate the angle (in degrees) between the two vectors. This is the angle I need to rotate the ship.
Here's how I'm doing the calculation:
   old_direction = direction.normalize()
   direction = goal.normalize()
   angle = math.acos(old_direction.dot(direction)) * (180.0 / 3.1415927)

   if steer_left:
      rot.y += angle * -1
   else:
      rot.y += angle

   glRotate(rot.y, 0, 1, 0)
   # Draw the ship
When I do this, the rotatation of the ship lags behind the direction it's actually moving. Any ideas about what I'm doing wrong?

(log in to comment)

Comments

You're not converting the result of math.acos from radians to degrees.
Hmm ... I thought that I was by multiplying the result by (180.0 / 3.1415927). Maybe I need to check to make sure my vectors are set up correctly.
Ah, so you are! The perils of viewing the message in a narrow window ;-)
This isn't a solution, but I'd use math.degrees() and math.radians() for that sort of thing.
Instead of calculating an angle and then constructing a rotation matrix from it, there's a more direct way that also works for general rotations in 3d:

The columns of the rotation matrix (or rows, if you're using OpenGL's column-major matrix convention) are unit vectors representing the axis directions of the old coordinate system in the new coordinate system. (Or it might be the other way around, I haven't got time to think it through properly right now.)

I'm a little uncomfortable with a few things in your code - not that they're wrong, but they just wouldn't be the way I would do them.

The one thing I would do most differently is to have the actual heading maintained by your ship object, and then every time you go to draw it, rotate to that heading. So, if you're turning from 90 degrees to 95 degrees, the draw code will issue a glRotate(95, 0, 1, 0) call instead of a glRotate(5, 0, 1, 0) call.

In some code I'm working on right now (for work, not the competition), I do something very similar:

    def drawVector(self):            
        glColor3f(*self.color)
        glPushMatrix()
        x,y=self.pos
        glTranslate(x,y,0)
        glRotate(self.heading, 0, 0, 1)
        
        glBegin(GL_LINE_LOOP)
        glVertex2f(-5.0, -3.0)
        glVertex2f( 5.0,  0.0)
        glVertex2f(-5.0,  3.0)
        glEnd()
        glPopMatrix()
So, if I were to take that draw code and plug it in to your steering code, it'd probably look a little like this:

self.heading=math.degrees(math.atan2(direction[2],direction[0]))
self.drawVector()
I don't know if that's at all helpful, but maybe it's worth trying.
Thanks for the input. I'm going to try it.
If you're still stuck, here's the code I implemented this morning for my baddie AI:

player_dir = self.player.collision.c - baddie.collision.c # direction I would like to face
facing_dir = baddie.get_facing_ray().v                    # direction I am currently facing
n = facing_dir.cross(euclid.Vector3(0, 1, 0))             # normal of plane dividing universe along facing_dir
direction = n.dot(player_dir)                             # sign gives direction (left or right) to turn
angle = math.acos(player_dir.dot(facing_dir))             # magnitude of angle