Como posso girar sobre um ponto arbitrário em 3D (em vez da origem)?

15

Eu tenho alguns modelos que eu quero girar usando quaternions da maneira normal, exceto que em vez de rotação sobre a origem, eu quero que ele seja ligeiramente deslocado. Eu sei que você não diz, no espaço 3D, que gira em torno de um ponto; você diz que gira em torno de um eixo. Então, eu estou visualizando como girando sobre um vetor cuja cauda não está posicionada na origem local.

Todas as transformações afins no meu mecanismo de renderização / física são armazenadas usando SQT (escala, quaternário, tradução; uma idéia emprestada do livro Game Engine Architecture ). Então, construo uma matriz de cada quadro desses componentes e passo-a para o vertex shader. Nesse sistema, a tradução é aplicada, depois a escala e a rotação.

Em um caso específico, preciso converter um objeto no espaço do mundo, dimensioná-lo e girá-lo sobre um vértice não centralizado na origem local do objeto.

Pergunta: Dadas as restrições do meu sistema atual descrito acima, como posso obter uma rotação local centrada em um ponto diferente da origem? Voto automático para quem pode descrever como fazer isso usando apenas matrizes também :)

entalhe
fonte
Quaternions já descrevem uma rotação em torno de um eixo arbitrário; você tem problemas para construir esse quaternion a partir dos dados que possui?
Martin Sojka
3
Sério, as pessoas que aprovaram as respostas realmente as lêem ? Dei um método, uma fórmula eficiente e até uma demonstração. No entanto, a única resposta votada, apesar de fornecer algumas informações valiosas (e também algumas claramente erradas), não apresenta nenhuma delas e nem sequer responde à pergunta!
21711 Samu Hocevar
@MartinSojka, trata-se de um ponto arbitrário, não de um eixo arbitrário.
notlesh
@ SamHocevar Ambas as suas respostas foram úteis. Eu escolhi o seu porque era mais completo e me ajudou a chegar a uma solução. Obrigado a ambos.
notlesh
Ah, desculpe - eu confundi com Quaternions duplos (eles também oferecem a tradução "de graça"). Vou escrever o que quis dizer em uma resposta mais tarde; talvez outros achem útil, especialmente porque você pode reduzir seus três componentes para apenas um - embora um pouco mais complexo.
Martin Sojka

Respostas:

17

Em resumo

Você só precisa alterar T no seu formulário SQT.

Substitua o vetor de conversão vpor v' = v-invscale(p-invrotate(p))onde vestá o vetor de conversão inicial, pé o ponto em torno do qual você deseja que a rotação ocorra invrotatee invscalesão as inversas de sua rotação e escala.

Demonstração rápida

Seja po ponto em torno do qual você aplica a rotação r. Let sSer seus parâmetros de escala e vseu vetor de tradução. A transformação final da matriz é em T(p)R(r)T(-p)S(s)T(v)vez de R(r)S(s)T(v).

O que você deseja são novos parâmetros de transformação v', r'e s'tal que a transformação final da matriz seja R(r')S(s')T(v')e tenhamos:

