rotation to a given angel
#1 Members  Reputation: 122
Posted 29 June 2001  08:03 AM
#2 Members  Reputation: 1377
Posted 29 June 2001  09:47 AM
Do you mean that you want the xy plane of the vehicle (the xy plane being the plane of the wheels) to be aligned with the hill surface (i.e., the plane of the vehicle is always perpendicular to the normal of the hill)?
Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
#3 Anonymous Poster_Anonymous Poster_* Guests  Reputation:
Posted 29 June 2001  06:53 PM
cross around a 3dlandscape, jump, fire, crash, ect.
the zrotangle of vehicle is used for its direction.
yes, i want to align the wheels plane(x,yrot) with the
hills surface(the angle between surfacenormal and
vehiclenormal = 0).
z



/x
/
/
y
#4 Members  Reputation: 1377
Posted 04 July 2001  11:21 AM
Also, since you have a registered user name, please do not post as an Anonymous Poster.
Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
#6 Members  Reputation: 1377
Posted 06 July 2001  09:27 AM
Seeing your code helps me better see what you''re trying to do! The process of getting the normals to line up is actually the easy part. Maintaining the direction of orientation in the xy plane (your zrot angle) at the same time makes it tricky. I have some comments on how you''re rotating the square to line its normal up with the triangle normal. We''ll deal with zrot later.
I''m not sure what Java API you are using for your 3d math. I assume that OM.xrot() means "take the current orientation of the object and rotate it about the x axis by the given angle." Is this true? (Another interpretation is that OM.xrot() means "set the rotation angle about the x axis to be the given angle.")
Here is why I believe you are unable to get the square''s normal to line up with the triangle normal when you try to do both x and y rotations. I believe you''re ignoring the fact that the normal of the square *changes* when you do the OM.yrot(). The normal of the square will actually be different after yrot() than before yrot(). Thus, if you are using the original values for normalSquare when you finally do OM.xrot(), your value of ddx is either too large or too small, and you aren''t rotating by the correct angle. The order of rotations is also important. You will get a different result if you do OM.xrot() first and then OM.yrot() second. Your approach may work if you grab the updated normalSquare before calculating ddx and doing xrot().
Is it possible in your 3D API to specify an angular rotation about an arbitrary given axis, perhaps as a quaternion? If so, you can do the following to the square to line it up with the triangle using one rotation:
1) Find the cross product of normalSquare and normalTriangle. Make it a unit vector. The resulting vector defines the axis to rotate about.
2) Find the angle between normalSquare and normalTriangle. Don''t worry about separating xrot and yrot. Just get one angle using the following formula:
dda = normalSquare[0]*normalTriangle[0] + normalSquare[1]*normalTriangle[1] + normalSquare[2]*normalTriangle[2]
angle = Math.acos(dda);
angle_in_degrees = angle * 180/Math.PI;
3) Do the rotation about the axis determined in step 1 with angle angle_in_degrees. If your API requires that you specify this as a quaternion, then the quaternion would be:
cos(angle/2) + i(ax*sin(angle/2)) + j(ay*sin(angle/2)) + k(az*sin(angle/2))
Where (ax, ay, az) is the unit vector found in step 1.
Note that the quaternion requires the angle in radians so don''t use angle_in_degrees for this.
4) After step 3, the normals should be lined up perfectly even when you rotate the triangle arbitrarily.
If your API cannot support rotation about an arbitrary axis, or if you don''t follow this approach, then can you list the code for doing *both* rotations on your sample web page? I can then help you adjust your code to get it to work.
Also, since your goal is to merely make sure the vehicle is always perfectly aligned with the surface, yet pointing in the direction of travel, there is an easier way to do the whole process, but it requires that your API be able to directly set the transformation matrix for the vehicle/square.
Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
#8 Members  Reputation: 1377
Posted 09 July 2001  06:38 AM
About the remaining artifact. You'll notice that the normal is actually flipping too, so the polygon face is flipping 180 degrees and not just rotating within its plane. I have an idea about what's going on. Lets analyze it.
The square and triangle are always very close to aligned, and the correction of the square at each frame never needs to be a very large correction. The dot product, dda, for example, is probably always positive (unless the frame rate drops significantly or perhaps at the first step). In fact, if the normals are unit vectors then dda is usually going to be close to 1.0. That means your rotation angle will always be zero or slightly positive, since acos returns only zero or positive values from 0 to pi. So there's no weirdness going on with the dot product calculation, and the angle of rotation. The rotation angle will be small, so you wouldn't expect the normal to flip 180 degreesand yet it does.
Lets look at the calculation of the axis of rotation, (ax, ay, az). Now *THIS* could be the cause of trouble. Consider that the triangle and square normal may be very close to one another in some cases. If they are, then it could be that the computed length of (ax, ay, az) is very nearly zero, and we don't really have a usable vector at all. Roundoff error in the quaternion calculation could result in some terms of the transformation matrix being zero when they aren't *really* zero. The behavior of your quaternion would be eratic in that case. I suggest you check and if fabs(length) < 1.e6 don't do any rotation for that frame.
My guess is that the weirdness is occuring when normalSquare and normalTriangle are essentially parallel as described in the preceding paragraph. The only other thing I can think of is that perhaps your normalSquare and normalTriangle are *not* unit vectors. If they are not unit vectors then you are getting garbage out of acos and so your quaternion is bad. But since the thing is working most of the time I don't think this is the problem.
It seems to me you may have one remaining issue. How to orient the square so that it is pointing in the direction it is moving, while at the same time maintaining the normal alignment that you now have working. Is this still an open issue, or do you have the information you need?
Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Edited by  grhodes_at_work on July 9, 2001 1:40:40 PM
#9 Members  Reputation: 122
Posted 09 July 2001  11:41 AM
well, u''re right, the anormal rotation happens when angle between the 2 normals becomes to close, but i can avoid this by initalising the square by a nice direction (sorry for my terribly engl. u know what i mean) and at least angle of surface will never become critical.
2.
quaternion > rotation about an arbitrary axis (hmm, the normal of square :>)
3.
there is one more problem (i think the last one for this). please download this , extract and doubleclick to Cruzo.jar, or enter at shell java jar Cruzo.jar . u''ll need the java JDK 1.3 to run it.
make sure numlock is activated. use 4,6,8,2 at numpad to move car (dont worry about stupid movement, just for testing). move it over a mountain. why does the car rotate about zaxis? (Car.java at:122144) s.getNormalAtCoordinates(x,y) returns the unitnormal of surface hitted at (x,y  the green plane). i did everything as above mentioned. i''m perplexed a little bit.
4.thanx
#11 Members  Reputation: 1377
Posted 10 July 2001  05:12 AM
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 twostep 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 "multiobjective 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.
#12 Members  Reputation: 1377
Posted 11 July 2001  07:16 AM
The approximation is as follows. Instead of doing steps 14 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.
#13 Members  Reputation: 122
Posted 11 July 2001  10:35 AM
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_directionvector 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 matrixop, 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).
#14 Members  Reputation: 1377
Posted 11 July 2001  02:22 PM
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.xx
DIR[1] = DIR.yx
DIR[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.
#15 Members  Reputation: 122
Posted 16 July 2001  04:20 AM
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.
#16 Members  Reputation: 1377
Posted 16 July 2001  04:43 AM
Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.