I just did an orbital camera recently from going through one of the gameDev tutorials! so I will have a go at going over it.
Here's the mouse Input function, from the looks of it you already have your own way to get change in mouse movmeent though.
mouseMove(HWND hWnd, Camera *camera){ static int mousex, mousey; POINT mouse; GetCursorPos(&mouse); // Get the 2D mouse cursor (x,y) position ScreenToClient(hWnd, &mouse); // Mouse coords within the window if(m_keys[VK_LBUTTON]) { tVector3 MouseDirection; MouseDirection.x = ((float)mousex - (float)mouse.x)/100.0f; MouseDirection.y = ((float)mousey - (float)mouse.y)/100.0f; camera->update(&MouseDirection); } mousex = mouse.x; mousey = mouse.y;}
All that's been done here is getting the change Mouses position in the x and y directions and I have then passed them into camera->update were the magic will happen.
There are a few maths functions you'll need for this, and they are: Vector crossProduct, create unit Length vector, quaternion conjugate, convert vector to quaternion and a quaternion multiply, I see you have some there already.
For the camera.update function
void Camera::init(){ m_lookat = tVector3(0.0f, 0.0f, 0.0f); m_position = tVector3(-100.0f,100.0f,-100.0f); m_up = tVector3(0.0f,1.0f,0.0f);}void Camera::update(tVector3 *MouseDir){ // axis to rotate around will be the normal to the UP vector and // vector between the camera position and lookat. tVector3 UP(0.0f,1.0f,0.0f);// World Space Up Vector tVector3 v = m_lookat - m_position; tVector3 axis = Math::crossProduct(&v, &m_up); // Turn it into a unit vector axis = Math::unitVector(&axis); rotateCamera(MouseDir->y, &axis); rotateCamera(MouseDir->x, &UP);}
Here I'm creating the axis that you will want to rotate about.
The rotation about the UP vector is fairly straight forward.
The 'x-axis' for the other rotation is given by the cross product of the up vector and the vector between the camera's lookat and current position. This is a local x-axis to the camera, not the world x-axis.
Here's a wee diagram to illustrate this.
What we want to do now is rotate the view vector(v = m_lookat - m_position) by an angle(MouseDir.x/y) about an axis(UP and axis). So now we have everything needed to rotate the camera so lets look at the rotateCamera function.
A quaternion to represent a rotation is given by
R = (w,v) were w = cos(theta/2) //scalar component v = u sin(theta)/2 // u is a unit Vector
In this case, u is 'axis'/'UP' and theta is the MouseDir.x/y
Rotating a point in 3d space using this quaternion is done by:
P(rotated) = R P R' // R' is the conjugate of R
In this case P refers to our view vector (m_lookat - m_position)
(note this will only work is q if a unit quaternion which it will be as long as your axis is a unit vector, else you would need to use the inverse or R instead of the conjugate.)
So rotating the vector now boils down to 2 quaternion multiplications.
void Camera::rotateCamera(float angle, tVector3 *axis){ tVector3 view = m_lookat - m_position; quaternion R, result; R.x = axis->x * sin(angle/2.0f); R.y = axis->y * sin(angle/2.0f); R.z = axis->z * sin(angle/2.0f); R.w = cos(angle/2.0f); quaternion conjR = Math::conjugate(&R); quaternion v = Math::vecToQuat(&view); // v is the point we wish to rotate //Result = R * V * R' quaternion VmultConjR = Math::multiply(&v, &conjR); // V * R' result = Math::multiply(&R, &VmultConjR); // R multipled by the above // Quats are 'associative' m_position.x = m_lookat.x + result.x; m_position.y = m_lookat.y + result.y; m_position.z = m_lookat.z + result.z;}
You can do the quaternion multiplications either (R*V)*R' or R*(V*R') as long as the order is the same.
The rotated view vector is now called result. To then convert this into the new position of the camera in world space it will be the camera's lookat + result.
Now the camera class will have the camera position and lookat you can extract and slap into your gluLookat or DirectX equivilent.
Theres 1 extra thing missing here though. The camera can't go past the vertical.
To do this you will need to change the local up vector (m_up) this will be done by applying the same rotation to the m_up as you did with view. This will allow the camera to go around in a full sphere..ideal if yer idea is like tetrisSphere!