T(p)R(r)T(-p)S(s)T(v) = R(r')S(s')T(v')

O comportamento no infinito indica que os parâmetros de rotação e os parâmetros de escala não podem mudar (isso pode ser demonstrado). Temos assim r = r'e s = s'. O único parâmetro que falta é v', portanto , seu novo vetor de tradução:

T(p)R(r)T(-p)S(s)T(v) = R(r)S(s)T(v')

Se essas matrizes são iguais, seus inversos são iguais:

T(-v)S(-s)T(p)R(-r)T(-p) = T(-v')S(-s)R(-r)

Isso vale especialmente para a origem O:

T(-v)S(-s)T(p)R(-r)T(-p)O = T(-v')S(-s)R(-r)O

Escalar e girar a origem produz a origem, e obtemos:

T(-v)S(-s)T(p)R(-r)(-p) = -v'

v'é o novo vetor de tradução que você está procurando e permite armazenar sua transformação no formato SQT. Provavelmente é possível simplificar o cálculo; mas pelo menos o armazenamento necessário não é aumentado.

sam hocevar
fonte
Obrigada pelo esclarecimento. BTW, você conhece algum recurso em que eu possa ler mais sobre truques de representação SQT?
Pachanga 5/05
Corrija-me se eu estiver errado, mas parece que outra solução seria armazenar seu Quaternion normalmente e, se você precisar contabilizar a tradução em torno de um ponto / eixo arbitrário, construa a matriz Q com isso incluído, basta extrair o vetor de tradução a partir desta matriz (última coluna, geralmente) e adicione-a ao vetor Translation de objetos e, em seguida, jogue fora sua matriz temporária.
precisa saber é o seguinte
15

Todas as fórmulas rotacionais canônicas usadas para derivar suas matrizes de rotação são para rotação sobre a origem. Se você preferir aplicar essa rotação em torno de um ponto específico, primeiro desloque a origem - ou, equivalentemente, mova o objeto para que o ponto sobre o qual você deseja girar esteja na origem.

Considere o caso 2D primeiro, porque é mais simples e a técnica é dimensionada. Se você tivesse um cubo de largura 2 centrado na origem e desejasse girá-lo 45 graus sobre o centro, isso seria uma aplicação trivial da matriz de rotação 2D .

Mas se você deseja girá-lo em torno do canto superior direito (localizado em 1,1), primeiro você precisa traduzi-lo para que o canto fique na origem. Isso pode ser conseguido com uma tradução de -1,-1. Em seguida, você pode girar o objeto como antes, mas você deve segui-lo traduzindo-o de volta (por 1,1). Portanto, em geral, para obter a matriz de rotação Rpara uma rotação de rcerca de ponto, Pfaça o seguinte:

R = translate(-P) * rotate(r) * translate(P)

onde translatee rotatesão as matrizes canônicas de translação / rotação, respectivamente. Por acaso, isso é dimensionado trivialmente para 3D, que também é a exceção de fornecer um eixo para a rotação - você sempre pode escolher as matrizes canônicas de rotação dos eixos X, Y ou Z, mas isso seria tedioso. Você deseja usar a matriz de rotação eixo-ângulo arbitrária . Sua final Rem 3D é assim:

R = translate(-P) * rotate(a,r) * translate(P)

onde aé um vetor de unidade que representa o eixo de rotação e Pagora é um ponto 3D no espaço do modelo que representa o ponto de rotação.

Por acaso, os quaternions podem ser convertidos de e para representações matriciais, para que você possa fazer sua concatenação dessa maneira, se assim desejar. Ou você pode simplesmente deixar tudo como matrizes (os quaternions têm algumas vantagens interessantes, como facilitar a interpolação de uma maneira sã, mas se você precisa ou não disso é com você).

Além disso:

Então, eu estou visualizando como girando sobre um vetor cuja cauda não está posicionada na origem local.

A rigor, enquanto vetores podem ser usados ​​para representar posições, considerando-os como deslocamentos de uma origem, os vetores não têm posições em si, portanto, é um pouco incomum visualizá-los como tais.


fonte
Obrigado, esta é uma boa resposta. Porém, ele não se encaixa nas restrições do meu sistema. Eu deveria ter incluído na minha pergunta "é possível fazer isso, dadas essas restrições?", E acho que a resposta é que não, pois isso requer duas traduções e eu apenas prevejo uma. Isso é uma falha inevitável do uso do SQT como representação de transformações afins?
notlesh
Cabe perfeitamente dentro de suas restrições. A matriz R (produzida como translate-rotate-translate-back) é sua matriz de rotação. Substitua Q por R no seu sistema "SQT" para que você tenha o paradigma mais comum de escala de rotação-conversão e pronto. Essa última conversão é independente das duas traduções intermediárias feitas para produzir a rotação desejada.
Você está propondo que eu substitua o quaternion por uma matriz? São mais 12 bytes por objeto (8 se eu o armazenar como uma matriz 4x3)! Vou silenciar o otimista em mim e dar um giro nisso. (Na verdade, isso provavelmente nem chegará a um aumento de 2kb na área ocupada ...) Obrigado por suas respostas.
notlesh 1/11/11
Você pode - você também pode converter entre eles, construindo o quaternion de rotação dessa maneira e conectando-se novamente ao seu sistema existente.
11
@ SamHocevar: Como alternativa, qualquer combinação dos mesmos pode ser expressa como um único parafuso .
Martin Sojka