GLM: Ângulos de Euler para Quaternion

12

Espero que você conheça a Matemática GL ( GLM ), porque eu tenho um problema, não posso quebrar:

Eu tenho um conjunto de ângulos de Euler e preciso executar uma interpolação suave entre eles. A melhor maneira é convertê-los em Quaternions e aplicar o alrogirthm SLERP.

O problema que tenho é como inicializar glm :: quaternion com Euler Angles, por favor?

Eu li a documentação GLM várias vezes, mas não consigo achar apropriado Quaternion constructor signature, isso levaria três ângulos de Euler. A mais próxima que encontrei é a função angleAxis () , assumindo o valor do ângulo e um eixo para esse ângulo. Observe, por favor, o que estou procurando de uma maneira, como analisar RotX, RotY, RotZ.


Para sua informação, esta é a assinatura da função angleAxis () acima mencionada :

detail::tquat< valType > angleAxis (valType const &angle, valType const &x, valType const &y, valType const &z)
Bunkai.Satori
fonte

Respostas:

13

Não conheço o GLM, mas, na ausência de uma função para converter diretamente dos ângulos de Euler em quaternions, você pode usar as funções "rotação em torno de um eixo" (como "angleAxis").

Veja como (pseudocódigo):

Quaternion QuatAroundX = Quaternion( Vector3(1.0,0.0,0.0), EulerAngle.x );
Quaternion QuatAroundY = Quaternion( Vector3(0.0,1.0,0.0), EulerAngle.y );
Quaternion QuatAroundZ = Quaternion( Vector3(0.0,0.0,1.0), EulerAngle.z );
Quaternion finalOrientation = QuatAroundX * QuatAroundY * QuatAroundZ;

(Ou talvez seja necessário alternar essas multiplicações de quaternion, dependendo da ordem em que suas rotações do ângulo de euler se destinam a ser aplicadas)

Como alternativa, ao examinar a documentação do GLM, parece que você pode converter ângulos de euler -> matrix3 -> quaternion da seguinte maneira:

toQuat( orient3( EulerAngles ) )
Trevor Powell
fonte
boa resposta porque é menos ambígua quanto à ordem de aplicação.
Richard Fabian
@ Trevor: +1, Oi Trevor, obrigado pela sua boa resposta. Parece a solução mais prática aqui. Eu posso alternar facilmente entre a ordem de multiplicação da rotação. Possivelmente, o número de combinações é a razão pela qual a conversão de ângulo de Euler em quaterion não está disponível no GLM.
Bunkai.Satori
Embora todas as respostas sejam boas e valiosas, na minha opinião, essa é a mais prática. Gostaria de marcar como Resposta Aceita .
Bunkai.Satori
@Trevor: No Quaternion finalOrientation = QuatAroundX * QuatAroundY * QuatAroundZ ;, que tipo de multiplicação você quis dizer? Estou surpreso que o GLM não sobrecarregue operator *a multiplicação de Quaternion, portanto, possivelmente, terei que realizar a multiplicação manualmente .
Bunkai.Satori
3
@Bunkai, o conceito de multiplicação de quaternário é semelhante à multiplicação de matrizes, não é um ponto nem produto cruzado. Se você deseja entender o uso de quaternions, acostume-se a matrizes e entenda ângulos de eixo, o conceito básico deles é bastante semelhante a quaternions, a matemática é um pouco mais avançada, mas depois de entender os ângulos de eixo, os quaternions não são mais longe.
Maik Semder
16
glm::quat myquaternion = glm::quat(glm::vec3(angle.x, angle.y, angle.z));

Onde angleestá um passoglm::vec3 contendo , guinada, rolo, respectivamente.

PS. Em caso de dúvida, basta ir aos cabeçalhos e procurar. A definição pode ser encontrada em glm / gtc / quaternion.hpp:

explicit tquat(tvec3<T> const & eulerAngles) {
        tvec3<T> c = glm::cos(eulerAngle * value_type(0.5));
    tvec3<T> s = glm::sin(eulerAngle * value_type(0.5));

    this->w = c.x * c.y * c.z + s.x * s.y * s.z;
    this->x = s.x * c.y * c.z - c.x * s.y * s.z;
    this->y = c.x * s.y * c.z + s.x * c.y * s.z;
    this->z = c.x * c.y * s.z - s.x * s.y * c.z;    
}

Para onde quaté um typedef flutuante tquat.

deceleratedcaviar
fonte
Isso é bastante ambíguo, em que ordem eles se aplicariam? Eulers são rotações ordenadas e o construtor de quaternion aqui não parece se importar com isso.
Richard Fabian
A definição da função é exatamente a mesma que a sua; Eu postei na minha resposta, se isso importasse.
deceleratedcaviar
não a ordem dos argumentos, a ordem de aplicação da rotação. Minha resposta contém o pedido XYZ, retirado do artigo da wikipedia, no entanto, usamos o pedido ZYX do aplicativo na minha antiga empresa e o YZX na atual. o ângulo x ainda é o primeiro valor na lista de vetores / argumentos em todos os casos, mas a transformação resultante real não é a mesma.
Richard Fabian
Corrigi minha resposta para o rotationQuat, para que você possa ver como poderia facilmente alterar a ordem. Por padrão, ele aceita XYZ, mas você pode facilmente mudar isso.
deceleratedcaviar
2
-1 para não mencionar a ordem de rotação, o que é muito importante para a questão
Maik Semder
7

A solução está na wikipedia: http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles

usando isso:

sx = sin(x/2); sy = sin(y/2); sz = sin(z/2);
cx = cos(x/2); cy = cos(y/2); cz = cos(z/2);

q( cx*cy*cz + sx*sy*sz,
   sx*cy*cz - cx*sy*sz,
   cx*sy*cz + sx*cy*sz,
   cx*cy*sz - sx*sy*cz ) // for XYZ application order

q( cx*cy*cz - sx*sy*sz,
   sx*cy*cz + cx*sy*sz,
   cx*sy*cz - sx*cy*sz,
   cx*cy*sz + sx*sy*cz ) // for ZYX application order

Construtores para um quaternion, dado um Euler (onde a aplicação da rotação é XYZ ou ZYX). No entanto, são apenas duas das seis combinações possíveis de ângulos de Euler. Você realmente precisa descobrir em que ordem os ângulos de Euler são construídos ao converter para transformar a matriz. Somente então a solução pode ser definida.

Na empresa antiga em que trabalhei, tínhamos Z como encaminhador (como a maioria das placas gráficas); portanto, o pedido de aplicativo era ZYX; na minha empresa atual, o eixo Y é encaminhado e Z está ativo; portanto, o pedido é YZX. Essa ordem é a ordem em que você multiplica seus quaternions para gerar sua transformação final, e a ordem que importa para rotações é que as multiplicações não são comutativas.

Richard Fabian
fonte
1
+1, oi e obrigado pela ótima resposta. Enquanto uso o OpenGL , o valor Z sai da tela. Na minha aplicação, eu executo a ordem de multiplicação de ZYX . Originalmente, eu pensei que o GLM tem essa funcionalidade disponível, mas, como eu ainda não a implementou, uma alternativa é criar a conversão manualmente , como você recomenda.
Bunkai.Satori
Esta é a melhor resposta aqui.
plasmacel
1
vec3 myEuler (fAngle[0],fAngle[1],fAngle[2]);
glm::quat myQuat (myEuler);

O ângulo deve estar em radianos!

Carlos
fonte
2
Isso foi uma piada? Ou você simplesmente não leu as outras respostas (especialmente as de Daniel)?
Chris diz Reinstate Monica