# Camera & Quaternions

Hello,

I’m currently trying to develop a camera class using Quaternions.

This is how I’d like my camera to behave:

[ul][li] The camera moves along its local axes by using the keyboard.[*] The camera rotates on itself (changing orientation, lookAt) by dragging the mouse.[/ul][/li]
Basically, the first part works but the second one is quite messy: when I drag the mouse, my scene is rotating (not the camera…) chaotically ^^.

Here’s a sample of my code:

``````
void Camera::rotate( float32 angle, float32 axisX, float32 axisY, float32 axisZ )
{
Quaternion q;
Vec3 v (axisX,axisY,axisZ);

q.FromAxis(v,angle);
q.normalise();

m_quat *= q ;
}

void Camera::buildTransformationMatrix()
{
m_quat.buildRotationMatrix();

for(int i=0;i<12;i++)
{
m_TransformationMatrix[i]= m_quat.m_RotationMatrix[i];
}

m_TransformationMatrix[12]= m_Position.m_x;
m_TransformationMatrix[13]= m_Position.m_y;
m_TransformationMatrix[14]= m_Position.m_z;
m_TransformationMatrix[15]= 1;
}

void Camera::glPut()
{
buildTransformationMatrix();

glMatrixMode(GL_MODELVIEW);

float32 mat [16];
for(int i=0;i<16;i++) mat[i]=m_TransformationMatrix[i];

glLoadMatrixf(mat);
}

void mapToSphere(const int x, const int y, Vec3* NewVec)
{
Vec3 TempPt;
float32 length;

//Copy paramter into temp point
TempPt = Vec3(x,y,0.f);

//Adjust point coords and scale down to range of [-1 ... 1]
TempPt.m_x  =        (TempPt.m_x * 2 / WindowWidth)  - 1.0f;
TempPt.m_y  = 1.0f - (TempPt.m_y * 2 / WindowHeight);

//Compute the square of the length of the vector to the point from the center
length      = (TempPt.m_x * TempPt.m_x) + (TempPt.m_y * TempPt.m_y);

//If the point is mapped outside of the sphere... (length > radius squared)
if (length > 1.0f)
{
//Compute a normalizing factor (radius / sqrt(length))
float32 norm = 1.0f / sqrt(length);

//Return the "normalized" vector, a point on the sphere
NewVec->m_x = TempPt.m_x * norm;
NewVec->m_y = TempPt.m_y * norm;
NewVec->m_z = 0.0f;
}
else    //Else it's on the inside
{
//Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
NewVec->m_x = TempPt.m_x;
NewVec->m_y = TempPt.m_y;
NewVec->m_z = sqrt(1.0f - length);
}
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
PostQuitMessage(0);	break;

case WM_PAINT:
drawScene();
SwapBuffers(hDC);
break;

case WM_SIZE:
resize( LOWORD(lParam), HIWORD(lParam) ); break;

case WM_DESTROY:
return 0;

case WM_KEYDOWN:
{
// [...] Translations
}
break;

case WM_LBUTTONDOWN:
lbtn_clicked = true ;
break;

case WM_LBUTTONUP:
lbtn_clicked = false ;
break;

case WM_MOUSEMOVE:
xMouseRel = LOWORD(lParam) - xMousePos;
yMouseRel = HIWORD(lParam) - yMousePos;
xMousePos = LOWORD(lParam);
yMousePos = HIWORD(lParam);

if(lbtn_clicked)
{
mapToSphere(xMousePos,yMousePos,&stVec);
stVec.normalise();

camera.rotate(atan(stVec.m_x/stVec.m_y), stVec.m_x, stVec.m_y, 0.f);
camera.glPut();

}
break;

default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

return 0;
}

``````

I tried different stuff I found on several websites (Nehe,gpwiki,…), but I can’t make it work correctly…
I’ll take any piece of advice I can get. I can, of course, post more extracts from my code if needed.

I doubt it’ll help much in this case, but I’m coding with Visual Studio 2008 Express, on a virtual Windows Xp, on a macbook 13"3.