여기서 카메라 Orbit 이란 3DS MAX 의 카메라 Oribit 을 말한다. 보통 TrackBall
이라는 용어도 많이 쓰인다. 카메라 회전을 위해 마우스의 드래그시에 뷰포트에
보이지 않는 구가 중앙에 있는 것으로 생각하고 그 구를 손으로 돌리듯이 움직이면
카메라 뷰포트가 회전하는 것을 구현한다. 주의할 것은
- 마우스를 드래그시에 마우스 처음 위치에서 상대적인 회전을 해야 한다는 것
(그렇게 하지 않으면 마우스를 막 돌리다보면 처음 마우스 위치에 엉뚱한
회전이 적용된다)
- 회전시켜 반바퀴 돌려보면 회전이 반대로 적용되는 경우가 있는데, 이를 위해
서는 역행렬을 구해 현재 마우스 위치벡터를 회전이 적용되기 전의 벡터로
변형시켜야 한다.
void CameraOrbiting ( float src[2], float dest[2] )
{
/*
src[0] = [드래그시작시 마우스 x 위치 -1.0 ~ 1.0];
src[1] = [드래그시작시 마우스 y 위치 -1.0 ~ 1.0];
dest[0] = [드래그중 마우스 y 위치 -1.0 ~ 1.0];
dest[1] = [드래그중 마우스 y 위치 -1.0 ~ 1.0];
*/
float p1[3], p2[3];
float tm[16], inverse_tm[16], m[16];
// 현재 TM 을 얻는다.
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)tm);
// 역행렬을 구한다. (회전만을 포함하기 때문에 Trnaspose 만을 해도된다)
matrix_transpose(tm, inverse_tm); // (만들어야 함!)
p1[0] = src[0];
p1[1] = src[1];
// 길이가 1인 벡터로 가정하고 z 값을 구한다.
// sqrt(x*x + y*y + z*z) = 1
if ((p1[0]*p1[0] + p1[1]*p1[1]) > 1) { /* 원을 벗어난 마우스 위치에 대해서 */
p1[2] = 0.0F; // z 값을 0으로 한다.
}
else {
p1[2] = 1 - p1[0]*p1[0] - p1[1]*p1[1];
}
p2[0] = dest[0];
p2[1] = dest[1];
if ((p2[0]*p2[0] + p2[1]*p2[1]) > 1) {
p2[2] = 0.0F;
}
else {
p2[2] = 1 - p2[0]*p2[0] - p2[1]*p2[1];
}
// 벡터를 노말라이즈한다.
vector_normalize(p1); // (만들어야 함!)
vector_normalize(p2);
vector_mult_matrix(p1, inverse_tm); // (만들어야 함!)
vector_mult_matrix(p2, inverse_tm);
// p2 에서 p1 으로 회전하는 커터니온을 구한다. (만들어야 함!)
quat_set_from_ax(p2, p1, &orbit->quat); /* important order of p1, p2 */
// 쿼터니온을 매트릭스로 바꾼다. (만들어야 함!)
quat_to_mat(&orbit->quat, m);
// 현재 회전매트릭스를 적용한다.
glMultMatrixf((const GLfloat *)m);
}
[REF] "GRAPHICS GEMS", ANDREW S. GLASSNER, VIRTUAL TRACKBALL p462-463
Posted by chungki


