Eu tenho dois vetores uev. Existe uma maneira de encontrar um quatérnio que representa a rotação de u para v?
math
vector
quaternions
sdfqwerqaz1
fonte
fonte
crossproduct
não será válido nesses casos, portanto, primeiro você precisa verificardot(v1, v2) > 0.999999
edot(v1, v2) < -0.999999
, respectivamente, e retornar um quat de identidade para vetores paralelos ou retornar uma rotação de 180 graus (em torno de qualquer eixo) para vetores opostos.sqrt((v1.Length ^ 2) * (v2.Length ^ 2))
simplifica parav1.Length * v2.Length
. Não consegui obter nenhuma variação disso para produzir resultados razoáveis.Solução vetorial de meio caminho
Eu encontrei a solução que acredito que Imbrondir estava tentando apresentar (embora com um pequeno erro, provavelmente por isso que o sinistrochipmunk teve problemas para verificar).
Dado que podemos construir um quatérnio representando uma rotação em torno de um eixo assim:
E que o ponto e o produto cruzado de dois vetores normalizados são:
Visto que uma rotação de u para v pode ser alcançada girando por teta (o ângulo entre os vetores) em torno do vetor perpendicular, parece que podemos construir diretamente um quatérnion representando tal rotação a partir dos resultados dos produtos pontuais e cruzados ; no entanto, como está, theta = ângulo / 2 , o que significa que fazer isso resultaria no dobro da rotação desejada.
Uma solução é a de calcular um meio caminho vector entre u e v , e usar o ponto e o produto cruzado de u e a meio caminho vector para construir um Quatérnion representando uma rotação de duas vezes o ângulo entre u e a meio caminho vector, o que nos leva até v !
Há um caso especial, onde u == -v e um vetor intermediário único se torna impossível de calcular. Isso é esperado, dadas as infinitas rotações de "arco mais curto" que podem nos levar de u a v , e devemos simplesmente girar 180 graus em torno de qualquer vetor ortogonal a u (ou v ) como nossa solução de caso especial. Isso é feito tomando o produto vetorial normalizado de u com qualquer outro vetor não paralelo a u .
Segue-se um pseudocódigo (obviamente, na realidade, o caso especial teria que levar em conta imprecisões de ponto flutuante - provavelmente verificando os produtos escalares em relação a algum limite em vez de um valor absoluto).
Observe também que não há nenhum caso especial quando u == v (o quatérnio de identidade é produzido - verifique e veja por si mesmo).
A
orthogonal
função retorna qualquer vetor ortogonal ao vetor fornecido. Esta implementação usa o produto vetorial com o vetor de base mais ortogonal.Solução de Quatérnio de Meio Caminho
Esta é realmente a solução apresentada na resposta aceita, e parece ser marginalmente mais rápida do que a solução vetorial intermediária (~ 20% mais rápida pelas minhas medições, embora não acredite apenas no que eu digo). Estou adicionando aqui para o caso de outras pessoas como eu estarem interessadas em uma explicação.
Essencialmente, em vez de calcular um quatérnio usando um vetor intermediário, você pode calcular o quatérnio que resulta em duas vezes a rotação necessária (conforme detalhado na outra solução) e encontrar o quatérnio a meio caminho entre aquele e zero graus.
Como expliquei antes, o quatérnio para o dobro da rotação necessária é:
E o quatérnio para rotação zero é:
Calcular o quatérnio a meio caminho é simplesmente uma questão de somar os quatérnios e normalizar o resultado, assim como acontece com os vetores. Porém, como também é o caso com vetores, os quatérnions devem ter a mesma magnitude, caso contrário, o resultado será desviado para o quatérnio com a magnitude maior.
A quaternion construído a partir do ponto e produto cruzado de dois vetores terá a mesma magnitude em que esses produtos:
length(u) * length(v)
. Em vez de dividir todos os quatro componentes por esse fator, podemos aumentar o quaternion de identidade. E se você está se perguntando por que a resposta aceita aparentemente complica as coisas com o usosqrt(length(u) ^ 2 * length(v) ^ 2)
, é porque o comprimento ao quadrado de um vetor é mais rápido de calcular do que o comprimento, portanto, podemos salvar umsqrt
cálculo. O resultado é:E então normalize o resultado. Segue pseudocódigo:
fonte
O problema conforme afirmado não está bem definido: não há uma rotação única para um determinado par de vetores. Considere o caso, por exemplo, onde u = <1, 0, 0> e v = <0, 1, 0> . Uma rotação de u para v seria uma rotação pi / 2 em torno do eixo z. Outra rotação de u para v seria uma rotação pi em torno do vetor <1, 1, 0> .
fonte
Por que não representar o vetor usando quatérnions puros? É melhor se você normalizá-los primeiro, talvez.
q 1 = (0 u x u y u z ) '
q 2 = (0 v x v y v z )'
q 1 q rot = q 2
Pré-multiplique com q 1 -1
q rot = q 1 -1 q 2
onde q 1 -1 = q 1 conj / q norma
Isso pode ser considerado "divisão à esquerda". A divisão certa, que não é o que você quer, é:
q rot, right = q 2 -1 q 1
fonte
Não sou muito bom no Quaternion. No entanto, eu lutei por horas nisso e não consegui fazer a solução Polaris878 funcionar. Eu tentei pré-normalizar v1 e v2. Normalizando q. Normalizando q.xyz. Mesmo assim, não entendo. O resultado ainda não me deu o resultado certo.
No final, porém, encontrei uma solução que o fez. Se isso ajudar mais alguém, aqui está meu código de trabalho (python):
Um caso especial deve ser feito se v1 e v2 são paralelos como v1 == v2 ou v1 == -v2 (com alguma tolerância), onde acredito que as soluções devem ser Quaternion (1, 0,0,0) (sem rotação) ou Quaternion (0, * v1) (rotação de 180 graus)
fonte
quat = diffVectors(v1, v2); assert quat * v1 == v2
.angle
obtém seu valor de um produto escalar.Algumas das respostas não parecem considerar a possibilidade de que o produto cruzado possa ser 0. O snippet abaixo usa a representação do eixo do ângulo:
O
toQuaternion
pode ser implementado da seguinte forma:Se você estiver usando a biblioteca Eigen, também pode simplesmente fazer:
fonte
toQuaternion(axis, ang)
-> você se esqueceu de especificar o que éang
angle
que faz parte da representação do ângulo do eixo do quaternion, medido em radianos.Do ponto de vista do algoritmo, a solução mais rápida olha em pseudocódigo
Certifique-se de que você precisa de quatérnios de unidade (normalmente, é necessário para interpolação).
NOTA: Quatérnions não unitários podem ser usados com algumas operações mais rápidas do que a unidade.
fonte