PDA

View Full Version : Camera & Quaternions

beuleuppeup
04-15-2010, 12:59 PM
Hello,

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

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

The camera moves along its local axes by using the keyboard. The camera rotates on itself (changing orientation, lookAt) by dragging the mouse.

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];

}

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,&amp;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.