기존에는 몬스터가 플레이어를 추적할때 플레이어 방향으로 각도를 맞추어 줄 수 있도록 X축과 Z축의 두개축을 가지고 atan2f() 함수를 사용하여 Y축의 회전 각도를 보간하였습니다.
기존의 방식은 평변을 기준으로 계산하기때문에 3개의 축을 한번에 계산하기는 조금 번거로웠습니다.
하지만 행렬과 CreateLookAt() 함수를 사용하여 X,Y, Z 3개의 모든축의 회전 각도를 보간할수 있는 방법을 정리하고자 합니다.
[사용 예시]
아래의 코드는 플레이어객체(player)가 항상 타겟(boss)을 향하고 있도록 회전시키는 코드입니다.
Matrix M = Matrix::CreateLookAt(player->GetWorldPos(), boss->root->GetWorldPos(), Vector3(0, 1, 0));
M = M.Transpose();
Quaternion Q = Quaternion::CreateFromRotationMatrix(M);
player->rotation.y = Util::QuaternionToYawPtichRoll(Q).y;
1. 전치행렬관계로 만들어져있는 뷰행렬를 생성합니다.
Matrix M = Matrix::CreateLookAt(회전을적용할객체의좌표, 목표대상객체의좌표, UP벡터);
inline Matrix Matrix::CreateLookAt(const Vector3& eye, const Vector3& target, const Vector3& up) noexcept
{
using namespace DirectX;
Matrix R;
XMVECTOR eyev = XMLoadFloat3(&eye);
XMVECTOR targetv = XMLoadFloat3(&target);
XMVECTOR upv = XMLoadFloat3(&up);
XMStoreFloat4x4(&R, XMMatrixLookAtLH(eyev, targetv, upv));
return R;
}
2. 뷰행렬을 전치행렬로 변환합니다.
M = M.Transpose();
inline Matrix Matrix::Transpose() const noexcept
{
using namespace DirectX;
XMMATRIX M = XMLoadFloat4x4(this);
Matrix R;
XMStoreFloat4x4(&R, XMMatrixTranspose(M));
return R;
}
3. 행렬(Matrix)을 쿼터니언(Quaternion)으로 변환합니다.
Quaternion Q = Quaternion::CreateFromRotationMatrix(M);
inline Quaternion Quaternion::CreateFromRotationMatrix(const Matrix& M) noexcept
{
using namespace DirectX;
XMMATRIX M0 = XMLoadFloat4x4(&M);
Quaternion R;
XMStoreFloat4(&R, XMQuaternionRotationMatrix(M0));
return R;
}
4. 회전시킬 객체의 회전값에 QuaternionToYawPtichRoll()함수를 사용하여 회전을 적용합니다.
회전시킬객체->rotation.y = Util::QuaternionToYawPtichRoll(Q).y;
Vector3 Util::QuaternionToYawPtichRoll(Quaternion q1)
{
float sqw = q1.w * q1.w;
float sqx = q1.x * q1.x;
float sqy = q1.y * q1.y;
float sqz = q1.z * q1.z;
float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
float test = q1.x * q1.w - q1.y * q1.z;
Vector3 v;
if (test > 0.4995f * unit) { // singularity at north pole
v.y = 2.0f * atan2f(q1.y, q1.x);
v.x = PI / 2.0f;
v.z = 0;
return NormalizeAngles(v);
}
if (test < -0.4995f * unit) { // singularity at south pole
v.y = -2.0f * atan2f(q1.y, q1.x);
v.x = -PI / 2.0f;
v.z = 0;
return NormalizeAngles(v);
}
Quaternion q = Quaternion(q1.w, q1.z, q1.x, q1.y);
// Yaw
v.y = atan2f(2.0f * q.x * q.w + 2.0f * q.y * q.z, 1.0f - 2.0f * (q.z * q.z + q.w * q.w));
// Pitch
v.x = asinf(2.0f * (q.x * q.z - q.w * q.y));
// Roll
v.z = atan2f(2.0f * q.x * q.y + 2.0f * q.z * q.w, 1.0f - 2.0f * (q.y * q.y + q.z * q.z));
return NormalizeAngles(v);
}
'공부 > DirectX3D' 카테고리의 다른 글
[DirectX3D] Slash trail (0) | 2023.09.04 |
---|---|
[DirectX3D] 폭죽 효과(파티클효과 응용) (0) | 2023.08.30 |
[DirectX3D] 눈내리는 효과(파티클효과 응용) (0) | 2023.08.29 |
[DirectX3D] PostEffect 블러(Blur)효과 적용하기 ( + Filter ) (0) | 2023.08.22 |
[DirectX3D] 로딩씬(씬전환) (0) | 2023.08.21 |
댓글