Advertisement

spaceship camera (like Descent..)

Started by October 21, 2004 06:10 PM
11 comments, last by rodzilla 20 years, 1 month ago
i'm trying to write a small game like Xwing vs Tie Fighter and i've got some problems with the camera: basically when i try to rotate up or down i need to CONTINUE the rotation (not to stop like when i look up/down in a fps)... this way i could complete a circle if i wish. in my old fps engine i used this function to rotate the camera with the mouse:

void CCamera::SetViewByMouse()
{
	POINT mousePos;							// This is a window structure that holds an X and Y
	int middleX = g_Width  >> 1;					// This is a binary shift to get half the width
	int middleY = g_Height >> 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 angleZ = 0.0f;							// This will be the value we need to rotate around the Y axis (Left and Right)
	static float currentRotX = 0.0f;
	
	GetCursorPos(&mousePos);

	if( (mousePos.x == middleX) && (mousePos.y == middleY) ) return;

	SetCursorPos(middleX, middleY);							
	angleY = (float)( (middleX - mousePos.x) ) / 500.0f;		
	angleZ = (float)( (middleY - mousePos.y) ) / 500.0f;		
	currentRotX -= angleZ;  

	if(currentRotX > 2)
		currentRotX = 2;
	else if(currentRotX < -1.0f)
		currentRotX = -1.0f;

	else{
		CVector3 vAxis = Cross(m_vView - m_vPosition, m_vUpVector);
		vAxis.Normalize();

		RotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);
		RotateView(angleY, 0, 1, 0);
	}
}

what should i modify? Does someone know a tutorial or a link?
There is a very simple way to do this. I had it on my old Tie Fighter game, lol. All u need to do is comment this line:

SetCursorPos(middleX, middleY);

This will stop the mouse being set to middle. And the distance will keep being added the further away u are from middle. Good Luck
------------ "Here lies a toppled God,His fall was not a small one,We but built his pedastle,A narrow, and a tall one" Frank Herbert (Dune:Messiah)
Advertisement
Doesn't work. I don't think this is what i was searching for..
What happens instead then.
------------ "Here lies a toppled God,His fall was not a small one,We but built his pedastle,A narrow, and a tall one" Frank Herbert (Dune:Messiah)
basically nothing changes, but the rotation speed is near light speed :P
Basically, I can see 2 problems in your approach :
- you calculate the angles using the mouse movement only. You should "add" the mouse movement to previous values of the angles ;
- you might want to use a quaternion to store the orientation. You will avoid gimbal lock problems.

Tell me if you want me to post some code. I have a class that handles the position and orientation of objects/cameras that is pretty easy to use.
SaM3d!, a cross-platform API for 3d based on SDL and OpenGL.The trouble is that things never get better, they just stay the same, only more so. -- (Terry Pratchett, Eric)
Advertisement
What I do in those cases is store the orientation of the ship as a 4x4 matrix (a quaternion works too).

From this matrix, I can extract the up/side/forward vectors through matrix multiplication so I can move the ship the right way.

To rotate, I simply generate a new rotation matrix (around the X Y or Z axis) and multiply the previous matrix by the new one: this changes the orientation as by a real rotation.

The "view" matrix is the inverse of the orientation matrix multiplied by the translation matrix (which you get from the position of the ship).
@rodzilla: it would be very nice if you post your camera class :)

anyway, i've changed my approach: i don't need anymore to rotate the camera with the mouse, i have to use only the keyboard. So now for example, if i keep pressed the UP key, the camera view changes doing a complete circle if necessary.

I hope i've been clear...
Here's the class I use to handle camera/objects movement.

First the math-related stuff ; you probably have your own classes so I won't put mine in here. All you need is a Vector3 and a Quaternion classes. You should define glTranslate and inv_glTranslate for the Vector3 and glRotate and inv_glRotate for the Quaternion.
glTranslate is straightforward, glRotate is:

voidQuaternion::glRotate() const {	float scale_2 = x*x+y*y+z*z;	if (scale_2 != 0.0) {		float angle = acos(w);		float inv_scale = inv_sqrt(scale_2);		glRotatef(114.59155902616464175358*angle, x*inv_scale, y*inv_scale, z*inv_scale);	}}


Here's the PO (position-orientation) class:

