Look vector to Rotation Matrix
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.
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;}
Well, think of the identity matrix (column mayor notation):
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:
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:
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:
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]
[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]
I have tried creating a row major version for DirectX/XNA as follows:
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.
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.
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.
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)?
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)?
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).
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:
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.
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.
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.
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)
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)
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement