Comment puis-je faire pivoter un point arbitraire en 3D (au lieu de l'origine)?

15

J'ai certains modèles que je veux faire tourner en utilisant des quaternions de la manière normale, sauf qu'au lieu de faire une rotation autour de l'origine, je veux qu'il soit légèrement décalé. Je sais que vous ne dites pas, dans l'espace 3D, que vous tournez autour d'un point; vous dites que vous tournez autour d'un axe. Je le visualise donc comme tournant autour d'un vecteur dont la queue n'est pas positionnée à l'origine locale.

Toutes les transformations affines de mon moteur de rendu / physique sont stockées à l'aide de SQT (échelle, quaternion, traduction; une idée empruntée au livre Game Engine Architecture .) Je construis donc une matrice chaque image à partir de ces composants et la passe au vertex shader. Dans ce système, la translation est appliquée, puis l'échelle, puis la rotation.

Dans un cas spécifique, j'ai besoin de traduire un objet dans l'espace mondial, de le mettre à l'échelle et de le faire pivoter autour d'un sommet non centré sur l'origine locale de l'objet.

Question: Compte tenu des contraintes de mon système actuel décrites ci-dessus, comment puis-je réaliser une rotation locale centrée sur un point autre que l'origine? Upvote automatique à tous ceux qui peuvent décrire comment le faire en utilisant uniquement des matrices :)

notlesh
la source
Les quaternions décrivent déjà une rotation autour d'un axe arbitraire; avez-vous des problèmes pour construire un tel quaternion à partir des données dont vous disposez?
Martin Sojka
3
Sérieusement, les personnes qui ont répondu positivement pouvaient- elles les lire ? J'ai donné une méthode, une formule efficace et même une démonstration. Pourtant, la seule réponse positive, tout en fournissant des informations précieuses (et également des informations manifestement erronées), n'en contient aucune et ne répond même pas à la question!
sam hocevar
@MartinSojka, il s'agit d'un point arbitraire et non d'un axe arbitraire.
2011
@SamHocevar Vos deux réponses ont été utiles. J'ai choisi la vôtre parce qu'elle était plus approfondie et m'a aidée à trouver une solution. Merci à vous deux.
2011
Ah, désolé - je l'ai confondu avec les Dual Quaternions (ceux-ci vous donnent également la traduction "gratuitement"). J'écrirai ce que je voulais dire dans une réponse plus tard; peut-être que d'autres trouveraient cela utile, d'autant plus que vous pouvez réduire vos trois composants à un seul - quoique un peu plus complexe.
Martin Sojka

Réponses:

17

En bref

Il vous suffit de changer T dans votre formulaire SQT.

Remplacez le vecteur de translation vpar v' = v-invscale(p-invrotate(p))vest le vecteur de translation initial, pest le point autour duquel vous souhaitez que la rotation se produise, et invrotateet invscalesont les inverses de votre rotation et de votre échelle.

Démonstration rapide

Soit ple point autour duquel vous appliquez la rotation r. Soit svos paramètres d'échelle et vvotre vecteur de traduction. La transformation de matrice finale est T(p)R(r)T(-p)S(s)T(v)au lieu de R(r)S(s)T(v).

Ce que vous voulez, ce sont de nouveaux paramètres de transformation v', r'et s'tels que la transformation finale de la matrice soit R(r')S(s')T(v')et nous avons:

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

Le comportement à l'infini indique que les paramètres de rotation et les paramètres d'échelle ne peuvent pas changer (cela pourrait être démontré). Nous avons donc r = r'et s = s'. Le seul paramètre manquant est donc v'votre nouveau vecteur de traduction:

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

Si ces matrices sont égales, leurs inverses sont égales:

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

Cela est particulièrement vrai pour l'origine O:

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

La mise à l'échelle et la rotation de l'origine donne l'origine, on obtient ainsi:

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

v'est le nouveau vecteur de traduction que vous recherchez qui vous permet de stocker votre transformation sous forme SQT. Il est probablement possible de simplifier le calcul; mais au moins le stockage requis n'est pas augmenté.

