rotation to a given angel

Started by
14 comments, last by bloemschneif 22 years, 9 months ago
Your demo looks pretty cool! Should be fun to play once you''re done with it!

I have another very long reply, but hopefully it will be clear. If you have another question, please ask.

The reason the vehicle is rotating about the z axis is because the quaternion you''re rotating about, to align the vehicle with the surface, is not necessarily perpendicular to the z axis. Try it. In your Car.java file, take the dot product of (ax, ay, az) with (0, 0, 1), and you''ll find the dot product is usually nonzero. The only way to avoid rotation about the z axis is to ensure this dot product is exactly zero. But to get the normals to line up for a vehicle moving in an arbitrary direction, there is no easy way you can guarantee the dot product will be zero. The solution is a two-step approach. But not doing xrot() and yrot() as you were before...read on.

You want to align the normal of the vehicle with the surface, but at the same time you want to specify a specific rotation about the z axis. How do you do it? This is actually a tricky problem, which requires a bit of geometric insight. I don''t have time to draw diagrams to illustrate the geometry, but I will tell you how to do the calculations. You''ve actually created a "multi-objective optimization problem" (as mathematicians might call it). You want to find the rotation that minimizes the difference between the vehicle normal and surface normal while at the same time minimizing the difference between the vehicle z rotation and a specified z rotation (i.e., the direction of motion). Fortunately, for your racing game, there will always be an exact solution that you can find.

I will tell you my idea for finding the rotations. It requires two steps, and you''re already doing the first step! Rotating the vehicle to align its normal is the first step! The next step is to rotate a second time, using the surface normal as the quaternion direction, and using an angle that will line the vehicle up with the direction of motion. Since the second rotation will be about the surface normal, the vehicle will continue to be aligned properly with the terrain. And since the vehicle is moving along the terrain and never in the direction of the terrain''s normal, it is guaranteed that there is an angle of rotation that will correctly orient the vehicle with its direction of moving.

Finding this new angle of rotation is trickier and more expensive than the first angle.

1) Given a direction of motion (i.e., your zrot angle called RADdir), compute DIR in the following way:

DIR = new Matrix3D();DIR.quaternion(Math.cos(RADdir/2), 0, 0, Math.sin(RADdir/2)); 


Notice that this rotation is purely about the z axis and so the z component of DIR will be zero.

For testing, just to make sure the vehicle isn''t rotating incorrectly, you may want to leave RADdir = 0. Then once this code is working, go back and set RADdir equal to the correct value.

2) Find the equation of the plane of the vehicle. The equation has the form:

NSurface[0]*x + NSurface[1]*y + NSurface[2]*z + D = 0 


Here, (x,y,z) is a point on the surface of the plane, and D is a constant. It is D that you don''t know, but need to find. Here''s how to find it:

D = -NSurface[0]*x_vehicle + NSurface[1]*y_vehicle + NSurface[2]*z_vehicle 


where (x_vehicle, y_vehicle, z_vehicle) is the current world location of the vehicle.

Now that you have D, you have the equation of the plane of the vehicle.

3) Find a point on the vehicle plane that is vertically above the point represented by the DIR vector.

x_point = DIR[0] + x_vehicle;y_point = DIR[1] + y_vehicle;z_point = (-D - NSurface[0]*x_point - NSurface[1]*y_point)/NSurface[2]; 


Note that this code fails if you surface is exactly vertical.

4) Find a vector from the vehicle position to (x_point, y_point, z_point):

dvector[0] = x_point - x_vehicle;dvector[1] = y_point - y_vehicle;dvector[2] = z_point - z_vehicle; 


It is actually this vector, dvector, that is causing all the trouble. We need to rotate the vehicle about NSurface so that the x vector of the vehicle is parallel to dvector.

5) Compute the dot product of the vehicle x axis to dvector.

ddx = dvector[0]*xdir_x + dvector[1]*xdir_y + dvector[2]*xdir_z; 


Here, (xdir_x, xdir_y, xdir_z) is the vehicle''s local x direction vector, represented in global coordinates. You can consider the vehicle''s normal to be its local z direction vector. The local x direction vector (and local y direction vector for that matter) are parallel to the plane of the vehicle. If you can grab the vehicle''s full transformation matrix, then (xdir_x, xdir_y, xdir_z) will either be the first 3 elements of the first row or the first 3 elements of the first column, depending on your 3D API. (The vehicle normal is either the first 3 elements of the third row or the first 3 elements of the third column.)

6) Now compute the new angle:

newangle = Math.acos(ddx); 


7) Finally, do the last rotation:

OM.quaternion(Math.cos(newangle/2),              NSurface[0]*Math.sin(newangle/2),              NSurface[1]*Math.sin(newangle/2),              NSurface[2]*Math.sin(newangle/2)); 


8) The vehicle should be aligned correctly, so that the normal is parallel to the surface normal and the vehicle is pointing in the correction direction of motion (specified by RADdir).

Please note that I have not tested my code at all, and there may be minor errors. But its basically correct.

I need to tell you that there is a slightly easier way to do all of this. Your approach of rotating the vehicle into the new orientation makes sense if you intend to include physics at some point. But if you merely want to make sure the vehicle is aligned, I''m thinking of another approach that is more direct and a bit faster to calculate. Let me know if you want to know this approach. It requires that your 3D API allow you to specify the full transformation matrix for the vehicle. For example, instead of using xrot() or quaternion() to *modify* the transformation matrix, you''d need a function like OM.set_transform_matrix(Matrix3D new_transformation_matrix).




Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Advertisement
I should say that my solution to the second rotation, in my post above, is meant to give you a *perfect*, *flawless* orientation of the vehicle. There is an approximation to the perfect solution that is much less expensive to calculate. And this approximation may be quite good enough.

