Jump to content
  • Advertisement
Sign in to follow this  
akaitora

Look vector to Rotation Matrix

This topic is 3267 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

Hi guys. What is the easiest way to take a 3d normalized look vector and turn it into a rotation matrix such that the entity will be looking in the direction of the look vector? Thanks.

Share this post


Link to post
Share on other sites
Advertisement
Assuming you use OpenGL look at this code:


Matrix4x4& Matrix4x4::LookAt ( const Vector3<float>& vecPos, const Vector3<float>& vecLookAt, bool Reset )
{
Vector3<float> X, Y, Z;
Z = vecPos - vecLookAt; Z.Normalize();
X = cross(Vector3<float>(0.0f, 1.0f, 0.0f), Z);
if ( magnitude(X) < 0.01f)
X = cross(Vector3<float>(0.0f, 0.0f, 1.0f), Z);
if ( magnitude(X) < 0.01f)
X = cross(Vector3<float>(1.0f, 0.0f, 0.0f), Z);
X.Normalize();
assert( magnitude(X) != 0.0f);
Y = cross(Z, X);
Y.Normalize();

if ( Reset == true ) {
_m11 = X.x; _m12 = Y.x; _m13 = Z.x; _m14 = 0.0f;
_m21 = X.y; _m22 = Y.y; _m23 = Z.y; _m24 = 0.0f;
_m31 = X.z; _m32 = Y.z; _m33 = Z.z; _m34 = 0.0f;
_m41 = -dot(vecPos, X); _m42 = -dot(vecPos, Y); _m43 = -dot(vecPos, Z); _m44 = 1.0f;

return *this;
}

Matrix4x4 view(X.x, Y.x, Z.x, 0.0f,
X.y, Y.y, Z.y, 0.0f,
X.z, Y.z, Z.z, 0.0f,
-dot(vecPos, X), -dot(vecPos, Y), -dot(vecPos, Z), 1.0f);

*this *= view;

return *this;
}

Share this post


Link to post
Share on other sites
Well, think of the identity matrix (column mayor notation):


[1 0 0 0]
[0 1 0 0]
[0 0 1 0]
[0 0 0 1]


