Como posso comparar dois quaternions por igualdade lógica?

9

Estou tentando escrever alguns testes de unidade e percebo que não sei como comparar quaterniões. Preciso saber se dois quaternions representam a mesma orientação (o objeto estaria voltado para o mesmo caminho). Com uma posição de vetor, eu simplesmente compararia as partes e verificaria se elas estão próximas o suficiente, mas para quaternions os valores podem ser muito diferentes.

Como posso comparar dois quaternions?

edA-qa mort-ora-y
fonte
Não tenho certeza se é uma prática padrão, mas, por exemplo, Java e Unity, os quaternions são armazenados como quatro valores flutuantes. Basta compará-los um ao outro, conforme descrito nestas mensagens: answers.unity3d.com/questions/288338/... stackoverflow.com/questions/5803627/quaternion-comparision
Tholle
11
@ Instrua o usuário também se preocupa com o impacto da aplicação do quaternion para transformar / girar uma entidade 3D (por exemplo, em pose). Dois quaternions diferentes podem atingir a mesma rotação (por exemplo, qe -q). A maneira ingênua (computacionalmente-wise) seria a de aplicar os dois quaternions para o mesmo vector e ver se os resultados do vetor são diferentes ..
teodron

Respostas:

7

Se seus dois quaternions são q1e q2, eles representam a mesma rotação se uma dessas duas condições for válida:

  1. q1é componente sábio aproximadamente igual a q2OR
  2. q1 é componente sábio aproximadamente igual a -q2

Sabendo disso, você pode escrever um testador de igualdade bastante simplista que atenda ao seu objetivo.

teodron
fonte
9
+1, porém, um nitpick qe -qrepresentam a mesma orientação (que estava sendo solicitada), mas não a mesma rotação. Isso é crucial ao interpolar.
falstro 15/05
@falstro, acho que entendo o que você quer dizer: os eixos de rotação são invertidos, mas o ângulo de argumento também é negado entre qe -qquando representado como um operador de rotação de eixo de ângulo. Portanto, tecnicamente, o efeito dessas rotações é o mesmo, embora os operadores não sejam. E, sim, quando SLERPING, é preciso ter certeza q1e q2estar no mesmo hemisfério da hiperesfera S3 para que o slerp siga o caminho mais curto.
Teodron 15/05
11
Exatamente, quando você executa qualquer rotação, você acaba com a mesma orientação, mas a interpola (se você lê ou slerp ou alguma outra interpolação sofisticada), verá que está mudando de maneira. E sim, o argumento do ângulo é negado, mas é o mesmo que 2pi-angle, portanto, está girando o caminho longo em torno dos eixos negados. Às vezes é isso que você deseja; é apenas algo para estar ciente, q1 dot q2 > 0resulta no turno curto, q1 dot q2 < 0leva no turno longo.
falstro 15/05
12

Só porque não foi mencionado. Como os quaternions usados ​​para orientação espacial têm sempre o comprimento da unidade (ou deveriam ser), o seguinte também funcionará.

abs(q1.dot(q2)) > 1-EPS

onde o EPS é um fator de correção para permitir pequenos erros devido à precisão limitada do ponto flutuante. Se (e somente se) os dois quaternions representam a mesma orientação q1 = +- q2, então e assim q1.dot(q2) = +- 1. Se você deseja garantir que eles tenham a mesma rotação (em vez de apenas orientação), remova o abs.

falstro
fonte
@bogglez true. Estava oculto no texto tl; dr. :)
falstro
+1, bastante elegante e, talvez até mais numericamente eficiente do que minha resposta (desde que as operações SIMD sejam usadas :)).
Teodron 16/05
Qual é a justificativa matemática para isso?
Fabian789
Justificativa "matemática" (entre aspas, não sou um matemático :)): dois vetores de comprimento unitário têm produto de ponto (também conhecido como produto interno) que é 0 se forem verticais entre si, 1 * 1 = 1 se estiverem apontando exatamente o mesma direcção, e 1 * 1 * cos (phi), no caso geral, com o seu ângulo phi ...
NTG
2

Os quaternions são armazenados como 4 carros alegóricos ou duplos, geralmente chamados x, y, z e w, onde os três primeiros representam um eixo ew o grau de rotação em torno desse eixo.

Uma abordagem ingênua seria apenas comparar esses números de dois quaternions pela igualdade. No entanto, como os cálculos de ponto flutuante envolvem um erro, você deve pelo menos usar um erro, geralmente chamado eps (para epsilon) e comparar cada componente como

    double const eps = 1e-12; // some error threshold
    abs(quat1_x - quat2_x) < eps // similar enough?
    // repeat for other values..

Um teste melhor seria calcular o produto escalar dos dois quaternions e testar se está próximo de 1,0. Você deve procurar a equação de quaternions com sin e cos e apenas pontuar dois quaternions, depois deve ver rapidamente por que isso funciona.

bogglez
fonte
0

Com base em todas as sugestões para usar Dot e eps, descobri que usando (em unidade):

Mathf.Approximately(Mathf.Abs(Quaternion.Dot(transform.rotation, to)), 1.0f)

funcionou bem sem eu ter que tomar uma decisão pelo tamanho de eps.

Sakull284
fonte