Archived

This topic is now archived and is closed to further replies.

lexor

Z-axis always forward?

Recommended Posts

Hi. Im writing a camera class for a third-person-view game. In the game the user is able to move the main character by clicking anyware on the ground. The mouse moves along the X/Z-axis over a flat terrain. To do this I simply convert the X/Y mouse cords to X/Z in the 3d world. The problem is when I rotate my camera. I always want the mouse to move in the same direction as the camera points when the user moves the mouse up or down. Right and left should always be right and left from the camera perspective. I use device.Transform.View = Matrix.LookAtLH(camPos, camTarget, camUp); to move and rotate the camera. Now, When I move the mouse up the pointer goes up or down or right, it all depends on how the camera is rotated (and thereby in which direction the worlds Z axis are) Are there some magical function to do this or do I have to implement some math function? Thanks for any help!

Share this post


Link to post
Share on other sites
Well your problem is fairly simple to understand and easy to explain the solution but, implementing it might be a bit difficult( for me atleast )

You are trying to map your Mouse movement only onto a single fixed 2d plane in 3d space. So, ofcourse your mouse would behave awkwardly depending on the rotation of the camera.

So, in order to correct the mouse you have to change the 2d plane as well( Simple isnt it? ) Now, to this mapping you will need some maths ( if you dont know maths, some readymade functions) which i cannot recall now. If you dont get any good replies, I might by then post it here. So, be patient...

Share this post


Link to post
Share on other sites
OK, Thanks.

I too imagine the solution is fairly simple.
Of what I understand, one way is to rotate the world (all objects, lights) insted of the camera. This however seems to me to be a bit overkill for this thing.

There must be some function or math to allow me to only rotate the cam. I have been unable to locate any samples/tutorials that adress this very problem.

Any links are very welcome! Thanks!

Share this post


Link to post
Share on other sites
Here's one solution:

Before you finish the render function, save the one rotation value of the camera (which would be defined in the view matrix you 'made' earlier in the D3DX LookAt function). When the user moves the mouse, use some math (i.e. sin/cos/tan) to move the mouse X number of units in the direction that you saved earlier. I'm not sure what the matrix value you have to save is, but I'm sure the one you want is in there.

[edited by - cypher19 on January 15, 2004 10:02:54 AM]

Share this post


Link to post
Share on other sites
AAAaarrhh ...
Still no luck after ALOT of playing around with Sin/Cos/Tan.

What I''m after here is a way to always move the cursor away from the camera when the mouse are moved up.

When the camera rotation is 0-degrees the cursor should only be moved along the Z-axis.

When the camera rotation is 45-degrees the cursor should equally along the X-axis & Z-axis.

That way the user always thinks he moves the mouse up (or from him).

Share this post


Link to post
Share on other sites
Hmm...I'm gonna go check out the DX help and see how yaw/pitch/roll is stored.

Well, this is certainly difficult. (Btw, this will be beneficial to me too because I'm developing a 3D RTS of my own and I'm gonna be concerned about this at SOME point as well) I can't seem to find anything useful in the DX help, by the way.

[edited by - cypher19 on January 15, 2004 3:03:35 PM]

Share this post


Link to post
Share on other sites
You could follow the SDK pick sample and instead of doing a ray-triangle intersection test intersect your ray with the XZ plane

Here's the important part of the SDK sample:

D3DXMATRIXA16 matProj;
m_pd3dDevice->GetTransform( D3DTS_PROJECTION, &matProj );

POINT ptCursor;
GetCursorPos( &ptCursor );
ScreenToClient( m_hWnd, &ptCursor );

// Compute the vector of the pick ray in screen space

D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * ptCursor.x ) / m_d3dsdBackBuffer.Width ) - 1 ) / matProj._11;
v.y = -( ( ( 2.0f * ptCursor.y ) / m_d3dsdBackBuffer.Height ) - 1 ) / matProj._22;
v.z = 1.0f;

// Get the inverse of the composite view and world matrix

D3DXMATRIXA16 matView, matWorld, m;
m_pd3dDevice->GetTransform( D3DTS_VIEW, &matView );
m_pd3dDevice->GetTransform( D3DTS_WORLD, &matWorld );

m = matWorld * matView;
D3DXMatrixInverse( &m, NULL, &m );

// Transform the screen space pick ray into 3D space

vPickRayDir.x = v.x*m._11 + v.y*m._21 + v.z*m._31;
vPickRayDir.y = v.x*m._12 + v.y*m._22 + v.z*m._32;
vPickRayDir.z = v.x*m._13 + v.y*m._23 + v.z*m._33;
vPickRayOrig.x = m._41;
vPickRayOrig.y = m._42;
vPickRayOrig.z = m._43;


Let's say your terrain is flat and has y=d

then the point you are looking for is vPickRayOrig+(d-vPickRayOrig.y)/vPickRayDir.y*vPickRayDir

I guess this is a bit overkill, but i don't have any paper to do the maths myself right now

[edited by - Ghwerig on January 16, 2004 10:03:28 AM]

Share this post


Link to post
Share on other sites
A friend gave me one solution, but it don't seems to work...

CursorX = MouseX * Cos(90 - CameraAngle)
CursorZ = MouseY * Cos(CameraAngle)

The mouse needs a coordinate system of it's own, with the Z-axiz
always in the camera direction... but ...

I still cant get this right!



[edited by - leXor on January 16, 2004 10:42:23 AM]

Share this post


Link to post
Share on other sites
Ghwerig ...

Thank you!
I did not understand at first what values you ment by vPickRayOrig and vPickRayDir. But then it came to me that you ment The Original cam position and the cam Direction (camtarget - camposition). I just implanted the code and it works better than I could imagine! From very bad movement to exelent!

