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.