지난 포스트에 이어 우리가 그동안 배운 행렬 연산을 실제로 어떤 식으로 활용할 수 있는지 다른 예시도 살펴보자.
회전목마 같이 회전하는 원판 위에 어떤 물체가 놓여 있을 때, 회전목마가 S(=회전행렬) 만큼 회전했을 경우 이 물체의 위치는 초기 위치 B에서 어떻게 표현할 수 있을까?
우선 회전목마의 Transform부터 표현해보자.
우리는 Transform을 TRS 중 S를 생략한 TR matrix로 표현가능하며, 회전목마의 회전하기 전 TR Matrix를 M이라고 하자.
또 y축에 대해 일정 각도만큼 회전운동을 하는 행위를 나타낸 회전행렬 S가 있다고 하자.
이때 회전 후 Transform인 M'은 단순히 SM으로 표현할 수 없는데, 이는 M이 기준점에 있다는 보장이 없으므로 S만큼 회전했을 때 M의 중심을 기준으로 회전하는 게 아닌, 좌표계 원점을 기준으로 회전해버려 전혀 다른 위치로 가버릴 수도 있기 때문이다.
때문에 우리는 우선 이 회전목마를 원점까지 가져온 이후 이걸 회전시키고 그걸 다시 원래 위치에 돌려놓아야 한다.
이는 T * S * T^-1 * M으로 표현할 수 있다. (연산순서 우에서 좌로 가는 것에 항상 주의)
이때 M은 TR이므로 (TR Matrix) 이 식을 정리하면
M' = T * S * R이 된다.
이번에는 이렇게 얻은 M'을 이용해 회전목마 위에 있던 상자의 transform을 표현해보자.
상자의 transform은 회전목마의 로컬 좌표계를 기준으로 나타낼 수 있는데, 상자의 transform이 B이고 회전목마의 로컬 좌표계에서의 상자의 transform은 M^-1 * B이다.
M^-1 * B을 S만큼 회전시켜주고 그걸 다시 global 좌표계로 변환해주면 최종결과를 구할 수 있다.
B' = M * S * M^-1 * B
이제 매 프레임마다 상자의 transform과 회전목마의 transform을 각각 B', M'으로 설정해주면 제대로 동작하는 회전운동을 볼 수 있다.
S를 어떻게 구하는지에 대해서는 다음 코드를 참고하자.
회전할 각과 회전축(벡터)가 주어질 때 회전행렬 S는 다음과 같이 표현 가능하다.
void Matrix4x4::SetRotation(float flAngle, const Vector& v)
{
// Normalize beforehand
TAssert(fabs(v.LengthSqr() - 1) < 0.000001f);
// c = cos(angle), s = sin(angle), t = (1-c)
// [ xxt+c xyt-zs xzt+ys ]
// [ yxt+zs yyt+c yzt-xs ]
// [ zxt-ys zyt+xs zzt+c ]
float x = v.x;
float y = v.y;
float z = v.z;
float c = cos(flAngle*(float)M_PI/180);
float s = sin(flAngle*(float)M_PI/180);
float t = 1-c;
m[0][0] = x*x*t + c;
m[1][0] = x*y*t - z*s;
m[2][0] = x*z*t + y*s;
m[0][1] = y*x*t + z*s;
m[1][1] = y*y*t + c;
m[2][1] = y*z*t - x*s;
m[0][2] = z*x*t - y*s;
m[1][2] = z*y*t + x*s;
m[2][2] = z*z*t + c;
}
'mathematics > game mathematics' 카테고리의 다른 글
[Mathematics] 28. 회전목마 (0) | 2022.08.07 |
---|---|
[Mathematics] 26. Camera view transformation matrix (0) | 2022.06.23 |
[Mathematics] 25. Local vs Global Coordinate System(3D) (0) | 2022.06.23 |
[Mathematics] 24. Fast TR Matrix Inversion (0) | 2022.06.23 |
[Mathematics] 23. Eigenvectors, Eigenvalues (0) | 2022.06.06 |