[C++, DirectX] Moving camera around a point

Started by
10 comments, last by MJP 16 years, 3 months ago
-using c++ -using directX I've been trying to make a function that will take direction and move the camera relative to itself (forward being what you're looking at) but I'm not getting the math right. I'm trying to get the angle of the direction of movement on the XZ plane (i don't need up and down) where x+ is right and z+ is towards the screen. Then I can move a certain distance along that line. what I want in bullet form: -forward goes straight towards the point (what it's looking at) -back goes straight away from the point -left and right are perpendicular to the line the camera and the point make (for lack of a better description)
void CalculateCameraPosition(CAMERA &camera, float distance, DWORD direction)
{
	float angle;
//start of problems
	if(camera.lookAt.x - camera.position.x != 0)
		angle = atan((camera.lookAt.z - camera.position.z)/(camera.lookAt.x - camera.position.x));
	else
		angle = atan((camera.lookAt.z - camera.position.z)/0.0000001f);
//end of problems
	switch(direction)
	{
	case MOVE_FORWARD:
		{
			angle += 0.0f;
			break;
		}
	case MOVE_BACKWARD:
		{
			angle += 180.0f;
			break;
		}
	case MOVE_LEFT:
		{
			angle += -90.0f;
			break;
		}
	case MOVE_RIGHT:
		{
			angle += 90.0f;
			break;
		}
	}
	camera.position.x += sin(angle) * distance; //I think this line...
	camera.position.z += cos(angle) * distance; //...and this line are fine.
}



I am really not sure what I can do to calculate the angle the camera is facing away from the Z axis. I want an angle of 0 for the camera if it is at 0,0,0 and looking at 0,0,1. The only information I have about the camera is it's position and the point it's looking at. What I have in there now is just something I was messing with. It didn't work. Please help! <:O [Edited by - justcallmedrago on January 9, 2008 7:01:38 PM]
-----------------------------std::string is the way to go.
Advertisement
Don't worry, this is much simpler than you're making it out to be. You already have the key piece of information, which is the direction the camera is looking. Like you said you're not interested in the Y direction, so what you need is a translation vector that exists only in the X/Z plane. This is easy to calculate, provided you have access to either a view matrix or a world matrix for your camera (either one will do, since they're just inverses of each other). If you have a viewMatrix, the code looks like this:

// World matrix is inverse of the view matrixD3DXMATRIXA16 cameraWorldMatrix;D3DXMatrixInverse ( &cameraWorldMatrix, NULL, &camera.viewMatrix );// Set the translation parts of matrix to zero.  This means it will only rotate,// not translate.cameraWorldMatrix.41 = cameraWorldMatrix.42 = cameraWorldMatrix.43 = 0// Create a translation vector that's in object space for the camera.D3DXVECTOR3 translationVector (0,0,0);switch(direction){	case MOVE_FORWARD:	{		translationVector.z = 1.0f;		break;	}	case MOVE_BACKWARD:	{		translationVector.z = -1.0f;		break;	}	case MOVE_LEFT:	{		translationVector.x = -1.0f;		break;	}	case MOVE_RIGHT:	{		translationVector.x = 1.0f;		break;	}}// Now rotate our translation vector so that aligned with the camera's view// directionD3DXVec3TransformCoord( &translationVector, &translationVector, &cameraWorldMatrix );// Now, we flatten the vector so it's in the XZ plane.translationVector.y = 0;// Normalize the vectorD3DXVec3Normalize( &translationVector, &translationVector );// Multiply so it's magnitude == distancetranslationVector *= distance;// Translate the camera's positioncamera.position += translationVector; 
thanks a lot. This was really frustrating me.



Why do you use that Inverse function? I'm confused about that part.

[Edited by - justcallmedrago on January 10, 2008 6:39:42 AM]
-----------------------------std::string is the way to go.
Sure, let me explain:

Let's take a world matrix for a particular 3D object. It's purpose is generally to take a series of points (vectors) that make up a mesh, and then move them and rotate them so they're at their world positions. This means we take the mesh from where it's originally centered, usually <0,0,0>, and move it off to some other position.

Now let's take a view matrix for a camera. This camera transforms vectors that are already in world space to view-space, which means that the vectors are then relative to the camera's position in orientation. Think of a trivial example: say we have a single point at <0,0,5>, and a camera positioned at <5,0,5> and facing in the positive-z direction (<0,0,1>). The view-space position of the original point would then be <0,0,5> - <5,0,5> == <-5,0,0>. Look carefully at what we're doing here: if we wanted to move the camera from <0,0,0> to it's world position <5,0,5>, we would translate it by a value of <5,0,5>. This translation value would be the camera's world transform, which we would express as a matrix. But when we applied the view matrix, we did the opposite of this transform: we translated the original point by <-5,0,-5>. In matrix math, we can perform the opposite of a transform matrix by applying its inverse, and that's exactly what I did in the above code.

So let's summarize: if a camera is rotated 90 degrees about the y-axis and positioned at <0,10,0>, applying the inverse of its view matrix will do the same to any arbitrary vector. This is very useful for what you're trying to do, which is take a direction vector that's in view-space (relative to the camera's direction), and transform it so it's in world-space. And that's exactly what I did in the code. Based on what key is being pressed, I come up with unit vector that points in the direction of intended movement relative to the camera. Then, I rotate it with the inverse view matrix to determine which direction this is in world-space. Notice I only rotate and not translate: you don't want to translate, since that will give you a non-unit vector. Do prevent translation, I set the translation portion of the inverse view matrix to zero. Then once I have a direction vector in world-space, I "flatten" it so it exists only in the XZ-plane. This is easy, you just have to remove the Y-component and then re-normalize so we once again have a unit vector. Then, the last step is to ensure we move the distance specified, and since we have a unit vector all we need to do is multiply it by your distance parameter and we're all set. Not too bad, eh?
Wow that really really really helped me understand about worldspace and why meshes have to be translated into worldspace. I also didn't know/realize the camera transforms things so they are in it's own space, so a point right in front of it would be somewhere along it's z-axis!

