calculate 3d rotation of projectile based on direction

Started by
9 comments, last by fluke 14 years, 7 months ago
the title says it all. i'm using vectors to calculate the position of the projectile each frame and i want to take the projectile and "face" it in the direction it's moving, perhaps via some yaw/pitch mechanism? i'm assuming i'd use angles to get this but my attempts have come up short.

//ummm... no.
yaw=RAD2DEG(atan2(y,x));
glRotatef(yaw,0,1,0);

Advertisement
The method I would recommend would be to apply a relative rotation to the object each update that aligns it with the velocity vector.

One way to compute this rotation is as follows:

1. Compute the axis of rotation as the cross product of the velocity vector and the object's current direction vector. Normalize if necessary.

2. Compute the unsigned angle between the two vectors (there's a couple of different ways you can do this).

3. Apply the resulting axis-angle rotation to the object's current orientation.

There are a couple of special cases. If the velocity vector is zero-length or near zero-length the algorithm may fail, so in this case it's best to simply apply no rotation at all. The algorithm may also fail if the velocity vector and current direction vector are oppositely aligned or nearly oppositely aligned, but assuming typical projectile motion, I would think this would be unlikely to occur.
hmmm.. so minus div by zero checking, you mean like this?:

axis = cross(vel,dir);axis.normalize();sargeant_angle = abs(dot(vel,dir));glRotatef(sargeant_angle,axis.x,axis.y,axis.z);


i'm guessing this isn't correct as the behavior is... well, there's no behavior.. at least no rotation.
i'm a liiittle closer here having made some wild guesses. the projectile's (a simpe rectangular cube) rotation *seems* to coincide with it's current path/direction, but the orientation is WAY off.:

axis = cross(vel,dir);axis.normalize();sargeant_angle = acos(abs(dot(vel,dir))) * 360.0f;//later in render func:glPushMatrix();glTranslatef(x,y,z);glRotatef(sargeant_angle,axis.x,axis.y,axis.z);glScalef(0.05f, 0.05f, 0.2f); //problem exists here probably????????DrawCube(); //draws a simple cube, now rectangular thanks to prev scale callglPopMatrix();


is there an easy way to fix the orientation problem no matter which axis i scale the cube on?
You don't need to do this with angles, you can just do it with vectors.

You have the velocity vector for the particle at the rendering instant. This (normalised) is one of your base vectors -- Probably the Z axis if your item is modelled facing down that axis.

So, as long as the velocity vector isn't directly vertical...

Take your velocity, normalise it, cross it with the world's "up" vector [0,1,0]. This will get you a vector at right angles to them which will be your X axis. (normalise this). You're going to use the normalised velocity as the Z axis.

Next, cross your X and your Z and you'll get your Y axis (normalise it again).

You now have three vectors. Stuff them into a matrix in the top corner and put the position vector along the bottom; like this --

Xx Xy Xz 0
Yx Yy Yz 0
Zx Zy Zz 0
Px Py Pz 1

Where X Y Z are the three "basis" vectors, P is the position. "Nm" indicates the "m" component of the N vector.

If you do it as an array, the zeros go in m[3],m[7] and m[11], m[15] is the 1. You can then just upload that matrix to opengl.

Xy, for example, is the y component of the X-axis of your new space.

Multiply your object mesh verticies by this matrix and it moves them from model space into position/orientation space.

If your flight is vertical, you'll have to fudge some basis vectors; this is equivalent to gimbal lock using angles.

Just use a LookAt matrix to rotate with, which Katie is defining
Quote:You don't need to do this with angles, you can just do it with vectors.

You have the velocity vector for the particle at the rendering instant. This (normalised) is one of your base vectors -- Probably the Z axis if your item is modelled facing down that axis.

So, as long as the velocity vector isn't directly vertical...

Take your velocity, normalise it, cross it with the world's "up" vector [0,1,0]. This will get you a vector at right angles to them which will be your X axis. (normalise this). You're going to use the normalised velocity as the Z axis.

Next, cross your X and your Z and you'll get your Y axis (normalise it again).

You now have three vectors. Stuff them into a matrix in the top corner and put the position vector along the bottom; like this --

Xx Xy Xz 0
Yx Yy Yz 0
Zx Zy Zz 0
Px Py Pz 1

Where X Y Z are the three "basis" vectors, P is the position. "Nm" indicates the "m" component of the N vector.

If you do it as an array, the zeros go in m[3],m[7] and m[11], m[15] is the 1. You can then just upload that matrix to opengl.

Xy, for example, is the y component of the X-axis of your new space.

Multiply your object mesh verticies by this matrix and it moves them from model space into position/orientation space.

If your flight is vertical, you'll have to fudge some basis vectors; this is equivalent to gimbal lock using angles.
Quote:Just use a LookAt matrix to rotate with, which Katie is defining
The reason I recommend applying incremental rotations is that other than zero velocity (which is a special case no matter what), you really don't have to worry about any special cases or orientations where the generated basis will not be valid. The method I proposed is basically equivalent to the 'parallel transport frame', which is a well-documented method for keeping an object aligned as it moves along a spline.

In practice you're unlikely to have any problems using a fixed-reference frame (i.e. the 'inverse look-at' method you're proposing), but personally I find the PTF to be more elegant. That's just me though.

I suppose another option would be to build the new frame directly using the new velocity vector and the old up vector. I've never tried this particular method before though.

We often say 'use vectors, not angles', but quite often that's in reference to use of Euler angles or unnecessarily involved trigonometry where using vectors would be simpler and more straightforward. Building an axis-angle rotation that rotates one vector onto another is a fairly standard operation that needn't be avoided, IMHO. Also, there's a very nice quaternion-based algorithm that builds a quaternion that rotates one vector onto another without using any angles or trig, so that's another option to consider if you want to avoid using angles directly.

Anyway, IMHO, using incremental rotations in a case like this is a perfectly valid solution. The 'inverse look-at' solution is valid as well, but I wouldn't say that it's better.
ooookay. :) so jyk, is my implementation close to what you recommended then?

i'm mostly indifferent on the approach i use as long as it isn't too complicated to implement and then maintain. but of course, any opportunity to learn something new is one i won't pass up, so i'll definitely give katie's suggestion a shot as well. but in the meantime, i'd really like to just get what i've started working! ;)
This looks wrong:
sargeant_angle = acos(abs(dot(vel,dir))) * 360.0f;
The call to abs() isn't necessary, the conversion from radians to degrees is wrong, and the velocity vector will need to be normalized in order for this work.

However, the bigger problem is that you're relying on OpenGL to do your math, which is going to make it difficult to apply incremental rotations as I suggested. If you'd rather not have to get into that level of math at this point and keep your code structure more or less the same as it is now, then you might want to just use the 'inverse look-at' method suggested by the other posters (as it will allow you to construct the object transform from scratch as needed).
Quote:Original post by Katie
...


Aside from the fact that your post is practically verbatim of another thread we both visited, Opengl is column-vector, not row-vector.

My point being you got a little too deep into the specifics, the vectorness and majorness. It'd be best to talk about these things at a higher level.

This topic is closed to new replies.

Advertisement