The approximation is as follows. Instead of doing steps 1-4 to calculate dvector, just use DIR instead of dvector. So, in step 5, the calculation of ddx would be:

ddx = DIR[0]*xdir_x + DIR[1]*xdir_y + DIR[2]*xdir_z;

The steps 6 and 7 are exactly the same. As long as your terrain never becomes *too* steep or angled, this may give quite good results.


Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
click

Car.java

well, as u can see for some reason it does not work.
1.
my matrix looks like:
xx xy xz xo
yx yy yz yo
zx zy zz zo
do u mean DIR[0] equals DIR.xx; DIR[1]=DIR.yx? i interpreted so.
as x_direction-vector i took the first column. (i''ve tried all combinations, but nothing changed).
2.
if u mean "take new Matrix''s values and set as current" by set_transform_mat(Matrix source), yes i''am able to do.
3.
i''am perplex again.
4.
where u can learn such kind of math?? at scool we did simple 3d math as calculating normals, lines, planes, intersections, lengths, and all the bacis stuff. at university we did matrix-op, like mult, add, inverse, determinante ect. but no rotation stuff.
do u know a good tutorial about that problem?, well i am glad about possibility asking u, but many things u''re doing in previous posting i was no able to comprehend(escp. step 3).
unwritten letters
Hi,

I don''t have time to go over your code in great detail right now, but I do see that there is one typo. Where you have the following:
double x_point = DIR.xx * location[0];double y_point = DIR.xy * location[1]; 

You *should* have this instead:
double x_point = DIR.xx + location[0];double y_point = DIR.yx + location[1]; 

You just accidentally typed "*" instead of "+". This alone will cause the code to behave incorrectly. Also, your code has DIR.xy where it should be DIR.yx.

Oh, and your calculation of ddx should be the following
double ddx = dvector_x*OM.xx + dvector_y*OM.yx + dvector_z*OM.zx; 

Please fix this in the code and try again.

I did have a problem moving the vehicle in the new version. My number pad does not cause the vehicle to translate at all, even with num lock enabled. The vehicle just sits there. Is it because you''re continuously scaling the velocity down by 0.997 so that it becomes zero quickly, or because you''re setting it to zero in the constructor? Yesterday the car did translate and my code should not change this.

As for what I mean by DIR[?], it is exactly as you guessed:
DIR[0] = DIR.xxDIR[1] = DIR.yxDIR[2] = DIR.zx 

I am unfamiliar with your Java 3D API and so I had to see your new information to know this. Since the translation vector, (xo, yo, zo), is the last column of the matrix it must be that the local coordinate vectors of the object are in the first three columns.

If you take your transformation matrix, it is somewhat easy to see how the rotation works. The matrix rotates the x axis of the original object into the vector represented by the first column of the transformation matrix. Try it:
[rotated_xx]   [xx  xy  xz] [1]|rotated_yx| = |yx  yy  yz| |0|[rotated_zx]   [zx  zy  zz] |0| 

Here, I''m post multiplying the transformation matrix by a unit vector in the x direction. The result is the *rotated* x axis. Do the multiply and you will see that:
[rotated_xx]   [xx]|rotated_yx| = |yx|[rotated_zx]   [zx] 

And so the effect of the transformation matrix is to rotate the original coordinate system so that its x axis now points along the vector (xx, yx, zx), the y axis points along (yx, yy, yz), and the z axis points along (zx, zy, zz). You sort of have to do the math to figure that out, and it just takes time to get accustomed to it. The whole thing is easier understood if you relate to dot products. I just don''t have time to go into that this minute. It really needs a picture, and I may see if I can find a good reference for you.

In your matrix, the normal of the object *should* be represented by the terms (xz, yz, zz). You can check it. See if (xz, yz, zz) is exactly the same as normalSquare from your old code. (It should be the same.) And I''m just asserting that the object x direction (xx, yx, zx) is the forward direction of the vehicle. The way you''ve written it, the local vehicle axes are in the rows of the matrix.

Your set_transform_mat() method is exactly what I wanted. We can talk about the easier and faster way to solve your problem.

I''m not surprised that you''re perplexed about step 3. It requires a picture. Or really 2 or 3 pictures. It is difficult to describe in words.

Don''t worry if you don''t understand all my math yet. I studied the same things as you. You should know that I''ve been doing 3D graphics and computational geometry since the mid 1980''s, and so I''m just very very experienced! It will come in time my friend!


Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
hallo ghrodes;

after having a hard codin'' night i finally made it.
well, i considered to calcuate a revision angle to rotate the car in that angle and fix the problem. i took the first vertex of the hitted surface and calculated the angle between this and the car''s orientation. it worked fine, but not at all. at some areas it started to rotate random. the old problem --> this.
i simply did the following thing to fix this:
NSurface = -NSurface. thats it. it work`s perfectly.
here u can see car in action (there a just some physics bug, don''t worry about). Cruzo
now lets discuss the faster way of transforming.
unwritten letters
Great! I''m happy you got the code working. The game looks cool. Just a bit too sensitive and sometimes unstable physics, but when you get the controls working better and when you have a camera controller it should be quite fun to play!

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net

This topic is closed to new replies.

Advertisement