답변:
Nathan Reed와 teodron이 노출 한 것처럼 단위 길이 쿼터니언 q 로 벡터 v 를 회전시키는 방법 은 다음과 같습니다.
1) 순수 사원 수 만들기 페이지 중 절 . 이것은 단순히 네 번째 좌표 0을 추가하는 것을 의미합니다.
2) q를 사전 곱하고 켤레 q *를 곱한 후 :
3) 이것은 또 다른 순수한 쿼터니언을 만들어 벡터로 되돌릴 수 있습니다.
이 벡터 이며 회전 .
이것은 작동하지만 최적 은 아닙니다 . 쿼터니언 곱셈은 톤과 톤의 연산을 의미합니다. 나는 이것과 같은 다양한 구현에 대해 호기심이 많았고 , 어디에서 왔는지 찾기로 결정했습니다. 내 결과는 다음과 같습니다.
또한 설명 할 수 Q를 3 차원 벡터의 조합으로서 U 스칼라 S :
쿼터니언 곱셈 의 규칙에 따르면 단위 길이 쿼터니언의 켤레가 단순히 역수이므로 다음과 같이됩니다.
스칼라 부분 (ellipses)은 여기에 설명 된대로 0이 됩니다 . 흥미로운 것은 벡터 부분, 일명 우리의 회전 벡터 v ' 입니다. 몇 가지 기본 벡터 ID를 사용하여 단순화 할 수 있습니다 .
이것은 지금 훨씬 더 최적입니다 ; 두 개의 도트 제품, 교차 제품 및 몇 가지 추가 기능 : 작업의 절반 정도. 소스 코드에서 일반적인 벡터 수학 라이브러리를 가정하면 다음과 같이됩니다.
void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
// Extract the vector part of the quaternion
Vector3 u(q.x, q.y, q.z);
// Extract the scalar part of the quaternion
float s = q.w;
// Do the math
vprime = 2.0f * dot(u, v) * u
+ (s*s - dot(u, u)) * v
+ 2.0f * s * cross(u, v);
}
vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0f
이것은 유사한 최적화입니까? 다소 비슷해 보이지만 동일하지는 않습니다. 즉, 도트 제품이 아닌 교차 제품 만 사용합니다. 원본 소스 코드는 공식 GLM 저장소의 type_quat.inl 파일 에서 찾을 수 있습니다.이 파일operator*
에는 쿼터니언과 벡터 ( vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v)
)
우선, q ^ (-1)은 -q / magnitude (q)가 아닙니다. 그것은 q * / (magnitude (q)) ^ 2입니다 (q *는 켤레입니다; 이것은 실제 요소를 제외한 모든 구성 요소를 무효화합니다). 물론 모든 쿼터니언이 이미 정규화되어 있으면 회전 시스템에있을 경우 그 크기만큼 나눌 수 있습니다.
벡터의 곱셈에 대해서는 쿼트의 실제 성분을 0으로 설정하고 ijk 성분을 벡터의 xyz로 설정하여 벡터를 쿼터니언으로 확장하면됩니다. 그런 다음 쿼터니언 곱셈을 수행하여 v '를 얻은 다음 ijk 구성 요소를 다시 추출합니다. v '의 실수 부분은 항상 0에서 부동 소수점 오류를 더하거나 뺀 값이어야합니다.
첫 번째 관찰 :의 반대 q
는 아닙니다 -q/magnitude(q)
. 그것은 완전히 잘못되었습니다. 쿼터니언을 사용한 회전은 이러한 4D 복소수의 등가물이 단일 규범을 가지며 따라서 4D 공간에서 S3 단위 구에 있다는 것을 의미합니다. 쿼트가 단일이라는 사실은 그 표준이 norm(q)^2=q*conjugate(q)=1
그렇다는 것을 의미하며, 그 쿼트의 역수가 공액임을 의미합니다.
단위 쿼터니언이 q=(w,x,y,z)
= (cos (t), sin (t) v )로 작성되면 해당 켤레는 conjugate(q)=(w,-x,-y,-z)
= (cos (t),-sin (t) v )이며, 여기서 t 는 회전 각도의 절반이고 v 회전 축은 물론 단위 벡터입니다.
해밀턴 친구가 더 큰 차원의 복잡한 숫자를 사용하기로 결정했을 때, 그는 또한 좋은 속성을 발견했습니다. 예를 들어, 완전히 순수한 쿼터니언 q=(0,x,y,z)
(스칼라 부분 w 없음) 을 사용하는 경우 해당 쓰레기를 벡터로 간주 할 수 있습니다 (실제로 사람들이 S3 구의 적도라고 부르는 것에 대한 쿼트, 즉 S2 구입니다! 요즘 우리가 19 세기 사람들이 기술적으로 얼마나 손상을 입 었는지 생각해 보면 마음이 구부러진 다. 해밀턴은 그 벡터를 그 쿼트 형태로 가져 왔습니다. 쿼트 v=(0,x,y,z)
의 기하학적 특성을 고려한 일련의 실험을했습니다.
INPUT: _v=(x,y,z)_ a random 3D vector to rotate about an __u__ unit axis by an angle of _theta_
OUTPUT: q*(0,_v_)*conjugate(q)
어디에
q = (cos(theta/2), sin(theta/2)*u)
conjugate(q) = inverse(q) = (cos(theta/2), -sin(theta/2)*u)
norm(q)=magnitude(q)=|q|=1
관찰 : q * (0, v) * conj (q)는 (0, v ') 형식의 다른 쿼트 여야합니다. 왜 이런 일이 발생하는지에 대한 복잡한 설명은하지 않겠지 만,이 방법을 통해 순수한 가상의 쿼터니언 (또는 우리의 경우 벡터!)을 회전 시키면 비슷한 종류의 객체를 얻을 수 있습니다 : 순수한 상상의 쿼트. 그리고 당신은 그 가상의 결과를 당신의 결과로 받아들입니다. 거기에는 너트 쉘에 쿼터니언이있는 멋진 회전 세계가 있습니다.
참고 : 남용 된 문구로 뛰어 들어가는 사람 : 쿼트는 짐벌 락을 피하기 때문에 좋습니다. 먼저 상상력을 풀어야합니다 !! 쿼트는 단순한 "우아한"수학적 장치이며 다른 접근 방식을 사용하여 완전히 피할 수 있습니다. 축 앵글 접근과 완전히 기하학적으로 동등한 것을 알 수 있습니다.
코드 : 내가 상상 하는 C ++ 라이브러리 는 다소 단순하지만, 3D 그래픽 실험가가 그것을 배우기 위해 15 분 이상 낭비 할 필요가없는 모든 매트릭스, 벡터 및 쿼트 연산이 있습니다. 여기에서 작성한 것을 테스트 할 수 있습니다. C ++ 초보자가 아닌 경우 15 분 안에. 행운을 빕니다!
다음은 벡터를 쿼터니언으로 변환하는 다른 방법입니다. MS가 xna 프레임 워크에서하는 방식입니다. http://pastebin.com/fAFp6NnN
나는 이것을 손으로 해결하려고 노력했으며 다음 방정식 / 방법을 생각해 냈습니다.
// inside quaterion class
// quaternion defined as (r, i, j, k)
Vector3 rotateVector(const Vector3 & _V)const{
Vector3 vec(); // any constructor will do
vec.x = 2*(r*_V.z*j + i*_V.z*k - r*_V.y*k + i*_V.y*j) + _V.x*(r*r + i*i - j*j - k*k);
vec.y = 2*(r*_V.x*k + i*_V.x*j - r*_V.z*i + j*_V.z*k) + _V.y*(r*r - i*i + j*j - k*k);
vec.z = 2*(r*_V.y*i - r*_V.x*j + i*_V.x*k + j*_V.y*k) + _V.z*(r*r - i*i - j*j + k*k);
return vec;
}
누군가가 mt deriviation을 살펴 본다면 http://pastebin.com/8QHQqGbv를 사용 했다면 측면 스크롤을 지원하는 텍스트 편집기로 복사하는 것이 좋습니다.
내 표기법에서 나는 q ^ (-1)을 사용하여 켤레, 역수 및 다른 식별자를 의미했지만 후속 할 수 있기를 바랍니다. 나는 벡터의 실제 부분을 증명할 때 특히 대부분이 사라질 것이라고 생각합니다.