Thanks a million




Ok, now I noticed another thing, but less complicated (I think). Since the camera is strafing, it is moving perfectly along one axis relative to itself as intended. This causes it to move slightly farther away from the central point. how can I correct for this?

-----------------------------std::string is the way to go.
Quote:Original post by justcallmedrago
Wow that really really really helped me understand about worldspace and why meshes have to be translated into worldspace. I also didn't know/realize the camera transforms things so they are in it's own space, so a point right in front of it would be somewhere along it's z-axis!

Thanks a million



I'm glad I helped! Understanding the different coordinate spaces and how the relate to each other is definitely one of the trickiest parts of the math used in 3D graphics. I still sometimes have to stop, think, and draw out a simple diagram when I'm working out some complex shader code that uses different coordinate spaces.


Quote:Original post by justcallmedrago

Ok, now I noticed another thing, but less complicated (I think). Since the camera is strafing, it is moving perfectly along one axis relative to itself as intended. This causes it to move slightly farther away from the central point. how can I correct for this?


I'm not sure what you mean by this...are you saying that the camera moves further than the "distance" parameter when strafing left and right?

I think he means that he moves faster when he's both strafing and moving forward/backward, due to the velocities that accumulate. You could make a special case for this or just lower one of the velocities.

Slightly offtopic:
MJP, I understand that the view matrix is the inverse of the world matrix. Does this count for rotations also? I have a thread about arcball rotation in the Maths&Physics section and the problem I'm having there is that I want to rotate the camera instead of the world. Therefore, I apply the inverse rotation matrix to the position of the camera, but I get very fast and twitchy movement. What could be wrong?

Jeroen
no i mean that the new position will not be the same distance from the old look at point:
My bad visual representation:
Old camera postion........................................New Camera Position
|
|
|
|
|
|
|
|
|(this line is the old distance from the look-at point
|
|
|
|
|
|
|
|
Look at position


The new camera position is farther from the look-at point than before because the look-at position doesn't move.

I don't need this solved because I made my own using trig :P but I can apply this to strafing an object according to the camera.
-----------------------------std::string is the way to go.
Quote:Original post by godmodder
I think he means that he moves faster when he's both strafing and moving forward/backward, due to the velocities that accumulate. You could make a special case for this or just lower one of the velocities.



I thought that too at first, but it doesn't make sense since his switch statement only allows for movement in one direction at time. And even if it did, it wouldn't matter since I normalize the translation vector before multiplying by the magnitude, which means even if you're moving at a diagonal it should still translate the same amount. At least, assuming I didn't screw something up. [smile]

Quote:Original post by godmodder
Slightly offtopic:
MJP, I understand that the view matrix is the inverse of the world matrix. Does this count for rotations also? I have a thread about arcball rotation in the Maths&Physics section and the problem I'm having there is that I want to rotate the camera instead of the world. Therefore, I apply the inverse rotation matrix to the position of the camera, but I get very fast and twitchy movement. What could be wrong?

Jeroen


Yes it applies to rotations also. If you create a matrix that rotates around the Y-axis by 90 degrees, the inverse of that matrix will rotate around the Y-axis by -90 degrees. For your arcball camera, you should be able to create a translation matrix that moves the camera to its position and then concatenate it with one or more rotation matrices that will rotate the camera as if it were on the surface of a sphere. Creating the matrices shouldn't be too hard, the only important part is multiplying them in the right order. And of course, the right order is opposite for D3D and OpenGL since the former uses row-major matrices and the latter uses row-major. I would probably handle the camera like this:

-Keep track of a position for the camera. The z-value of this position be changed if the camera zooms in or out.
-Keep track of two panning angles for the camera, which correspond to rotations about the camera's local X and Y axis
-Keep track of two rotation angles for the camera, which correspond to rotations about the map's X and Y axis. This is the arcball rotation.

Then every frame...
-From the panning angles, create two rotation matrices. One for the rotation about the X-axis, one about the Y axis. We'll call these matLocalRotX and matLocalRotY.
-From the position, create a translation matrix. We'll call this matTranslation.
-From the rotation angles, create two rotation matrices. We'll call these matArcballRotX and matArcballRotY.

Now from these matrices, we create a world matrix for the camera. Like I said order is important. For D3D, the order is like this:

matWorld = matLocalRotX * matLocalRotY * matTranslation * matArcballRotX * matArcballRotY;


For OpenGL, it's the opposite:

matWorld = matArcballRotY * matArcballRotX * matTranslation * matLocalRotY * matLocalRotX;


Either way you're doing the same thing: panning the camera first, zooming it in or out, then rotating it to its final position. The view matrix for this camera is just the inverse of the world matrix, and if you need the world-space position of the camera you can just transform the vector <0,0,0> by the world matrix.
Quote:Original post by justcallmedrago
no i mean that the new position will not be the same distance from the old look at point:


Ohh I See what you mean. There's no need for trig however...since your camera movement doesn't affect it's direction all you need to do is add the translation you calculated to your old lookAt point. Here I'll make a bad diagram as well, where the final translation would be <+10,0,0>:

Old camera position<0,0,0>-------<+10,0,0>-------New Camera Position<10,0,0>|||||||||||Look at point<0,0,10>------------<+10,0,0>-------New look at point<10,0,10>

This topic is closed to new replies.

Advertisement