Thank you VERY much!

Share this post


Link to post
Share on other sites
You have to be careful with this code though. you might get a ray that is parallel to the xz plane so it won't intersect.

This would happen if you click above the horizon, so check for vPickRayDir.y==0

EDIT: Wait a sec. What are you doing? pickRayOrig and pickRayDir are calculated from you mouse coordinates and the inverses of your projection and view matrices. they are not camPos, camTarget-camPos

[edited by - Ghwerig on January 16, 2004 11:57:43 AM]

Share this post


Link to post
Share on other sites
But the ptCursor.X and ptCursor.Y are the mouse coords.
Anyway, I currently use the the Original CamTarget - CamPos
(Vector3(0, 0, -200) - Vector3(0, 0, 0) for vPickRayOrig and
the and the current Direction CamTarget - CamPos for vPickRayDir.

It works sweet! Could this cause a problem later on maybe?

Share this post


Link to post
Share on other sites
Sure .. it's in C#, but the names are nearly the same anyway:

I send in the 2D Mouse ordinates and out comes the position vector for the cursor over a flat terrain.



public Vector3 PickRay(float in_MouseX, float in_MouseY)
{
Matrix matProj;
matProj = mDevice.GetTransform(TransformType.Projection);

//////////////////////////////

Vector3 vPickRayDir = new Vector3();
Vector3 vPickRayOrig = new Vector3();

vPickRayDir = new Vector3(camTarget.X, camTarget.Y, camTarget.Z) - new Vector3(camPos.X, camPos.Y, camPos.Z);
vPickRayOrig = new Vector3(0, 0, -200) - new Vector3(0, 0, 0);
///////////////////////////////

///

Point ptCursor = new Point(0);
ptCursor.X = (int)in_MouseX;
ptCursor.Y = (int)in_MouseY;

// Compute the vector of the pick ray in screen space

Vector3 v;
v.X = ( ( ( 2.0f * ptCursor.X ) / mDevice.PresentationParameters.BackBufferWidth ) - 1 ) / matProj.M11;
v.Y = -( ( ( 2.0f * ptCursor.Y ) / mDevice.PresentationParameters.BackBufferHeight ) - 1 ) / matProj.M22;
v.Z = 1.0f;

// Get the inverse of the composite view and world matrix

Matrix matView, matWorld, m;
matView = mDevice.GetTransform(TransformType.View);
matWorld = mDevice.GetTransform(TransformType.World);

m = matWorld * matView;
m = Matrix.Invert( m );

// Transform the screen space pick ray into 3D space

vPickRayDir.X = v.X*m.M11 + v.Y*m.M21 + v.Z*m.M31;
vPickRayDir.Y = v.X*m.M12 + v.Y*m.M22 + v.Z*m.M32;
vPickRayDir.Z = v.X*m.M13 + v.Y*m.M23 + v.Z*m.M33;
vPickRayOrig.X = m.M41;
vPickRayOrig.Y = m.M42;
vPickRayOrig.Z = m.M43;

// 0 = terrain.Y

return vPickRayOrig + (0 - vPickRayOrig.Y) / vPickRayDir.Y * vPickRayDir;
}



[edited by - leXor on January 16, 2004 12:40:40 PM]

Share this post


Link to post
Share on other sites
Ah...thought as much.

You're setting vPickRayDir and vPickRayOrig but that gets overwritten at the end, so you're not actually using CamTarget - CamPos anywhere.
I took out the world matrix stuff (our code was calculating object space coords) and i added an error check.

public Vector3 PickRay(float in_MouseX, float in_MouseY)
{
Matrix matProj = mDevice.GetTransform(TransformType.Projection);

// Compute the vector of the pick ray in screen space

Vector3 v;
v.X = ( ( ( 2.0f * in_MouseX ) / mDevice.PresentationParameters.BackBufferWidth ) - 1 ) / matProj.M11;
v.Y = -( ( ( 2.0f * in_MouseY ) / mDevice.PresentationParameters.BackBufferHeight ) - 1 ) / matProj.M22;
v.Z = 1.0f;

// Get the inverse of the view matrix

Matrix m= mDevice.GetTransform(TransformType.View);
// Transform the screen space pick ray into 3D space

Vector3 vPickRayDir=new Vector3(v.X*m.M11 + v.Y*m.M21 + v.Z*m.M31,
v.X*m.M12 + v.Y*m.M22 + v.Z*m.M32,v.X*m.M13 + v.Y*m.M23 + v.Z*m.M33);
Vector3 vPickRayOrig=new Vector3(m.M41, m.M42,m.M43);
// 0 = terrain.Y


if(vPickRayDir.Y==0)
return new Vector3(0,1000,0); // error, ray doesn't intersect XZ or lies in XZ plane

//better: throw exception

else
return vPickRayOrig + (0 - vPickRayOrig.Y) / vPickRayDir.Y * vPickRayDir;
}

You had a lot of redundancy in your code:

vPickRayDir = new Vector3(camTarget.X, camTarget.Y, camTarget.Z) - new Vector3(camPos.X, camPos.Y, camPos.Z);

we don't need new objects here, we already have the right ones!

vPickRayDir = camTarget - camPos;


[edited by - Ghwerig on January 16, 2004 1:49:05 PM]

Share this post


Link to post
Share on other sites
The reason why I created new Vector3 was becourse the my camPos and camTarget temporarely was Vector4.

Thanks once again for you help. You have been most helpful!

[edited by - leXor on January 16, 2004 2:09:38 PM]

Share this post


Link to post
Share on other sites