반응형

http://mgun.tistory.com/398



이전의 오일러랑 같은역활을 하긴 하지만 
오일러의 단점을 보완하는 쿼터니온이 상당히 중요하다.
오일러의 단점으로 보면
각 축에 대한 회전의 적용순서가 다양하여 순서가 다르면 결과가 달라져 혼란을 야기한다.
- 회전자유도가 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는 동일하다.



반응형

+ Recent posts