Como Nathan Reed e teodron expuseram, a receita para rotacionar um vetor v por um quaternário de comprimento unitário q é:
1) Crie um quaternion puro p fora de v . Isso significa simplesmente adicionar uma quarta coordenada de 0:
p=(vx,vy,vz,0)⇔p=(v,0)
2) Pré-multiplique-o com q e pós-multiplique-o com o conjugado q * :
p′=q×p×q∗
3) Isso resultará em outro quaternion puro que pode ser retornado a um vetor:
v′=(p′x,p′y,p′z)
Este vector v′ é v girado por q .
Isso está funcionando, mas está longe de ser o ideal . Multiplicações de Quaternion significam toneladas e toneladas de operações. Fiquei curioso sobre várias implementações como esta e decidi descobrir de onde elas vieram. Aqui estão minhas descobertas.
Também podemos descrever q como a combinação de um vetor tridimensional u e um escalar s :
q=(ux,uy,uz,s)⇔q=(u,s)
Pelas regras de multiplicação de quaternion , e como o conjugado de um quaternion de comprimento de unidade é simplesmente inverso, obtemos:
p′=qpq∗=(u,s)(v,0)(−u,s)=(sv+u×v,−u⋅v)(−u,s)=((−u⋅v)(−u)+s(sv+u× v)+(sv+u×v)×(−u),…)=((u⋅v)u+s2v+s(u×v)+sv×(−u)+(u×v)×(−u),…)
A parte escalar (elipses) resulta em zero, conforme detalhado aqui . O interessante é a parte do vetor, também conhecido como vetor girado v ' . Pode ser simplificado usando algumas identidades vetoriais básicas :
v′=(u⋅v)u+s2v+s(u×v)+s(u×v)+u×(u×v)=(u⋅v)u+s2v+2s(u×v)+(u⋅v)u−(u⋅u)v=2(u⋅v)u+(s2−u⋅u)v+2s(u×v)
Agora isso é muito mais ideal ; dois produtos pontuais, um produto cruzado e alguns extras: cerca de metade das operações. O que daria algo parecido com isso no código-fonte (assumindo alguma biblioteca matemática vetorial genérica):
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);
}