Como você pode extrair a orientação de uma matriz de transformação?

10

Eu tenho uma matriz de transformação 4x4 M e quero descobrir a forma de uma esfera quando transformada por M. (A esfera está na origem e tem o raio 1.)

Eu sei que posso encontrar o centro apenas multiplicando M por (0,0,0,1).

No entanto, o raio se torna um problema, pois M pode esmagar e girar a esfera. Como posso descobrir o (s) novo (s) raio (s) do elipsóide resultante? Existe alguma maneira de descobrir a orientação?

Mais especificamente, preciso saber o tamanho da esfera delimitadora que envolveria a esfera transformada. Em outras palavras, qual é o máximo de | M * V - M * (0,0,0,1) |, onde V é um vetor unitário (um ponto na esfera original).

CaptainCodeman
fonte
11
Você não pode simplesmente calcular o comprimento dos vetores de eixos transformados? (3 colunas da parte de rotação da sua matriz) A esfera delimitadora teria um raio igual ao comprimento do vetor mais longo.
7243 Bart
Não, não acho que esteja correto. A direção mais longa pode não estar alinhada ao eixo. (Imagine se você a
esmagasse
Hmm, não tenho certeza se isso importa. Se eu conseguir me convencer, escreverei uma resposta ainda hoje. ;)
Bart
O problema é que, se você transformar a ESCALA, os vetores base da matriz M não precisam permanecer ORTOGONAIS um com o outro.
GPUquant

Respostas:

6

Matematicamente, a quantidade que você está perguntando é chamada de norma do operador . Infelizmente, não existe uma fórmula simples para isso. Se for uma transformação afim totalmente geral - por exemplo, se puder ter uma combinação arbitrária de rotações e escalas não uniformes, em qualquer ordem -, receio que não haja nada a não ser usar a decomposição de valores singular . Se você aplicar SVD à sua matriz, o maior valor singular será o raio máximo do elipsóide resultante. Os outros valores singulares também serão seus outros dois raios, e o procedimento SVD também pode extrair a orientação dos eixos para você.

A implementação de SVD não é para os fracos de coração, pois envolve a busca de valores próprios. Se tudo o que você deseja são os próprios valores singulares, elas são as raízes quadradas dos valores próprios de M ^ T * M. Portanto, se você tem um solucionador de valores próprios 3x3 à mão ou não se importa em escrever um, pode usá-lo. Se você deseja extrair também as orientações dos eixos, fica mais envolvido, pois você também precisa encontrar vetores próprios. Nesse artigo da Wikipedia, há uma lista de links para bibliotecas para fazer SVD, um dos quais você pode usar em seu projeto.

Se a forma da sua matriz for restrita de forma que a escala não uniforme aconteça no máximo uma vez e seja a primeira transformação aplicada, ou seja, seja a mais correta quando você estiver usando vetores de coluna, poderá simplificá-lo para apenas observar os comprimentos dos vetores de eixos transformados. Somente nesse caso - ou seja, uma única escala não uniforme seguida de qualquer sequência de rotações, reflexões e escalas uniformes - observar apenas os vetores dos eixos fornecerá a resposta certa.

Nathan Reed
fonte
Obrigado, agradeço a resposta detalhada. Onde a decomposição fornecida na outra resposta falha em funcionar?
9388 CaptainCodeman
2
@CaptainCodeman A outra resposta está apenas olhando os vetores de eixos transformados (ou seja, as colunas da matriz), como o que descrevi no meu terceiro parágrafo. Falha no caso de haver uma escala não uniforme após uma rotação, pois a escala não se aplica ao longo dos eixos originais.
Re
2

Talvez extraia fatores de escala da matriz e use o valor máximo de seus componentes. Usando a matriz SRT (Scale-Rotation-Translation), você pode fazer o seguinte:

glm::mat4 m = ...;
// Extract col vectors of the matrix
glm::vec3 col1(m[0][0], m[0][1], m[0][2]);
glm::vec3 col2(m[1][0], m[1][1], m[1][2]);
glm::vec3 col3(m[2][0], m[2][1], m[2][2]);
//Extract the scaling factors
glm::vec3 scaling;
scaling.x = glm::length(col1);
scaling.y = glm::length(col2);
scaling.z = glm::length(col3);

float scaleFactor = MAX(scaling.x, MAX(scaling.y, scaling.z));

(baseado em http://wklej.org/id/950061/ - o nome é decomposeTRS e não decomposeSRT porque eu uso nomes na ordem em que as matrizes são multiplicadas no OpenGL).

Agora você pode multiplicar o raio da esfera original por scaleFactor e terá sua esfera delimitadora.

inverter
fonte