Rotating an object using its vectors

Started by
5 comments, last by sirSolarius 20 years ago
Ok, so I have a camera with four vectors attached to it: up, right, forward and position. I want to be able to use it as a full function camera, but I'm getting weird problems (see bottom). Here's what I have so far: First, my orientation matrix has a general rotate function:

	void rot(float x, float y, float z)
	{
		
		/////////// Do the x rotations//////////////

		if(x!=0.0f)
		{
			Vector3 vTemp=getForward();
			vTemp.rotVect(x, getRight());
			setForward(vTemp);

			setUp(getRight().cross(getForward()));		// Set the up vector

		}
		if(y!=0.0f)
		{
			Vector3 vTemp=getForward();
			vTemp.rotVect(y, getUp());
			setForward(vTemp);
			
			setRight(getForward().cross(getUp()));
		}
		if(z!=0.0f)
		{
			Vector3 vTemp=getUp();
			vTemp.rotVect(z, getForward());
			setUp(vTemp);

			setRight(getForward().cross(getUp()));
		}
	}
Then the vector rotation function is here:

void rotVect(float angle, Vector3 coord)
{
	// Calculate the sine and cosine of the angle once

	float cosTheta = (float)cos(angle);
	float sinTheta = (float)sin(angle);

	// Find the new x position for the new rotated point

	x  = (cosTheta + (1 - cosTheta) * coord.x * coord.x)			* x;
	x += ((1 - cosTheta) * coord.x * coord.y - coord.z * sinTheta)	* y;
	x += ((1 - cosTheta) * coord.x * coord.z + coord.y * sinTheta)	* z;

	// Find the new y position for the new rotated point

	y  = ((1 - cosTheta) * coord.x * coord.y + coord.z * sinTheta)	* x;
	y += (cosTheta + (1 - cosTheta) * coord.y * coord.y)			* y;
	y += ((1 - cosTheta) * coord.y * coord.z - coord.x * sinTheta)	* z;

	// Find the new z position for the new rotated point

	z  = ((1 - cosTheta) * coord.x * coord.z - coord.y * sinTheta)	* x;
	z += ((1 - cosTheta) * coord.y * coord.z + coord.x * sinTheta)	* y;
	z += (cosTheta + (1 - cosTheta) * coord.z * coord.z)			* z;
}
And finally I have a camera function to rotate from mouse movement:

void CCamera::SetViewByMouse()
{
	POINT mousePos;						// This is a window structure that holds an X and Y

	int middleX = 800 >> 1;				// This is a binary shift to get half the width

	int middleY = 600 >> 1;				// This is a binary shift to get half the height

	float angleY = 0.0f;					// This is the direction for looking up or down

	float angleX = 0.0f;				// This will be the value we need to rotate around the Y axis (Left and Right)

	static float currentRotX = 0.0f;
	
	// Get the mouse's current X,Y position

	GetCursorPos(&mousePos);						
	
	// If our cursor is still in the middle, we never moved... so don't update the screen

	if( (mousePos.x == middleX) && (mousePos.y == middleY) ) return;
	
	// Set the mouse position to the middle of our window

	SetCursorPos(middleX, middleY);							

	// Get the direction the mouse moved in, but bring the number down to a reasonable amount

	angleY = (float)( (middleX - mousePos.x) ) / 500.0f;		
	angleX = (float)( (middleY - mousePos.y) ) / 500.0f;
	
	// Here we keep track of the current rotation (for up and down) so that

	// we can restrict the camera from doing a full 360 loop.

	currentRotX -= angleX;

	// If the current rotation (in radians) is greater than 1.0, we want to cap it.

	if(currentRotX > 1.0f)
		currentRotX = 1.0f;
	// Check if the rotation is below -1.0, if so we want to make sure it doesn't continue

	else if(currentRotX < -1.0f)
		currentRotX = -1.0f;
	// Otherwise, we can rotate the view around our position

	else
	{
		orientation.rot(angleX,0, 0);
	}

	// Rotate around the y axis no matter what the currentRotX is

	orientation.rot(0, angleY, 0);
}
Ok, what's happening is that when I rotate, the scene gets squeezed until it becomes a little vertical line and disappears, leaving offly the clear color. If I rotate at all using the mouse, in any direction, it does that. What's going off? [edited by - sirSolarius on March 24, 2004 7:59:07 PM]
Advertisement
quote:Original post by sirSolarius
Ok, so I have a camera with four vectors attached to it: up, right, forward and position. I want to be able to use it as a full function camera, but I''m getting weird problems (see bottom).

