Quaternion에서 회전 행렬을 만드는 방법을 정리하고 이를 구현한 코드를 첨부하시오.
사원수의 회전 식
$q_1\cdot q_2 =(w_1w_2-(v1\cdot v2), w_1v_2+w_2v_1 + v_1\times v_2)$
$\quad \space \space \space \space \space \space =(-(\vec{v_1}\cdot \vec{v_1}),(\vec{v_1}\times \vec{v_1}))$
실수부를 통일 시키지 않고 위 식을 적용하면 실수부가 다르므로 다른 공간에 존재 하게 됨.
$v' = qvq^* = v + wt + v\times t$
그러므로 위 식을 이용해서 실수부를 통일시켜야 합니다.
$v' = q(0, 1, 0, 0)q^*$
$\quad = (w + xi + yj + zk)(i)(w -xi -yj -zk) $
$ \quad = (-x + wi + zj - yk)(w - xi -yj -zk) $
$ \quad = x^2i + xyj + xzk + w^2i -wyij -wzik +wzj - xzji -z^2jk -wyk +xyki +y^2kj $
$ \quad = x^2i + xyj + xzk + w^2i -wyk +wzj +wzj + xzk -z^2i -wyk +xyj -y^2i $
$ \quad= (w^2 + x^2 + -y^2 - z^2)i + 2(xy + wz)j + 2(xz - wy)k $
$ \quad= (1 - 2(y^2 + z^2))i + 2(xy + wz)j + 2(xz - wy)k \quad (w^2 + x^2 = 1 - y^2 -z^2)$
$v' = q(0, 0, 1, 0)q^*$
$ \quad = (w + xi + yj + zk)(j)(w -xi -yj -zk)$
$ \quad = (-y - zi + wj + xk)(w-xi-yj-zk)$
$ \quad = xyi - wzi - wzjk -xykj + y^2j + z^2ik + w^2j - x^2ki + yzk + yzij - wxji + wxk$
$ \quad = xyi - wzi - wzi + xyi + y^2j - z^2j + w^2j - x^2j + yzk + yzk + wxk + wxk$
$ \quad = 2(xy - wz)i + (w^2 - x^2 + y^2 - z^2)j + 2(wx + yz)k$
$ \quad = 2(xy - wz)i + (1 - 2(x^2 + z^2))j + 2(wx + yz)k$
$v' = q(0, 0, 0, 1)q^* $
$ \quad = (w + xi + yj + zk)(k)(w -xi -yj -zk) $
$ \quad = (-z + yi - xj + wk)(w-xi-yj-zk) $
$ \quad = xzi + wyi +xzjk -wykj + yzj - yzik - wxj - wxki + z^2k - y^2ij + x^2ji + w^2k $
$ \quad = xzi + wyi +xzi +wyi + yzj + yzj - wxj - wxj + z^2k - y^2k - x^2k + w^2k $
$ \quad = 2(wy + xz)i + 2(yz - wx)j + (1 - 2(x^2 + y^2))k$
$M = \begin{bmatrix}
1- 2(y^2 + z^2) & 2(xy -wz) & 2(xz +wy) & 0 \\
2(xy+wz) & 1-2(x^2 - z^2) & 2(yz-wx) & 0\\
2(xz - wy) & 2(yz + wx) & 1 - 2(x^2 - y^2) & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}$
FORCEINLINE Matrix4x4 Quaternion::ToRotationMatrix() const
{
Matrix4x4 result;
float xs = X * X;
float ys = Y * Y;
float zs = Z * Z;
float wx = W * X;
float wy = W * Y;
float wz = W * Z;
float xy = X * Y;
float xz = X * Z;
float yz = Y * Z;
result.Cols[0] = Vector4(1.f - 2.f * (ys + zs), 2.f * (xy + wz), 2.f * (xz - wy), 0.f);
result.Cols[1] = Vector4(2.f * (xy - wz), 1.f - 2.f * (xs + zs), 2.f * (wx + yz), 0.f);
result.Cols[2] = Vector4(2.f * (wy + xz), 2.f * (yz - wx), 1.f - 2.f * (xs + ys), 0.f);
result.Cols[3] = Vector4(0.f, 0.f, 0.f, 1.f);
return result;
}
오일러 각 정보를 받아 Quaternion으로 변환하는 수식을 정리하고 이를 구현한 코드를 첨부하시오.
$q_{yaw}, q_{pitch}, q_{roll}$ 을 활용합니다.
$q_y = cos\frac{\theta_y}{2} + sin\frac{\theta_y}{2}j$
$q_p = cos\frac{\theta_p}{2} + sin\frac{\theta_p}{2}i$
$q_r = cos\frac{\theta_r}{2} + sin\frac{\theta_r}{2}k$
$q_y \cdot q_p \cdot q_r = (cos\frac{\theta_y}{2} + sin\frac{\theta_y}{2}j) (cos\frac{\theta_p}{2} + sin\frac{\theta_p}{2}i) (cos\frac{\theta_r}{2} + sin\frac{\theta_r}{2}k) $
$ = (cos\frac{\theta_y}{2}cos\frac{\theta_p}{2} + cos\frac{\theta_y}{2}sin\frac{\theta_p}{2}i + sin\frac{\theta_y}{2}cos\frac{\theta_p}{2}j + sin\frac{\theta_y}{2}sin\frac{\theta_p}{2}ji)(cos\frac{\theta_r}{2} + sin\frac{\theta_r}{2}k) $
$ = (cos\frac{\theta_y}{2}cos\frac{\theta_p}{2} + cos\frac{\theta_y}{2}sin\frac{\theta_p}{2}i + sin\frac{\theta_y}{2}cos\frac{\theta_p}{2}j - sin\frac{\theta_y}{2}sin\frac{\theta_p}{2}k)(cos\frac{\theta_r}{2} + sin\frac{\theta_r}{2}k) $
$ = cos\frac{\theta_y}{2}cos\frac{\theta_p}{2} cos\frac{\theta_r}{2} + cos\frac{\theta_y}{2}cos\frac{\theta_p}{2} sin\frac{\theta_r}{2}k + cos\frac{\theta_y}{2}sin\frac{\theta_p}{2} cos\frac{\theta_r}{2}i $
$ \quad + cos\frac{\theta_y}{2}sin\frac{\theta_p}{2} sin\frac{\theta_r}{2}ik + sin\frac{\theta_y}{2}cos\frac{\theta_p}{2} cos\frac{\theta_r}{2}j + sin\frac{\theta_y}{2}cos\frac{\theta_p}{2} sin\frac{\theta_r}{2}jk $
$ \quad - sin\frac{\theta_y}{2}sin\frac{\theta_p}{2} cos\frac{\theta_r}{2}k - sin\frac{\theta_y}{2}sin\frac{\theta_p}{2} sin\frac{\theta_r}{2}kk $
$ = cos\frac{\theta_y}{2}cos\frac{\theta_p}{2} cos\frac{\theta_r}{2} + sin\frac{\theta_y}{2}sin\frac{\theta_p}{2} sin\frac{\theta_r}{2} $
$ \quad + (cos\frac{\theta_y}{2}sin\frac{\theta_p}{2} cos\frac{\theta_r}{2} + sin\frac{\theta_y}{2}cos\frac{\theta_p}{2} sin\frac{\theta_r}{2})i $
$ \quad + (sin\frac{\theta_y}{2}cos\frac{\theta_p}{2} cos\frac{\theta_r}{2} - cos\frac{\theta_y}{2}sin\frac{\theta_p}{2} sin\frac{\theta_r}{2})j $
$ \quad + (cos\frac{\theta_y}{2}cos\frac{\theta_p}{2} sin\frac{\theta_r}{2} - sin\frac{\theta_y}{2}sin\frac{\theta_p}{2} cos\frac{\theta_r}{2})k $
$ = w + xi + yj + zk $
FORCEINLINE explicit Quaternion(const Rotator & InRotator)
{
float sp, sy, sr;
float cp, cy, cr;
Math::GetSinCos(sy, cy, InRotator.Yaw * 0.5f);
Math::GetSinCos(sp, cp, InRotator.Pitch * 0.5f);
Math::GetSinCos(sr, cr, InRotator.Roll * 0.5f);
W = cy * cp * cr + sy * sp * sr;
X = cy * sp * cr + sy * cp * sr;
Y = sy * cp * cr - cy * sp * sr;
Z = cy * cp * sr - sy * sp * cr;
}
Quaterion에서 오일러 각 정보로 변환하는 수식을 정리하고 이를 구현한 코드를 첨부하시오.
$sin\theta_{r}\cdot cos\theta_{p}=2(wz+xy)$
$cos\theta_{r}\cdot cos\theta_{p}=1-2(z^2+x^2)$
$tan\theta_{r}=\frac{2(wz+xy)}{(1-2(z^2+x^2))}$
$\theta_r = atan2(2(wz+xy), (1 - 2(z^2+x^2))) \quad (cos\theta_p \neq 0, cos\theta_r \neq 0)$
$sin\theta_p = 2(wx-yz)$
$\theta_p = asin(2(wx-yz))$ (- $ \theta_p = asin(2(wx-yz)) \quad (-\frac{\pi}{2} < \theta_p <\frac{\pi}{2})$
$sin\theta_y \cdot cos\theta_p = 2(xy+xz)$
$cos\theta_y \cdot cos\theta_p = 1-2(x^2+y^2)$
$tan\theta_y = \frac{2(wy+xz)}{1 - 2(x^2+y^2)}$
$\theta_y = atan2(2(wy+xz), 1 - 2(x^2+y^2))$
FORCEINLINE Rotator Quaternion::ToRotator() const
{
Rotator result;
result.Roll = Math::Rad2Deg(atan2f(2 * (W * Z + X * Y), 1 - 2 * (Z * Z + X * X)));
const float singularity = 0.499999f;
float sinp = 2 * W * X - Y * Z;
if (W * X - Y * Z < -singularity)
{
result.Pitch = -90.f;
}
else if (W * X - Y * Z > singularity)
{
result.Pitch = 90.f;
}
else
{
result.Pitch = Math::Rad2Deg(asinf(sinp));
}
result.Yaw = Math::Rad2Deg(atan2f(2 * (W * Y + X * Z), 1.f - 2 * (X * X + Y * Y)));
return result;
}
Quaternion의 Slerp를 구현을 위한 공식을 정리하고, 이를 구현한 코드를 첨부하시오.
Lerp
$q(t)=(1-t)\cdot q_1+t\cdot q_2$
$q'=\frac{q(t)}{|q(t)|}$
Slerp
삼각비와 내적을 사용합니다.
$q = cost\theta q_1+sint\theta \frac{q_{2\perp}}{|q_2{\perp}|}$
$q_{2\perp} = q_2 - cos\theta q_1$
$|q_2{\perp}| = \sqrt{(q_2 - cos\theta q_1)(q_2 - cos\theta q_1)} $
$ = \sqrt{q^2_2 - 2cos\theta q_2\cdot q_1 + cos^2\theta q^2_1}$
$ = \sqrt{1 - 2cos^2\theta + cos^2\theta}$
$= \sqrt{1 - cos^2\theta} $
$ = sin\theta $
$q = cost\theta q_1 + sint\theta \frac{q_2 - cos\theta q_1}{sin\theta} $
$ = (\frac{sin\theta cost\theta - cos\theta}{sin\theta})q_1 + (\frac{sint\theta}{sin\theta})q_2 $
$ = (\frac{sin(1 - t)\theta}{sin\theta})q_1 + (\frac{sint\theta}{sin\theta})q_2 $
Quaternion Quaternion::Slerp(const Quaternion& q1, const Quaternion& q2, const float& t)
{
Quaternion result;
float cosTheta = Math::Clamp(q1.W * q2.W + q1.X * q2.X + q1.Y * q2.Y + q1.Z * q2.Z, -1.f, 1.f);
float s1, s2;
if (cosTheta < 0.99999f)
{
float theta = acosf(cosTheta);
float invSin = 1.f / sinf(theta);
s1 = sinf((1.f - t) * theta) * invSin;
s2 = sinf(t * theta) * invSin;
}
else
{
return Lerp(q1, q2, t);
}
result = q1 * s1 + q2 * s2;
return result;
}
마인크래프트 캐릭터를 계층구조로 만들고 Quaternion Slerp를 사용해 회전시키는 애니메이션을 구현하시오.
Front Page :
'게임제작기법연구' 카테고리의 다른 글
게임제작기법 연구 14주차 (0) | 2020.07.14 |
---|---|
게임제작기법연구 13주차 (0) | 2020.07.07 |
게임제작기법연구 12주차 (0) | 2020.06.29 |
게임제작기법연구 11주차 (0) | 2020.06.22 |
게임제작기법연구 10주차 (0) | 2020.06.16 |