Archived

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

Z-axis always forward?

Recommended Posts

lexor    122
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 on other sites
iron_monkey    122
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 on other sites
lexor    122
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 on other sites
Cypher19    768
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 on other sites
lexor    122
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 on other sites
Cypher19    768
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 on other sites
Ghwerig    122
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 on other sites
lexor    122
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 on other sites
lexor    122
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 on other sites
Ghwerig    122
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 on other sites
lexor    122
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 on other sites
Ghwerig    122
Maybe you could post the code you are using now so i can see what your doing

Share on other sites
lexor    122
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 on other sites
Ghwerig    122
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;}

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]