0
101 Oct 01, 2009 at 23:24

Hi
I am a new to graphic programming. I manage to get the surface normal of a triangle. Now I want to rotate an axis using right hand rule. How do you go about doing this ?

God Bless
Eng Huat

#### 15 Replies

0
139 Oct 01, 2009 at 23:44
0
101 Oct 02, 2009 at 00:03

I’m a bit confused by the question. You have a triangle normal and you also have a second vector and you want to rotate that second vector around the normal? Or something else? When you say “to” surface normal it implies to me they will be the same normal when you are done in which case there is really nothing to do so I figure you mean something else.

0
101 Oct 02, 2009 at 00:13

Imagine there is a slope and I need to place the tank up the slope where the top of the tank will be the z - axis.

0
101 Oct 02, 2009 at 00:46

@elijah

Imagine there is a slope and I need to place the tank up the slope where the top of the tank will be the z - axis.

Ok got you.

So if you have two unit vectors; your normal and the Z of the tank, you can get the cos of the angle between them by taking the dot product of the two vectors. So the acos of that then gives you the angle you need to rotate your tank by. Then if you take the cross product of the same two vectors and normalize the result you will get a unit vector axis that you can rotate your tank around by the aforementioned angle.

Then you can build a matrix to rotate your tank. Here is some crappy C++ code I wrote for that. Note that a) I am working left hand cooridnates b) I left off the last column of the matrix to save a bit of calculation. (I assume it to be 0,0,0,1 going down) and c) you will still have to multiply in the translation matrix to put your tank in the correct location on the hill. Read Reedbeta’s link for an overview.

template<class T> void TRPG3DMatrix<T>::Set(const TRPGVector<T> &clAx, T fTheta, CRPG3DAxisRotate &clType)
{
m_pType = &clType;
T c = cos(fTheta);
T s = sin(fTheta);
T t = 1.0-c;
T fX = clAx.X();
T fY = clAx.Y();
T fZ = clAx.Z();
m_a.D[0][0]= t*fX*fX + c;           m_a.D[0][1]= t*fX*fY - s*fZ;        m_a.D[0][2]= t*fX*fZ + s*fY;
m_a.D[1][0]= t*fX*fY + s*fZ;        m_a.D[1][1]= t*fY*fY + c;           m_a.D[1][2]= t*fY*fZ - s*fX;
m_a.D[2][0]= t*fX*fZ + s*fY;        m_a.D[2][1]= t*fY*fZ + s*fX;        m_a.D[2][2]= t*fZ*fZ + c;
m_a.D[3][0]= 0;                     m_a.D[3][1]= 0;                     m_a.D[3][2]= 0;
}


Hope that helps

0
103 Oct 02, 2009 at 04:54

If you have a fuzzy front, then make the up the normal of the triangle, cross to get the right, normalize the right (very important) then recross to get the real front.

just point the fuzzy front flat in the direction you generally want the tank to go in.

And that should work too - just dont expect it to go straight up a horizontal(vertical i mean) cliff, because thats the weakness with this method. :)

And as I guess you know, thats a valid basis for the models orientation, which is what you wanted.

0
101 Oct 02, 2009 at 06:42

Hi SyntaxError,

I have tried your recommendation. It works for most cases. I did this test on a cylinder. half of the body that is facing back gives the correct axis, but the front body of the cylinder gives the wrong axis. Any ideal how I can solved this ? This cylinder is cull back design.

0
101 Oct 02, 2009 at 06:45

Hi roucer,

I’m sorry What is fuzzy front. I’m new in graphics.

0
103 Oct 02, 2009 at 07:01

I invented it sorry :). I mean point on the xz plane where you want the tank to “point” as if it was on flat ground.

then if you double cross and normalize like that youll “tilt” the tank onto a slanted ground but itll still have its turret pointing in the direction you want it.

0
101 Oct 02, 2009 at 07:14

Any tips on how to solve my problem. Perth is a nice place. I was there 2 years ago

0
101 Oct 02, 2009 at 12:53

@elijah

Hi SyntaxError, I have tried your recommendation. It works for most cases. I did this test on a cylinder. half of the body that is facing back gives the correct axis, but the front body of the cylinder gives the wrong axis. Any ideal how I can solved this ? This cylinder is cull back design.

