www.pudn.com > Fog_D3D.zip > camera.cpp


#include "camera.h" 
 
// Default Constructor 
CCamera::CCamera() 
{ 
	reset(); 
} 
 
// Sets right, up and forward to world X, Y, Z axis 
// Sets eye to five units back on -Z 
void CCamera::reset() 
{ 
	right.set(1.0f, 0.0f, 0.0f); // +X axis 
	up.set(0.0f, 1.0f, 0.0f); // +Y axis 
	forward.set(0.0f, 0.0f, 1.0f); // +Z axis 
	 
	// Set eye back 5 units on -Z 
	eye.set(0.0f, 0.0f, -5.0f); 
} 
 
// Pitches the camera up/down 
void CCamera::pitch(float angle) 
{ 
	/* 
		Now when we pitch the camera up/down we need to make sure we keep all 
		the camera axes perpendicular to each other, otherwise we loose the 
		fact that they represent the camera's coordinate system. 
		 
		Thus when we rotate the forward vector, we also have to recalculate 
		the up vector because it will rotate too.  We could just rotate it 
		around the same axis, but it's faster to recompute it using  
		the cross product, so that's what we do. 
		 
		**NOTE** The right vector doesn't change when you pitch up/down.  Don't believe me? 
				 Well draw it out on paper and see for yourself :)	 
	*/   
 
	// Calculate new forward 
	forward = rotateAroundAxis(forward, right, angle); 
	 
	// Calculate new camera up vector 
	up = forward.crossProduct(right); 
} 
 
// Using your standard Y-axis rotation matrix, we'll rotate around the Y-axis 
// Rotates camera around the world Y-axis 
// ca == cosf(angle)	sa == sinf(angle) 
// [ ca 0 -sa ] 
// [ 0  1   0 ] 
// [ sa 0  ca ] 
void CCamera::rotateY(float angle) 
{ 
	float xxx, zzz; 
	float sinAng, cosAng; 
	 
	// Get sin()/cos() of angle 
	sinAng = sinf(angle); 
	cosAng = cosf(angle); 
	 
	// Save off forward components for computation 
	xxx = forward.x; 
	zzz = forward.z; 
	 
	// Rotate forward vector 
	forward.x = xxx * cosAng + zzz * sinAng; 
	forward.z = xxx * -sinAng + zzz * cosAng; 
	 
	// Save off up components for computation 
	xxx = up.x; 
	zzz = up.z; 
	 
	// Rotate up vector 
	up.x = xxx * cosAng + zzz * sinAng; 
	up.z = xxx * -sinAng + zzz * cosAng; 
	 
	// Save off right components for computation 
	xxx = right.x; 
	zzz = right.z; 
	 
	// Rotate right vector 
	right.x = xxx * cosAng + zzz * sinAng; 
	right.z = xxx * -sinAng + zzz * cosAng; 
} 
 
// Moves the camera in the specified direction 
void CCamera::move(ECamMoveDir dir) 
{ 
	switch(dir) 
	{ 
		case eForward: // Move along the camera's forward vector 
			eye += forward; 
				break; 
		 
		case eBack: // Move along the camera's negative forward vector 
			eye -= forward; 
				break; 
				 
		case eLeft: // Move along the camera's negative right vector 
			eye -= right; 
				break; 
				 
		case eRight: // Move along the camera's right vector 
			eye += right; 
				break; 
	} 
} 
 
// Private Methods //////////////////////////////////// 
////////////////////////////////////////////////////// 
///////////////////////////////////////////////////// 
 
// Here is where most of the magic happens.  This function takes an 
// arbitrary  axis and rotates the view vector (the forward axis) of the  
// camera around this axis by "angle" radians.  So how do we rotate around 
// an arbitrary axis?  Well lets first look at a couple of matrices that will 
// rotate us around the world X, Y, and Z axis respectively.  We use 't' as  
// an angle theta to rotate around the axis. 
 
////////////////////////////////////////////////////////////////////////// 
//		X-Axis						Y-Axis					Z-Axis			 
// [1    0	    0   ]		 [cos(t) 0 -sin(t)]		 [ cos(t) sin(t)  0] 
// [0  cos(t) sin(t)]		 [  0	 1    0	  ]		 [-sin(t) cos(t)  0] 
// [0 -sin(t) cos(t)]		 [sin(t) 0  cos(t)]		 [   0	    0	  1] 
////////////////////////////////////////////////////////////////////////// 
 
// Using the above matrices for rotation around a "known" axis, and a little 
// bit (well maybe a lot) of math, we can come up with the matrix that will 
// allow us to rotate around ANY axis.  Sparing the gritty math details, which 
// feel free to look up if you're in to S&M :), you get the following: 
 
// **NOTE** 
// x = X component of arbitrary normalized axis 
// y = Y component of arbitrary normalized axis 
// z = Z component of arbitrary normalized axis 
// t = angle theta to rotate by 
// Oh and prepare to scroll over, this puppy is long :) 
 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
// [(x * x * (1 - cos(t)) + cos(t))			(x * y * (1 - cos(t)) + z * sin(t))		(x * z * (1 - cos(t)) - y * sin(t))] 
// [(x * y * (1 - cos(t)) - z * sin(t))		(y * y * (1 - cos(t)) + cos(t))			(y * z * (1 - cos(t)) + x * sin(t))] 
// [(x * z * (1 - cos(t)) + y * sin(t))		(y * z * (1 - cos(t)) - x * sin(t))		(z * z * (1 - cos(t)) + cos(t))	   ] 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
 
// With the above matrix and a tad more linear algebra we can now implement 
// this function which takes "axis" as the axis to rotate the camera around 
// by "angle" amount in radians 
 
// Rotates around an arbitary axis 
CVector CCamera::rotateAroundAxis(const CVector &vec, const CVector &axis, float angle) 
{ 
	float aX = axis.x; // Axis X 
	float aY = axis.y; // Axis Y 
	float aZ = axis.z; // Axis Z 
	 
	// Compute the sin and cos of the angle  
	float sinAng = sinf(angle); 
	float cosAng = cosf(angle); 
 
	// Calculate X component 
	float xxx = (aX * aX * (1.0f - cosAng) + cosAng) * vec.x + 
			    (aX * aY * (1.0f - cosAng) + aZ * sinAng) * vec.y + 
			    (aX * aZ * (1.0f - cosAng) - aY * sinAng) * vec.z; 
	 
	// Calculate Y component	    
	float yyy = (aX * aY * (1.0f - cosAng) - aZ * sinAng) * vec.x + 
			    (aY * aY * (1.0f - cosAng) + cosAng) * vec.y + 
			    (aY * aZ * (1.0f - cosAng) + aX * sinAng) * vec.z; 
			    
	// Calculate Z component 
	float zzz = (aX * aZ * (1.0f - cosAng) + aY * sinAng) * vec.x + 
			    (aY * aZ * (1.0f - cosAng) - aX * sinAng) * vec.y + 
			    (aZ * aZ * (1.0f - cosAng) + cosAng) * vec.z; 
			     
	return CVector(xxx, yyy, zzz); // Return result 
} 
 
// Externed camera 
CCamera theCamera; 
CCamera *gCamera = &theCamera;