sam hocevar
la source
Merci pour l'explication. BTW, connaissez-vous des ressources où je pourrais en savoir plus sur les astuces de représentation SQT?
pachanga
Corrigez-moi si je me trompe, mais il semble qu'une autre solution serait de stocker votre Quaternion normalement, et si vous devez tenir compte de la traduction autour d'un point / axe arbitraire, puis créez la matrice Q avec cela inclus, extrayez simplement le vecteur de traduction à partir de cette matrice (dernière colonne, généralement) et ajoutez-la au vecteur de traduction des objets, puis jetez votre matrice temporaire.
johnbakers
15

Toutes les formules de rotation canoniques utilisées pour dériver vos matrices de rotation sont destinées à la rotation autour de l'origine. Si vous souhaitez plutôt appliquer cette rotation autour d'un point spécifique, vous devez d'abord décaler l'origine - ou, de manière équivalente, déplacer l'objet de sorte que le point sur lequel vous souhaitez tourner se trouve à l'origine.

Considérons d'abord le cas 2D, car il est plus simple et la technique évolue. Si vous aviez un cube de largeur 2 centré sur l'origine et que vous vouliez le faire pivoter de 45 degrés autour de son centre, ce serait une application triviale de la matrice de rotation 2D .

Mais si à la place vous vouliez le faire pivoter autour de son coin supérieur droit (situé à 1,1), vous devriez d'abord le traduire pour que ce coin soit à l'origine. Cela peut être accompli avec une traduction de -1,-1. Ensuite, vous pouvez faire pivoter l'objet comme précédemment, mais vous devez suivre cela en le traduisant en arrière (par 1,1). Donc, en général, pour atteindre la matrice de rotation Rpour une rotation d' renviron un point, Pvous faites:

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

translateet rotatesont les matrices canoniques de translation / rotation, respectivement. En l'occurrence, cela évolue trivialement en 3D, à l'exception du fait de devoir également fournir un axe à la rotation - vous pouvez toujours choisir les matrices canoniques de rotation des axes X, Y ou Z, mais ce serait terne. Vous voudrez utiliser la matrice de rotation axe-angle arbitraire . Votre finale Ren 3D est donc:

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

aest un vecteur unitaire représentant l'axe de rotation et Pest maintenant un point 3D dans l'espace objet représentant le point de rotation.

En l'occurrence, les quaternions peuvent être convertis vers et à partir de représentations matricielles, vous pouvez donc effectuer votre concaténation de cette façon si vous le souhaitez. Ou vous pouvez simplement tout laisser sous forme de matrices (les quaternions ont de beaux avantages, comme être plus faciles à interpoler de manière saine, mais vous en avez besoin ou non).

Aussi:

Je le visualise donc comme tournant autour d'un vecteur dont la queue n'est pas positionnée à l'origine locale.

À strictement parler, alors que les vecteurs peuvent être utilisés pour représenter des positions en les considérant comme des déplacements par rapport à une origine, les vecteurs n'ont pas eux-mêmes de positions, il est donc un peu inhabituel d'en visualiser une en tant que telle.


la source
Merci, c'est une bonne réponse. Cela ne correspond pas aux contraintes de mon système. J'aurais dû inclure dans ma question "est-il possible de faire cela compte tenu de ces contraintes?" Et je pense que la réponse est que non, car cela nécessite deux traductions et je n'en prévois qu'une. Est-ce une lacune inévitable de l'utilisation du SQT comme représentation des transformations affines?
1er
Il s'intègre parfaitement dans vos contraintes. La matrice R (produite sous forme de translation-rotation-translation-retour) est votre matrice de rotation. Remplacez Q par R dans votre système "SQT" afin que vous ayez le paradigme d'échelle-rotation-traduction le plus courant, et vous avez terminé. Cette dernière translation est indépendante des deux traductions intermédiaires effectuées pour produire la rotation souhaitée.
Vous proposez de remplacer le quaternion par une matrice? C'est 12 octets de plus par objet (8 si je le stocke en tant que matrice 4x3)! Je vais cependant faire taire l'optimiste en moi et faire un tourbillon. (En fait, cela n'augmentera probablement même pas de 2 Ko l'empreinte ...) Merci pour vos réponses.
1er
Vous pouvez - vous pouvez également convertir entre eux, en construisant le quaternion de rotation de cette façon et en vous connectant à votre système existant.
1
@SamHocevar: Alternativement, toute combinaison de ceux-ci peut être exprimée comme une seule vis .
Martin Sojka