class PO {protected:	//!	Position.	Vector3		m_position;	//!	Orientation.	Quaternion	m_orientation;	//!	A vector facing forward.	Vector3		m_forward;	//!	A vector facing up.	Vector3		m_up;	//!	A vector facing right.	Vector3		m_right;	void update_vectors();public:	//!	Default constructor.	PO();	//!	Get the position.	/*!	\return the position.	*/	const Vector3& get_position() const { return m_position; }	//!	Set the position.	/*!	\param p the new position.	*/	void set_position(const Vector3& p);	//!	Get the orientation.	/*!	\return the orientation.	*/	const Quaternion& get_orientation() const { return m_orientation; }	//!	Set the orientation.	/*!	\param p the new orientation.	*/	void set_orientation(const Quaternion& q);	//!	Move the PO.	/*!	\param v the translation vector in world coordinates.	*/	void translate(const Vector3& v);	//!	Rotate the PO.	/*!	\param q the rotation quaternion in world coordinates.	*/	void rotate(const Quaternion& q);	//!	Return the PO's forward vector.	/*!	\return the PO's forward vector in world coordinates.	*/	const Vector3& forward() const { return m_forward; }	//!	Return the PO's up vector.	/*!	\return the PO's up vector in world coordinates.	*/	const Vector3& up() const { return m_up; }	//!	Return the PO's right vector.	/*!	\return the PO's right vector in world coordinates.	*/	const Vector3& right() const { return m_right; }};voidPO::update_vectors() {	m_right.x = 1.0f - 2.0f * ( m_orientation.y * m_orientation.y + m_orientation.z * m_orientation.z );  	m_up.x = 2.0f * ( m_orientation.x * m_orientation.y - m_orientation.w * m_orientation.z );  	m_forward.x = -2.0f * ( m_orientation.x * m_orientation.z + m_orientation.w * m_orientation.y );  	m_right.y = 2.0f * ( m_orientation.x * m_orientation.y + m_orientation.w * m_orientation.z );  	m_up.y = 1.0f - 2.0f * ( m_orientation.x * m_orientation.x + m_orientation.z * m_orientation.z );  	m_forward.y = -2.0f * ( m_orientation.y * m_orientation.z - m_orientation.w * m_orientation.x );  	m_right.z = 2.0f * ( m_orientation.x * m_orientation.z - m_orientation.w * m_orientation.y );  	m_up.z = 2.0f * ( m_orientation.y * m_orientation.z + m_orientation.w * m_orientation.x );  	m_forward.z = 2.0f * ( m_orientation.x * m_orientation.x + m_orientation.y * m_orientation.y ) - 1.0f;  }// The default construtor initializes the forward, up and right vectors.PO::PO() : m_forward(0, 0, -1),       m_up(0, 1, 0),       m_right(1, 0, 0) {}// Moving the camera means adding a given vector to its position.voidPO::translate(const Vector3& v) {	m_position += v;}// Rotate the camera :voidPO::rotate(const Quaternion& q) {	// apply the rotation to the orientation.	m_orientation *= q;	update_vectors();}// Set the camera's position.voidPO::set_position(const Vector3& p) {	m_position = p;}// Set the camera's orientation.voidPO::set_orientation(const Quaternion& q) {	m_orientation = q;	update_vectors();}


Here's how to use the PO:

// If the PO is used for a camera you can do the following// before drawing your scene :glMatrixMode(GL_MODELVIEW);glLoadIdentity();			// Set it to identity.po.get_orientation().inv_glRotate();	// Apply the inverted rotation po.get_position().inv_glTranslate();	// Apply the inverted translation// If the PO is used for an object you can do the// following before drawing it :po.get_orientation().glRotate();	// Apply the rotation po.get_position().glTranslate();	// Apply the translation// If you want to translate the camera/object, just use// the translate() method and forward, right, up vectors.// Here's how I handle keyboard-controlled time-based movement:float forward_move = (key_state(SDLK_e)-key_state(SDLK_x));float right_move = (key_state(SDLK_d)-key_state(SDLK_s));float up_move = (key_state(SDLK_r)-key_state(SDLK_c));Vector3 tmp =   forward_move*m_camera.po.forward()	      + right_move*m_camera.po.right()	      + up_move*m_camera.po.up();m_camera.po.translate(dt*50.0*tmp);// Rotating is nearly as easy :boolTutorial::handle_mouse_motion(const int x, const int y) {	if (mouse_button_state(SDL_BUTTON_RIGHT)) {		// If right mouse button is pressed the mouse		if (x != 0) {					// rotates the camera around its forward vector.			Vector3 v(0, 0, -1);			// This is the forward vector (in camera coordinates).			Quaternion q(v, x*0.001);		// Create a quaternion that holds a rotation								// around this vector.			m_camera[m_current_camera].po.rotate(q);// Rotate the camera.		}	} else {						// If right mouse button is not pressed the mouse		if (x != 0) {					// rotates the camera around its up and right vectors.			Vector3 v(0, 1, 0);			Quaternion q(v, -x*0.001);			m_camera[m_current_camera].po.rotate(q);		}		if (y != 0) {			Vector3 v(1, 0, 0);			Quaternion q(v, -y*0.001);			m_camera[m_current_camera].po.rotate(q);		}	}	return true;}


Sure this class could be made easier-to-use (add rotate_x, rotate_y and rotate_z functions for example).

Any feedback welcome !
SaM3d!, a cross-platform API for 3d based on SDL and OpenGL.The trouble is that things never get better, they just stay the same, only more so. -- (Terry Pratchett, Eric)
thank you!

This topic is closed to new replies.

Advertisement