Here''s what I have so far:

First, my orientation matrix has a general rotate function:
	void rot(float x, float y, float z)	{				/////////// Do the x rotations//////////////		if(x!=0.0f)		{			Vector3 vTemp=getForward();			vTemp.rotVect(x, getRight());			setForward(vTemp);			setUp(getRight().cross(getForward()));		// Set the up vector		}		if(y!=0.0f)		{			Vector3 vTemp=getForward();			vTemp.rotVect(y, getUp());			setForward(vTemp);						setRight(getForward().cross(getUp()));		}		if(z!=0.0f)		{			Vector3 vTemp=getUp();			vTemp.rotVect(z, getForward());			setUp(vTemp);			setRight(getForward().cross(getUp()));		}	}



After you perform your cross products, you need to make sure to normalize the result vector to unit length.


quote:
Then the vector rotation function is here:

  void rotVect(float angle, Vector3 coord){	// Calculate the sine and cosine of the angle once	float cosTheta = (float)cos(angle);	float sinTheta = (float)sin(angle);	// Find the new x position for the new rotated point	x  = (cosTheta + (1 - cosTheta) * coord.x * coord.x)			* x;	x += ((1 - cosTheta) * coord.x * coord.y - coord.z * sinTheta)	* y;	x += ((1 - cosTheta) * coord.x * coord.z + coord.y * sinTheta)	* z;	// Find the new y position for the new rotated point	y  = ((1 - cosTheta) * coord.x * coord.y + coord.z * sinTheta)	* x;	y += (cosTheta + (1 - cosTheta) * coord.y * coord.y)			* y;	y += ((1 - cosTheta) * coord.y * coord.z - coord.x * sinTheta)	* z;	// Find the new z position for the new rotated point	z  = ((1 - cosTheta) * coord.x * coord.z - coord.y * sinTheta)	* x;	z += ((1 - cosTheta) * coord.y * coord.z + coord.x * sinTheta)	* y;	z += (cosTheta + (1 - cosTheta) * coord.z * coord.z)			* z;}



You should save the initial values of (x,y,z) into temporary variables and use those temporary values in your equations. What is happening is that you are modifying x, then using that modified x to calculate y, then using the modified x and y to calculate z. You want to use the unmodified values (the original point) for all calculations instead.

Hope that helps


Golem
Blender--The Gimp--Python--Lua--SDL
Nethack--Crawl--ADOM--Angband--Dungeondweller
Alright- progress! The scene is definitely rotating and isn''t shrinking or freaking out, but I''m still having some issues.

New orientation code:
	void rot(float x, float y, float z)	{				/////////// Do the x rotations//////////////		if(x!=0.0f)		{			Vector3 vTemp=getForward();			vTemp.rotVect(x, getRight());			setForward(vTemp);						vTemp=getRight().cross(getForward());			vTemp.normalise();			setUp(vTemp);		// Set the up vector					}		if(y!=0.0f)		{			Vector3 vTemp=getForward();			vTemp.rotVect(y, getUp());			setForward(vTemp);									vTemp=getForward().cross(getUp());			vTemp.normalise();			setRight(vTemp);		// Set the right vector		}		if(z!=0.0f)		{			Vector3 vTemp=getUp();			vTemp.rotVect(z, getForward());			setUp(vTemp);			vTemp=getForward().cross(getUp());			vTemp.normalise();			setRight(vTemp);		// Set the right vector		}	}


New vector code:
void rotVect(float angle, Vector3 coord){	Vector3 t=Vector3(x, y, z);	// Calculate the sine and cosine of the angle once	float cosTheta = (float)cos(angle);	float sinTheta = (float)sin(angle);	// Find the new x position for the new rotated point	t.x  = (cosTheta + (1 - cosTheta) * coord.x * coord.x)				* x;	t.x += ((1 - cosTheta) * coord.x * coord.y - coord.z * sinTheta)	* y;	t.x += ((1 - cosTheta) * coord.x * coord.z + coord.y * sinTheta)	* z;	// Find the new y position for the new rotated point	t.y  = ((1 - cosTheta) * coord.x * coord.y + coord.z * sinTheta)	* x;	t.y += (cosTheta + (1 - cosTheta) * coord.y * coord.y)				* y;	t.y += ((1 - cosTheta) * coord.y * coord.z - coord.x * sinTheta)	* z;	// Find the new z position for the new rotated point	t.z  = ((1 - cosTheta) * coord.x * coord.z - coord.y * sinTheta)	* x;	t.z += ((1 - cosTheta) * coord.y * coord.z + coord.x * sinTheta)	* y;	t.z += (cosTheta + (1 - cosTheta) * coord.z * coord.z)				* z;	x=t.x; y=t.y; z=t.z;}


Finally, the camera code is the same. So what''s happening is that as I rotate, my position in the world changes... ie, I travel in a circle like I''m rotating around something, rather than just spinning while stationary. Also, my up vector gets messed up and I end with it pointing along the real world X axis. And when I move my mouse up and down (should be rotating along the X axis) while pointed in a certain direction, I actually rotate by the Z axis... any idea as to what''s causing all of this?

Thanks so much for your help so far!
I posted the exe if you want to see what's going on: here .

[edited by - sirSolarius on March 25, 2004 11:56:43 AM]
Hmmm... well, I don't have immediate access to a Windows machine to run that, unfortunately.

Just a recommendation, though, is instead of continually applying rotation factors to the matrix to track rotation, you should store angles and regenerate the view matrix from scratch each time. When you constantly apply rotations to a vector, mathematical error creeps in and things start to go askew. The vectors start to lose their orthogonality, and start to deviate from unit length, causing all sorts of wierdness to creep in. If the matrix is generated from scratch from raw angles, though, then the math error does not creep in. I can't say that is your problem without seeing more code, though...

Also, double-check your translation code to make sure you are rotating and translating in the correct order. If you translate before you rotate, then the object (camera, or whatever) will rotate around in a circle around the origin, rather than spinning in place then moving out to it's location as is the desired behavior. gluLookAt() generates the rotation matrix based on the orientation vectors, then multiplies it by a translation matrix for the eyepoint:

R=Rot matrix
T=Translate matrix

FinalMatrix = R x T

If you perform the operation in reverse, ie:

FinalMatrix = T x R

then you will get the transformations backward, translating out and then rotating in a circle. Again, I can't be entirely certain this is the problem...

edit: Also, when using Euler angles like this (roll, pitch, yaw, or rotation around the individual x,y and z axes in turn; you include axis-angle code in your system, but use it merely for implementing Euler rotations around the X or Z axis), a problem can crop up called gimbal lock which behaves just as you describe--that is, rotations that should (in your mind) be about one axis instead end up being about another axis. This is a limitation of Euler angle rotations, and consequently the reason people frequently use axis-angle rotations about arbitrary axes (not limited to x, y or z axis) or quaternions for better control of orientation and avoidance of gimbal lock. Just something you might look into.


Golem
Blender--The Gimp--Python--Lua--SDL
Nethack--Crawl--ADOM--Angband--Dungeondweller

[edited by - VertexNormal on March 25, 2004 1:20:52 PM]
I'm going to look at how I construct my matrix (with respect to transformations, etc.), but as far as gimbal lock goes, shouldn't I be avoiding this because I'm rotating an object using ITS x, y and z axis, rather than the world's x, y and z axis?

Ok, the rotate 1st, translate second thing worked perfectly. Now, however, I'm getting a weird problem. I recompiled and posted the new exe over the old one above.

Try rotating along the x axis, then turning along the y, and rotating again. See what happens? I start rotating around what should be the camera's z axis. To me, this means that I'm not calculating the camera's vectors correctly (actually, it looks like I'm not calculating them at all!), and that my X axis for the camera stays at (1, 0, 0) no matter how I'm turning.

If you look at the exe, however, you'll see an X, Y and Z position marked in the upper left. This is the result of a direct call to currentCam->orientation.getRight(), and then it displays the x, y and z components, which look correct to my eye.

So getRight() is clearly giving me the correct vector, but for some reason I'm rotating about the basic world vectors of right = 1, 0,0 up= 0, 1, 0 and forward = 0, 0, 1.

[edited by - sirSolarius on March 25, 2004 3:13:43 PM]
Yeah, on second thought, that''s right. Your rotations are indeed local. Sorry, my bad...

This topic is closed to new replies.

Advertisement