Quickly Extracting Angles from Vectors

Started by
6 comments, last by Providence 18 years, 10 months ago
I'm currently using D3DXMatrixLookAtLH() to create my view transform because the code, even though I don't understand it, looks so much simpler and faster than the complicated nonsense I was using to construct my view matrix^[1]. Unfortunately, I can't figure out how to determine the direction the camera is pointing in world space so that I can then have my player object (3rd person view) also face that direction (or left/right/backward/etc relative to the camera direction) when walking. [1] Here's what I called "complicated nonsense". This was quickly reproduced, as it has been long since deleted, so it may not be functional. float xo,yo,zo,rx,ry,rz; /* update these when the camera moves */ D3DXMATRIX view,trans,rotx,roty,rotz,temp1,temp2; D3DXMatrixTranslation(&trans,xo,yo,zo); D3DXMatrixRotationX(&rotx,rx); D3DXMatrixRotationY(&roty,ry); D3DXMatrixRotationZ(&rotz,rz); D3DXMatrixMultiply(&temp1,&trans,&rotx); D3DXMatrixMultiply(&temp2,&temp1,&roty); D3DXMatrixMultiply(&view,&temp2,rotz); D3Ddevice->SetTransform(D3DTS_VIEW,&view);
Advertisement
The view matrix transforms objects from world space to view space. You have the camera's forward (or look_at) vector in viewspace as <0,0,1>. You want to transform it from view space to world space. That means you want the inverse of the world-to-view transformation, i.e. the inverse of the view matrix.

So, invert your view matrix, transform <0,0,1> by it, and you have your camera's look_at vector in world-space. Of course, transforming a <0,0,1> vector by a matrix will produce a vector whose components are matrix._31, matrix._32 and matrix._33, so you can just extract it directly.

Alternatively, if you have the camera's orientation in angles, you can also construct the vector with some sines and cosines. Sketch it on a piece of paper and it should be obvious. If not, and you'd like to go down this path, just say so.

EDIT: Wait a minute. You're using D3DXMatrixLookAtLH, so you already know your look_at vector in world space. What's the problem then?

[Edited by - Coder on May 23, 2005 10:27:17 AM]

My problem is that I'm trying to use D3DXMatrixRotationY() to face the character in the right direction. But that function takes an angle and not a vector. So I can get the direction from the eye point and look at point in vector form, but then I'd need to convert it into an angle in order to use it, which I seem to be failing at (my character faces the wrong way for half the angles). I was hoping that I could somehow skip this step (converting vector direction to angle) and just use the vector directions.
The direction where the camera is pointing is "vLookAt - vEye", so you need define/update these vectors to get the right direction.

Suppose that the camera's target (vLookAt vector) is always the character's position. So, the idea is to move the character (and the vLookAt, consequently) and to make the camera's eye (vEye vector) to follow vLookAt. For that, you could define a "directional vector" and to transform it, like this:

D3DXVECTOR3 vEyeLookAt ( ... , ... , ... ); // define a initial directional vector

D3DXMatrixRotationY( &matRotY, ang ); // get a rotation matrix based on the input angle

D3DXVec3TransformCoord( &vEyeLookAt, &vEyeLookAt, matRotY); // rotate vEyeLookAt

D3DXVECTOR3 vLookAt = vCharacter; // update the position of the character

D3DXVECTOR3 vEye = vLookAt - vEyeLookAt; // calculate the position of the camera's eye

Now, just pass vEye and vLookAt vectors to D3DXMatrixLookAtLH() function.
Also, to extract the angle between two vectors you must normalize these vectors and to calculate the dot product of them:

D3DXVec3Normalize( &V1, &V1 );
D3DXVec3Normalize( &V2, &V2 );
angle = D3DXVec3Dot( &V1, &V2 );
You can just pull the xz direction of your camera from the view matrix:
Vector cam_forward( view._13, 0.0f, view._33 );
cam_forward.Normalize();

If your camera is looking mostly up or down, you may need to replace z with y (change view._33 to view._23).

The vector's Y angle can be computed by doing something like this:
FLOAT y_angle;if( cam_forward.z >= 1.0f ){  y_angle = 0.0f; // already facing forward}else if( cam_forward.z <= -1.0f ){  y_angle = PI; // full 180}else{  y_angle = acosf( cam_forward.z );  if( cam_forward.x < 0.0f ) // need to turn left    y_angle = -y_angle;}


Let me know if you have any problems.
Quote:Original post by Providence
My problem is that I'm trying to use D3DXMatrixRotationY() to face the character in the right direction. But that function takes an angle and not a vector. So I can get the direction from the eye point and look at point in vector form, but then I'd need to convert it into an angle in order to use it, which I seem to be failing at (my character faces the wrong way for half the angles). I was hoping that I could somehow skip this step (converting vector direction to angle) and just use the vector directions.

With your look_at vector, character's "up" vector (typically <0,1,0>):
right = up cross look_at
up = look_at cross right

Stick these into a matrix as follows:
right.x   right.y   right.z    0up.x      up.y      up.z       0look_at.x look_at.y look_at.z  0pos.x     pos.y     pos.z      1

Use this as the character's world matrix.

EDIT: This will orient your character completely, like a plane does for example. If your character is a human or something (you only want it to turn left/right), before you do any calculations with look_at, zero its y component and normalize it.

[Edited by - Coder on May 24, 2005 9:43:26 AM]

Quote:Original post by Coder
With your look_at vector, character's "up" vector (typically <0,1,0>):
right = up cross look_at
up = look_at cross right

Stick these into a matrix as follows:
right.x   right.y   right.z    0up.x      up.y      up.z       0look_at.x look_at.y look_at.z  0pos.x     pos.y     pos.z      1

Use this as the character's world matrix.

EDIT: This will orient your character completely, like a plane does for example. If your character is a human or something (you only want it to turn left/right), before you do any calculations with look_at, zero its y component and normalize it.


Thank you! That is just the thing I was looking for.

This topic is closed to new replies.

Advertisement