Sign in to follow this  

How to rotate an object to terrain normal

This topic is 3838 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have an idea on how to do this but not 100% sure on how to implement it. 1.Get Normal of object to terrain? 2.Get Normal of terrain at point X? 3.Take cross() of those two? 4.Align object's normal you found to terrains normal? I have a lot of books, but can't think of any I have that I ever came across on how to implement this... So if anyone has a specific book that covers this I would appreciate it or if someone has a tutorial site that would be great also. I have looked around and most just talk theory not actual code base to learn from. I am not going to be doing each wheel for my models as of now are modeled as a solid unit... thanks [Edited by - MARS_999 on June 9, 2007 5:45:55 AM]

Share this post


Link to post
Share on other sites
you can use the followign method to generate a rotation matrix to transform an object alligned with the y-axis to the surface normal:

let the surface normal be the unit vector 'y'

then you have:

x = [y.z, 0, -y.x]/sqrt(y.x*y.x+y.z*y.z);
z = x cross y

thatll give a rotation matrix:

[x.x y.x z.x 0]
[x.y y.y z.y 0]
[x.z y.z z.z 0]
[ 0 0 0 1 ]

which you can add to the modelview transformation.

there is one degenerate case, when y.x and y.z are both 0, in which case you can use the matrix:

[ 1 0 0 0 ]
[ 0 y.y 0 0]
[ 0 0 0 y.y 0]
[ 0 0 0 1 ]

in otherwords, for a terrain this will be when its completely flat, and the rotation matrix will be the identity matrix since the terrain wont be upside down

Share this post


Link to post
Share on other sites
Ok here is what I have... I think I am close, but need someone who has an idea on this to take a look. Thanks


void RotatePlayerToTerrainNormal(Player *player, vec3 &normal)
{
Matrix4x4 matrixMV;
glGetFloatv(GL_MODELVIEW_MATRIX, matrixMV.matrix);

if(normal.x == 0.0f && normal.z == 0.0f)
{
Matrix4x4 tempMatrix;
tempMatrix.Identity();
tempMatrix *= matrixMV;

player->model->rot.x = tempMatrix.matrix[12];
player->model->rot.y = tempMatrix.matrix[13];
player->model->rot.z = tempMatrix.matrix[14];
}
else
{
vec3 x = vec3(normal.z, 0.0f, -normal.x) / sqrt(normal.x * normal.x + normal.z * normal.z);
vec3 z = Cross(x, normal);

Matrix4x4 tempMatrix(x.x, normal.x, z.x, 0.0f,
x.y, normal.y, z.y, 0.0f,
x.z, normal.z, z.z, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);

tempMatrix *= matrixMV;

player->model->rot.x = tempMatrix.matrix[12];
player->model->rot.y = tempMatrix.matrix[13];
player->model->rot.z = tempMatrix.matrix[14];
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by Rasmadrak
Have you tried implementing it? Does it work?


Which one? My TBN idea? If so yes and I can't get the math right, for how to setup the matrices.

If you are referring to luca-deltodesco idea, I posted my code and that isn't working either.

Thanks for the reply. I am about bald from pulling my hair out... :(

Share this post


Link to post
Share on other sites
Here is what I have now and still isn't working...


void RotatePlayerToTerrainNormal(Player *player, Camera &camera)
{
Matrix4x4 rotationMatrix;
vec3 terrainNormal = gterrain->GetTerrainNormal(camera.View.x, camera.View.z);
vec3 player1Normal = vec3(player->model->Objects->Normals[3],
player->model->Objects->Normals[4],
player->model->Objects->Normals[5]);

float angle = Dot(terrainNormal, player1Normal);

rotationMatrix.Rotate(angle, true, true, true);//rotate on all three axes
vec4 tempRotation = rotationMatrix.VectorMatrixMultiply3x3(player->model->rot);
player->model->rot.x = tempRotation.x;
player->model->rot.y = tempRotation.y;
player->model->rot.z = tempRotation.z;
}



Share this post


Link to post
Share on other sites
Once you get the angle between the terrain normal and the player's normal, you then need to find the cross product and rotate around it........not all 3 axis.

So....

float angle = Dot(...);
Vec3 cross = CrossProduct(...);
cross.normalize();

rotationMatrix.rotate(angle, cross.x, cross.y, cross.z);

Share this post


Link to post
Share on other sites
Thanks for the reply soconne, here is what I have but am sure its wrong...


void RotatePlayerToTerrainNormal(Player *player, Camera &camera)
{
Matrix4x4 rotationMatrix;
vec3 terrainNormal = gterrain->GetTerrainNormal(camera.View.x, camera.View.z);
vec3 player1Normal = vec3(player->model->Objects->Normals[3],
player->model->Objects->Normals[4],
player->model->Objects->Normals[5]);

float angle = Dot(terrainNormal, player1Normal);
vec3 crossProduct = Cross(terrainNormal, player1Normal);
crossProduct.Normalize();

rotationMatrix.Rotate(angle, int(crossProduct.x), int(crossProduct.y), int(crossProduct.z));

//vec4 tempRotation = rotationMatrix.VectorMatrixMultiply3x3(player1Normal);

player->model->rot.x = RADTODEG(rotationMatrix.matrix[12]);
player->model->rot.y = RADTODEG(rotationMatrix.matrix[13]);
player->model->rot.z = RADTODEG(rotationMatrix.matrix[14]);
//player->model->rot.x = RADTODEG(tempRotation.x);
//player->model->rot.z = RADTODEG(tempRotation.z);
}

Share this post


Link to post
Share on other sites
Quote:
Original post by MARS_999
Thanks for the reply soconne, here is what I have but am sure its wrong...

*** Source Snippet Removed ***


Its wrong because you're causing the x, y, z values of the cross product to become 0!! That vector is going to have floating point values less than 1.0. Does your rotate function rotate around an arbitrary vector or the main axis?

Here is my function for doing it.



void Matrix4::setupRotate(const Vector3 &axis, float theta)
{

// Quick sanity check to make sure they passed in a unit vector
// to specify the axis
assert(fabs(axis*axis - 1.0f) < .01f);

// Get sin and cosine of rotation angle
float s, c;
sinCos(&s, &c, theta);

// Compute 1 - cos(theta) and some common subexpressions
float a = 1.0f - c;
float ax = a * axis.x;
float ay = a * axis.y;
float az = a * axis.z;

// Set the matrix elements. There is still a little more
// opportunity for optimization due to the many common
// subexpressions. We'll let the compiler handle that...
m[0] = ax*axis.x + c;
m[1] = ax*axis.y + axis.z*s;
m[2] = ax*axis.z - axis.y*s;

m[4] = ay*axis.x - axis.z*s;
m[5] = ay*axis.y + c;
m[6] = ay*axis.z + axis.x*s;

m[8] = az*axis.x + axis.y*s;
m[9] = az*axis.y - axis.x*s;
m[10] = az*axis.z + c;

// Reset the translation portion
m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f; m[15] = 1.0f;
}



So you're code should stay the same, except after you call the above function, you need to actually store the entire new matrix and NOT just 3 simple values like you're doing. In my application I store a 3x3 rotation matrix for each object, not just a x,y,z rotation vector. I'm not sure if you can fully represent the proper rotation that way.

Share this post


Link to post
Share on other sites

This topic is 3838 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this