Now I’m confused again. You are using your cylinder as your tank or the cylinder as your terrain? You should be transforming your entire tank by the same matrix so if it’s wrong the whole thing should be wrong.

In any case if you are using a cylinder as your terrain, you need to make sure you are getting the correct surface normals. I’m not sure how you are storing your data but in a mesh edges can’t all be directed in one winding. If you draw out a mesh on a piece of paper you will notice you can’t make your triangles all one winding. Therefore you need to be able to somehow get the correct winding so you can get the correct normals. Perhaps that’s your problem. What mesh format are you using? Is it your own?

The other thing is there are special cases where your tank is already aligned with the terrain or exactly opposite the terrain. In those cases you can’t use cross product because it won’t give you an axis vector. Just add in a couple special cases for that.

Finally you still need to point your tank in the right direction. You can do that rotating around Z before you transform you tank to the terrain.

0
101 Oct 02, 2009 at 13:16

Actually I’m using the cylinder as a test case. When I press on the face of the triangle that made up the cylinder, the Z - Axis will point to the normal of the triangle.

The normal is calculate from the 3 points in the triangle. The code is below

public static Vector3f getTriangleNormal(Point3f p1, Point3f p2, Point3f p3) {
Vector3f Normal, AB, AC;

AB = new Vector3f(p1);
AB.sub(p2);

AC = new Vector3f(p1);
AC.sub(p3);

Normal = AB.cross(AB, AC);
Normal.normalize();

if (Normal.getX() == -0.0f) { Normal.setX(0.0f); }
if (Normal.getY() == -0.0f) { Normal.setY(0.0f); }
if (Normal.getZ() == -0.0f) { Normal.setZ(0.0f); }

return Normal;

}

public Transform3D getTransform3D(){
Vector3f INVERSE_NORMAL = NORMAL.clone();

TRANSFORM_3D_AXIS = new Transform3D();

float Angle_Value = gcMaths.VectorDotProduct( INVERSE_NORMAL, Vector3f.POSITIVE_Z_AXIS );

float angle = FastMath.acos( Angle_Value );

//AXIS_VECTOR = gcMaths.VectorCrossProduct( INVERSE_NORMAL , Vector3f.POSITIVE_Z_AXIS );

AXIS_VECTOR = gcMaths.VectorCrossProduct( Vector3f.POSITIVE_Z_AXIS , INVERSE_NORMAL );

AXIS_VECTOR.normalize();

AXIS_ANGLE = new AxisAngle3f( AXIS_VECTOR, angle );

matrix = new Matrix4f();
matrix.set( AXIS_ANGLE );
TRANSFORM_3D_AXIS.set( matrix );

NAN_CASE = CheckNAN.checkTransform3D( TRANSFORM_3D_AXIS );

TRANSFORM_3D_AXIS = NegativeZeroCleanup.cleanTransform3D( TRANSFORM_3D_AXIS.getCopy() );

TRANSFORM_3D_AXIS = NANCleanup.cleanTransform3D( TRANSFORM_3D_AXIS.getCopy() );

return TRANSFORM_3D_AXIS;
}

Just think like a 3D cad drawing. Clicking on the surface of the object, the axis will point towards the normal of the face.

Hope you can help me on this.

0
101 Oct 02, 2009 at 14:41

@elijah

public static Vector3f getTriangleNormal(Point3f p1, Point3f p2, Point3f p3)

I’m not entirely familiar with the package you are using however one thing I would like to point out is the ordering of your points is important for normal calculation. This is called winding. For instance is p1, p2 p3 clockwise looking from the front of your triangle or counterclockwise? If you can’t guarantee it’s always the same your normals will be inverted sometimes.

@elijah

Just think like a 3D cad drawing. Clicking on the surface of the object, the axis will point towards the normal of the face.

Great…however CAD programs work in a particular winding. You need to choose one and enforce it. I use clockwise myself but it’s up to you.

0
101 Oct 07, 2009 at 05:49

Thanks you very much for helping me. I have a new post on Vector intersecting a traingle. Can anybody help me on this ?

0
103 Oct 07, 2009 at 10:29

Do you want to orientate a model apon a triangle??? what i said is it!!!

0
101 Oct 09, 2009 at 08:37

Actually I what to revolve a outline of the shape around an axis but the winding rules get mix up. You are correct on the winding rule. So now I’m thinking of using the calculate Normal to check it will intersect the plane.