you can think of each column as a direction vector, such that column 1 is the "right" vector, column 2 is the "forward" vector and column 3 is the "up" vector (if you're using Y as up, just swap Y for Z)

Now, you have the forward vector 'f', your normalized direction vector, so replace it into your matrix:

[1 fx 0 0]
[0 fy 0 0]
[0 fz 1 0]
[0 0 0 1]


you know which way is up in your game world (0,0,1) this vector we will call U, so do a cross product with your forward vector and your up vector to get the right vector 'r':

r = normalize ( f x U)

now you have your right vector:


[rx fx 0 0]
[ry fy 0 0]
[rz fz 1 0]
[0 0 0 1]


Finally once you have both right and forward vectors you can calculate your object space up vector 'u', same as before using cross product:

u = normalize ( r x f)

and there you have it:


[rx fx ux 0]
[ry fy uy 0]
[rz fz uz 0]
[0 0 0 1]


This is what gluLookAt does.

(the cross product gives you a perpendicular vector to the plane in which the 2 vectors reside)

[Edited by - Kwizatz on December 7, 2009 1:49:15 PM]

Share this post


Link to post
Share on other sites
I have tried creating a row major version for DirectX/XNA as follows:


public static Quaternion GetOrientation(Vector3 v_Position, Vector3 v_Direction, Vector3 up)
{
Vector3 zAxis = Vector3.Normalize(v_Direction);

Vector3 xAxis = Vector3.Cross(up, zAxis);

if (xAxis.Length() < 0.01f)
{
xAxis = Vector3.Cross(Vector3.UnitZ, zAxis);
}
xAxis.Normalize();

Vector3 yAxis = Vector3.Normalize(Vector3.Cross(zAxis, xAxis));

Matrix m = Matrix.Identity;

// Row Major
m.M11 = xAxis.X;
m.M12 = xAxis.Y;
m.M13 = xAxis.Z;

m.M21 = yAxis.X;
m.M22 = yAxis.Y;
m.M23 = yAxis.Z;

m.M31 = zAxis.X;
m.M32 = zAxis.Y;
m.M33 = zAxis.Z;

m.M41 = -Vector3.Dot(v_Position, xAxis);
m.M42 = -Vector3.Dot(v_Position, yAxis);
m.M43 = -Vector3.Dot(v_Position, zAxis);

return Quaternion.CreateFromRotationMatrix(m);
}



It appears to work with no problems but I wanted to check a few things with you guys.

Could you explain what the M41, M42, M43 are in this case? Do they need to be changed from column major to row major?

If -ve Z goes into the screen the look direction remains positive, correct?

Thanks.

Share this post


Link to post
Share on other sites
Quote:
Original post by Spa8nky
Could you explain what the M41, M42, M43 are in this case? Do they need to be changed from column major to row major?
Thanks.


They should be position, if you don't need to set a position, set them to 0, gluLookAt just assigns the negated provided position as-is to this row/column, I have no idea why Deliverance is doing a dot product, but what it does is project the position onto the local axis after rotation.

Since you're extracting a Quaternion, I would think those values are ignored anyway (Quaternions contain no position information)

Quote:
Original post by Spa8nky
If -ve Z goes into the screen the look direction remains positive, correct?


I didn't understand that last part.

Share this post


Link to post
Share on other sites
Thanks Kwizatz, that makes sense now.

I probably should explain the last part:

If I have a textured quadrangle rendered in DirectX/XNA with no rotation (Quaternion.Identity), is the normal of the quadrangle (0,0,1) or (0,0,-1)?

Share this post


Link to post
Share on other sites
Quote:
Original post by Spa8nky
Thanks Kwizatz, that makes sense now.

I probably should explain the last part:

If I have a textured quadrangle rendered in DirectX/XNA with no rotation (Quaternion.Identity), is the normal of the quadrangle (0,0,1) or (0,0,-1)?


Depends on the vertex order... not sure if I understood still, but anyway, I really don't know about D3D, but OpenGL's camera 'forward' vector is 0,0,-1 (by default the camera looks down the Z axis), which is why it is negated if you look up the man page for gluLookAt, as you can see here (note: that page uses row mayor notation).

Share this post


Link to post
Share on other sites
Ok, no problem, it works fine apart from the following:

If I have a quadrangle facing backwards, its up vector is (0,1,0). This is a problem when I want the quadrangle to face up from default of facing backwards.

Now in the code I attempt to solve this problem with:


if (xAxis.Length() < 0.01f)
{
// Pick another unit axis
xAxis = Vector3.Cross(Vector3.UnitX, zAxis);
}


However, although this works and the quad will face up, the texture on the quad will face (0,0,1). Is this to be expected?

If I use:

xAxis = Vector3.Cross(Vector3.UnitZ, zAxis);

then the quadrangle will still face up but the texture will now point towards UnitZ.

Thanks again.

Share this post


Link to post
Share on other sites
Quote:
Original post by Spa8nky
Ok, no problem, it works fine apart from the following...


Hmmm... you could try swapping the operands from the cross products, depending on their order the normal will face one way or the other (forward or backward) so maybe you're getting one or more of the vectors flipped.


Share this post


Link to post
Share on other sites
The matrix i prrovided contains a rotation matrix and a translation matrix. They are combined by multiplying matrices like this:

ViewMatrix = Translation^(-1) * Rotation (rotation is applied first)

(1, 0, 0, 0, (X.x, Y.x, Z.x, 0.0f,
0, 1, 0, 0, * X.y, Y.y, Z.y, 0.0f,
0, 0, 1.0f, 0.0f, X.z, Y.z, Z.z, 0.0f,
-vecPos.x -vecPos.y, -vecPos.z, 1.0f) 0 0 0, 1.0f)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!