카메라 클래스 - 쿼터니온

반응형


이전의 오일러랑 같은역활을 하긴 하지만
오일러의 단점을 보완하는 쿼터니온이 상당히 중요하다.
오일러의 단점으로 보면
- 각 축에 대한 회전의 적용순서가 다양하여 순서가 다르면 결과가 달라져 혼란을 야기한다.
- 회전자유도가 3이지만 첫번째 회전축과 세번째 회전축이 거의 일치될 때 회전 자유도가
  하나 감소하는 짐벌락 현상이 발생한다.
- 회전을 오일러 각도로 표시하면 각 회전에 대한 오일러 각도가 유일하지 않다.
 - 두 오일러각도의 보간이 유일하지 않다.(보간경로의 문제)

이러한 단점을 보완하기 위해 쿼터니온을 사용한다.
사원수는 3차원에 적용하여 공간에서의 방향을 표현한다.

사원수의 장점
- 한 사원수는 하나의 4차원 벡터이고 3차원 공간에서의 한 방향을 표시
- 사원수는 단위벡터
- 사원수를 행렬로 또는 행렬을 사원수로 쉽게 바꿀 수 있다.
- 두 사원수를 곱하는 것이 행렬을 곱하는 것보다 더 빠르다
- 두 임의의 방향에 대한 선형보간 또는 구형선형보간이 쉽게 가능하다.

선형보간
- 두 벡터들을 선형식으로 보간하여 현재 위치에서 벡터들을 계산.
- 두 점 사이의 최단 직선을 따라 동일한 속도로 이동하는 형태
- 두 점이 사원수라면 단위초구상에 존재, 단위 초구상을 따라 움직이는 두사원수의 최단경로는
   단위 초구상에서의 두점을 잇는 원호가 된다.

구형선형보간
- 원호상에서의 등간격 보간.
- 초구상에는 동일한 회전에 해당하는 사원수가 2개씩 있어 보간시 경로가 가까운 쪽으로의 slerp를 선택하면 된다.
- 짧은경로를 선택하는 방법은 두 벡터를 내적하여 양수면 90도 미만이므로 짧은경로인 것을 알 수 있다.

선형보간과 구형선형보간의 차이
- 한 사원수에서 다른 사원수로 부드럽게 바꾸기 위해 t를 0에서 1로 바꾸면서 보간한다.
  선형보간은 두 사원수를 잇는 직선을 일정 간격으로 진행하면서 사원수들을 구하게 된다.
  구형선형보간은 두 사원수를 잇는 원호를 일정간격으로 진행하면서 사원수들을 구한다.
  그래서 선형보간일 경우 직선상에서는 일정간격이지만 원호상에서는 움직임이 동일간격이 아니며,
  두 점의 중간지점에 가까울수록 이동하는 속도가 빨라지지만 구형선형보간은 이러한 일이 없이 일정한 속도
로 움직인다.

사원수 관련 함수들
D3DXQuaternionIdentity : 단위사원수 만들기 (0,0,0,1)
D3DXQuaternionConjugate : 켤레사원수 만들기
D3DXQuaternionNormalize : 입력사원수를 단위사원수로 만들어 리턴
D3DXQuaternionInverse : 역사원수 만듬(켤레사원수를 정규화한 결과)
D3DXQuaternionMultiply : 두 사원수의 곱
D3DXQuaternionSlerp : 두 사원수를 Slerp 보간
D3DXQuaternionRotationAxis : 벡터 v를 회전으로 하여 사원수 q를 각도 angle만큼 회전.
                                           이 회전에 해당하는 사원수를 구할려면 q를 단위사원수(0,0,0,1)로 지정.
D3DXQuaternionRotationMatrix : 행렬 m에 해당하는 사원수를 만들어 리턴
D3DXMatrixRotationQuaternion : 사원수 q에 해당하는 회전행렬을 만들어 행렬 m 리턴
D3DXQuaternionRotationYawPitchRoll : yaw, pitch, roll로 사원수를 만들어 리턴

뷰행렬
void CameraQuaternion::GetViewMatrix(D3DXMATRIX* vmat)
{
 // 뷰행렬
 if(IsUpdate_)
 {
  // 1. 이동 - 카메라를 원점으로 이동 - 회전방향이 반대가 되도록 켤레사원수를 사용
  D3DXMATRIX matTranslation;
  D3DXMatrixTranslation(&matTranslation, -pos_.x, -pos_.y, -pos_.z);

  // 2. 회전 - 카메라 방향이 월드좌표계의 좌표축에 일치하도록 회전.
  D3DXMATRIX matRotation;
  D3DXMatrixRotationQuaternion(&matRotation,
   &D3DXQUATERNION(-orientation_.x, -orientation_.y, -orientation_.z, orientation_.w));

  // 3. 회전과 이동을 적용
  D3DXMatrixMultiply(&view_, &matTranslation, &matRotation);
  IsUpdate_ = false;
 }

 (*vmat) = view_;
}

이동
void CameraQuaternion::Walk(float fUnits)
{
 // z축
 D3DXVECTOR3 look;
 look.x = view_._13;
 look.y = view_._23;
 look.z = view_._33;

 if(ECT_WALKER == cameraType_)
  look.y = 0.0f;

 pos_ += look * fUnits * moveSpeed_;
 IsUpdate_ = true;
}

위치
void CameraQuaternion::Pitch(float fAngle)
{
 fAngle *= (rotateSpeed_ / 60);

 // right 방향으로 회전
 D3DXQUATERNION rot;

 // 사원수로 right 벡터를 구해서 주어진 각도만큼 right 벡터방향으로 회전하는 사원수 rot를 구한다.
 D3DXQuaternionRotationAxis(&rot, TransformAxis(&orientation_, &D3DXVECTOR3(1.0f, 0.0f, 0.0f)), fAngle);

 orientation_ *= rot; // 카메라 방향인 orientation 사원수에 rot 사원수를 곱하여 회전효과를 만든다.

 D3DXQuaternionNormalize(&orientation_, &orientation_); // 사원수 정규화.
 IsUpdate_ = true;
}

보간
bool CameraQuaternion::Slerp(D3DXQUATERNION* quatTarget)
{
 // 두 방향 사이를 부드럽게 보간(sphere linear interpolation)
 if(orientation_ == * quatTarget)
  return false;

 // 두 사원수 orientation과 quatTarget을 slerpSpeed(0~1)사이의 값으로 Slerp 보간.
 D3DXQuaternionSlerp(&orientation_, &orientation_, quatTarget, slerpSpeed_);
 D3DXQuaternionNormalize(&orientation_, &orientation_);
 IsUpdate_ = true;
 return true;
}

fx는 동일하다.



'Study > Directx 10' 카테고리의 다른 글

mesh 생성  (0) 2010.05.11
3ds 로드, 가상트랙볼  (0) 2010.05.09
카메라 클래스 - 오일러  (0) 2010.05.07
Depth Stencil ( orbit )  (0) 2010.05.05
육면체 렌더링  (0) 2010.05.05
TAGS.

Comments