Quaternion.js로 쿼터니온 평균 구하기
Slerp 개념 이해하기
사실, 지금껏 '평균' 이라고 했지만 '내삽' 이라는 좀더 일반적이고 깔끔한 용어가 있었다는 것을 잊고 있었습니다.
지난 포스트에서 쿼터니온을 최대한 건드리지 않고 오일러 각도로 변환한 뒤 각도의 평균을 내 주는 방법을 사용했다고 했죠.
그런데 이게 부정확했던 겁니다. 계속 값이 튀었어요. 모듈로 계산도 써 보고 머리를 싸매다가, 결국 스택오버플로우에서 검색을 해봤어요.
Yes, only quaternions are appropriate for inter/extrapolation.
네? 내삽/외삽을 게산하는 데 쿼터니온만이 적합하다고 합니다.
Quaternion Slerps are commonly used to construct smooth animation curves ...
아... 그랬던 겁니다. 애초에 제가 하는 스무딩 작업은 오일러 각도이든 축각 각도이든 한계가 있었고, 쿼터니온의 Slerp 라는 방법을 써야 각도의 내삽이 가능했던 거였어요.
다음은 위키백과의 Slerp 문서에서 가져온 사진입니다.
네.. 제가 원한 게 바로 이거였거든요. 두 개의 벡터의 단순 평균을 내 주는 게 아니라, 각도의 평균을 내 주는 작업이죠.
쿼터니온의 Slerp은 다음과 같은 계산과정을 거치는 모양입니다.
하지만 여기서는 Slerp의 개념만 이해하고 넘어가기로 했습니다. 계산과정은 모듈에게 맡기기로 합니다.
quaternion.js 모듈에 내삽과 관련된 함수가 있는지 찾아봅시다. (없으면 구현해야 하니까요...-_–)
아예 대놓고 Slerp 함수가 있었네요.... 지금이라도 찾아서 다행이라고 생각하며 적용해 보았어요.
적용해보기
우선 오일러 각으로 변환하던 기존 코드들을 전부 주석처리한 뒤,
var q1, q2
q1 = new Quaternion(result1[6], result1[3], result1[4], result1[5])
q2 = new Quaternion(result2[6], result2[3], result2[4], result2[5])
//평균을 내 줘야 하는 곳에서
var q3 = q1.slerp(result2[6], result2[3], result2[4], result2[5])(0.5)
//0.5 부분에는 0-1까지의 float가 들어갈 수 있습니다.
var index = [1,2,3,4,5,6,7,8,9]
for await (let i of index) {
var qResult = qformer.slerp(q3_w, q3_xyz[0], q3_xyz[1], q3_xyz[2])(i/9)
}
쿼터니온의 성분은 기존 코드에서 가져왔습니다.
근데 저렇게 하면 q2 변수는 왜 필요한거냐...? 사실은 오일러각 계산에 필요해서 저장해두고 있습니다.
모든 오일러각을 전부 없앤 게 아니고, 오일러각으로 다루는 게 편한 부분은 오일러각으로, 쿼터니온으로 다루는 게 편한 부분은 쿼터니온으로, 둘 다 비슷하다면 쿼터니온으로 계산하고 있어요.