Je programme des cartes personnalisées Starcraft 2 et j'ai obtenu des programmes mathématiques en 3D. Actuellement, j'essaie de créer et de faire pivoter un point autour d'un axe arbitraire, donné par x, y et z (le vecteur xyz est normalisé).
J'ai beaucoup essayé et lu beaucoup de choses sur Internet, mais je n'arrive pas à comprendre comment cela fonctionne correctement. Mon script actuel (vous ne connaissez probablement pas la langue, mais ce n'est rien de spécial) est le résultat de tout casser pendant des heures (ne fonctionne pas correctement):
point CP;
fixed AXY;
point D;
point DnoZ;
point DXY_Z;
fixed AZ;
fixed LXY;
missile[Missile].Angle = (missile[Missile].Angle + missile[Missile].Acceleration) % 360.0;
missile[Missile].Acceleration += missile[Missile].AirResistance;
if (missile[Missile].Parent > -1) {
D = missile[missile[Missile].Parent].Direction;
DnoZ = Point(PointGetX(D),0.0);
DXY_Z = Normalize(Point(SquareRoot(PointDot(DnoZ,DnoZ)),PointGetHeight(D)));
AZ = MaxF(ACos(PointGetX(DXY_Z)),ASin(PointGetY(DXY_Z)))+missile[Missile].Angle;
DnoZ = Normalize(DnoZ);
AXY = MaxF(ACos(PointGetX(DnoZ)),ASin(PointGetY(DnoZ)));
CP = Point(Cos(AXY+90),Sin(AXY+90));
LXY = SquareRoot(PointDot(CP,CP));
if (LXY > 0) {
CP = PointMult(CP,Cos(AZ)/LXY);
PointSetHeight(CP,Sin(AZ));
} else {
CP = Point3(0.0,0.0,1.0);
}
} else {
CP = Point(Cos(missile[Missile].Angle),Sin(missile[Missile].Angle));
}
missile[Missile].Direction = Normalize(CP);
missile[Missile].Position = PointAdd(missile[Missile].Position,PointMult(missile[Missile].Direction,missile[Missile].Distance));
Je n'arrive pas à me concentrer sur les mathématiques. Si vous pouvez l'expliquer en termes simples qui seraient la meilleure solution, un code coupé serait également bon (mais pas tout à fait aussi utile, car je prévois de faire plus de trucs 3D à l'avenir).
http://en.wikipedia.org/wiki/Rotation_matrix . Regardez sous la section Matrice de rotation de l'axe et de l'angle . Pour votre commodité, voici la matrice dont vous avez besoin. C'est un peu poilu. thêta est l'angle et ux, uy et uz sont les composantes x, y et z du vecteur d'axe normalisé normalisé
Si vous ne comprenez pas les matrices et les vecteurs, postez-les et je vous aiderai.
Une méthode utile pour faire de telles rotations est de les faire avec quaternions . En pratique, je les ai trouvés plus faciles à utiliser et j'ai l'avantage supplémentaire d'éviter Gimbal lock .
Ici est une belle promenade qui explique comment et pourquoi ils sont utilisés pour la rotation autour d'un axe arbitraire (c'est la réponse à la question de l'utilisateur). C'est un niveau un peu plus élevé et ce serait bien pour quelqu'un qui est nouveau dans l'idée, donc je recommande de commencer par là.
Mise à jour pour éviter la corrosion des liens
Le texte du site lié:
Comme vous l'avez sans doute déjà conclu, la rotation autour de l'axe passant par l'Origine et un point (a,b,c)
Sur la sphère unitaire en trois dimensions est une transformation linéaire, et peut donc être représentée par une multiplication matricielle. Nous donnerons une méthode très lisse pour déterminer cette matrice, mais pour apprécier la compacité de la formule, il sera sage de commencer par quelques remarques.
Les rotations en trois dimensions sont des transformations linéaires assez spéciales, notamment parce qu'elles préservent les longueurs des vecteurs et aussi (lorsque deux vecteurs sont tournés) les angles entre les vecteurs. De telles transformations sont appelées "orthogonales" et elles sont représentées par des matrices orthogonales:
M M' = I
où nous désignons commodément la transposition par '. En d'autres termes, la transposition d'une matrice orthogonale est son inverse.
Considérez les données nécessaires pour définir la transformation. Vous avez déjà donné une notation pour l'axe de rotation, ai + bj + ck
, Supposé commodément être un vecteur unitaire. La seule autre donnée est l'angle de rotation, que, faute d'un caractère plus naturel, je désignerai par r (pour rotation?) Et que nous supposerons être donné en radians.
Maintenant, les rotations sont en fait un peu spéciales, même parmi les transformations orthogonales, et en fait, elles sont aussi appelées transformations orthogonales spéciales (ou matrices) en raison de leur propriété d'être "préservant l'orientation". Comparez-les avec des réflexions, qui préservent également la longueur et l'angle, et vous constaterez que la caractéristique géométrique de la préservation de l'orientation (ou de la "main-d'oeuvre" si vous préférez) a une contrepartie numérique dans le déterminant de la matrice. La matrice d'une rotation a le déterminant 1, tandis que la matrice d'une réflexion a le déterminant -1. Il s'avère que le produit (ou la composition) de deux rotations est à nouveau une rotation, ce qui concorde avec le fait que le déterminant d'un produit est le produit des déterminants (ou 1 dans le cas d'une rotation).
Nous pouvons maintenant décrire une approche étape par étape que l'on pourrait suivre pour construire la matrice souhaitée (avant de raccourcir tout le processus et de passer à la réponse!). Considérons d'abord une étape dans laquelle nous faisons pivoter le vecteur unitaire:
u = ai + bj + ck
de sorte qu'il coïncide avec l'un des vecteurs unitaires "standard", peut-être k (l'axe z positif). Maintenant, nous savons comment tourner autour de l'axe z; il s'agit de faire la transformation 2x2 habituelle sur les seules coordonnées x, y:
cos(r) sin(r) 0
M = -sin(r) cos(r) 0
0 0 1
Enfin, nous devons "défaire" cette rotation initiale qui a conduit u à k, ce qui est facile car l'inverse de cette transformation est (rappelons-le) représenté par la transposition matricielle. En d'autres termes, si la matrice R représente une rotation prenant u à k, alors R 'prend k à u, et nous pouvons écrire la composition de transformations comme ceci:
R' M R
On vérifie facilement que ce produit de matrices, multiplié par u, redonne u:
R' M R u = R' M k = R' k = u
Il s'agit donc bien d'une rotation autour de l'axe défini par u.
Un avantage de cette expression est qu'elle sépare proprement la dépendance de M sur l'angle r de la dépendance de Q et Q 'sur le vecteur "axe" u. Cependant si nous devons effectuer les calculs en détail, nous aurons évidemment beaucoup de multiplication matricielle à faire.
Donc, au raccourci. Il s'avère que lorsque toute la poussière se dépose, la multiplication entre les rotations est isomorphe à la multiplication des quaternions unitaires. Les quaternions, au cas où vous ne les auriez pas vus auparavant, sont une sorte de généralisation à quatre dimensions de nombres complexes. Ils ont été "inventés" par William Hamilton en 1843:
[Sir William Rowan Hamilton] http://www-gap.dcs.st-and.ac.uk/~history/Mathematicians/Hamilton.html
et les programmeurs graphiques 3D d'aujourd'hui lui sont très chers.
Chaque unité quaternion q = q0 + q1*i + q2*j + q3*k
Définit alors une matrice de rotation:
(q0² + q1² - q2² - q3²) 2(q1q2 - q0q3) 2(q1q3 + q0q2)
Q = 2(q2q1 + q0q3) (q0² - q1² + q2² - q3²) 2(q2q3 - q0q1)
2(q3q1 - q0q2) 2(q3q2 + q0q1) (q0² - q1² - q2² + q3²)
Pour vérifier que Q est une matrice orthogonale, ie. que Q Q' = I
, signifie essentiellement que les lignes de Q forment une base orthonormée. Ainsi, par exemple, la première ligne doit avoir une longueur 1:
(q0² + q1² - q2² - q3²)² + 4(q1q2 - q0q3)² + 4(q1q3 + q0q2)²
= (q0² + q1² - q2² - q3²)² + 4(q1q2)² + 4(q0q3)² + 4(q1q3)² + 4(q0q2)²
= (q0² + q1² + q2² + q3²)²
= 1
et les deux premières lignes doivent avoir le produit scalaire zéro:
[ (q0² + q1² - q2² - q3²), 2(q1q2 - q0q3), 2(q1q3 + q0q2) ]
* [ 2(q2q1 + q0q3), (q0² - q1² + q2² - q3²), 2(q2q3 - q0q1) ]
= 2(q0² + q1² - q2² - q3²)(q2q1 + q0q3)
+ 2(q1q2 - q0q3)(q0² - q1² + q2² - q3²)
+ 4(q1q3 + q0q2)(q2q3 - q0q1)
= 4(q0²q1q2 + q1²q0q3 - q2²q0q3 - q3²q2q1)
+ 4(q3²q1q2 - q1²q0q3 + q2²q0q3 - q0²q2q1)
= 0
On peut aussi montrer en général que det(Q) = 1
, et donc que Q est vraiment une rotation.
Mais autour de quel axe est la rotation Q? Et sous quel angle? Eh bien, étant donné l'angle r et le vecteur unitaire:
u = ai + bj + ck
comme précédemment, le quaternion correspondant est:
q = cos(r/2) + sin(r/2) * u
= cos(r/2) + sin(r/2) ai + sin(r/2) bj + sin(r/2) ck
Ainsi avec:
q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c,
nous pouvons obtenir la propriété souhaitée que la multiplication par Q "corrige" u:
Q u = u
Plutôt que de passer à travers l'algèbre de longue haleine, faisons un exemple simple.
Soit u = 0i + 0.6j + 0.8k
Notre vecteur unitaire et r = pi notre angle de rotation.
Alors le quaternion est:
q = cos(pi/2) + sin(pi/2) * u
= 0 + 0i + 0.6j + 0.8k
et la matrice de rotation:
-1 0 0
Q = 0 -0.28 0.96
0 0.96 0.28
Dans ce cas concret, il est facile de vérifier que Q Q '= I et det (Q) = 1.
Nous calculons également que:
Q u = [ 0, -0.28*0.6 + 0.96*0.8, 0.96*0.6 + 0.28*0.8 ]'
= [ 0, 0.6, 0.8 ]'
= u
c'est à dire. le vecteur unitaire u définit l'axe de rotation car il est "fixé" par Q.
Enfin, nous illustrons que l'angle de rotation est pi (ou 180 degrés) en considérant comment Q agit sur le vecteur unitaire dans la direction de l'axe x positif, qui est perpendiculaire à u:
i + 0j + 0k, or as a vector, [ 1, 0, 0 ]'
Alors Q [ 1, 0, 0 ]' = [-1, 0, 0 ]'
Qui est la rotation de [1, 0, 0] 'à travers l'angle pi autour de u.
Comme référence pour cette représentation des rotations par quaternions et quelques méthodes de représentation supplémentaires (et à quoi elles servent), voir les détails ici:
[Représentant des rotations 3D] http://gandalf-library.sourceforge.net/tutorial/report/node125.html
Étant donné l'angle r en radians et le vecteur unitaire u = ai + bj + ck ou [a, b, c] ', définissez:
q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c
et construire à partir de ces valeurs la matrice de rotation:
(q0² + q1² - q2² - q3²) 2(q1q2 - q0q3) 2(q1q3 + q0q2)
Q = 2(q2q1 + q0q3) (q0² - q1² + q2² - q3²) 2(q2q3 - q0q1)
2(q3q1 - q0q2) 2(q3q2 + q0q1) (q0² - q1² - q2² + q3²)
La multiplication par Q effectue alors la rotation souhaitée, et notamment:
Q u = u
Pour effectuer une rotation 3D, il vous suffit de décaler le point de rotation par rapport à l'origine et de faire une rotation séquentielle autour de chaque axe, en stockant les résultats entre chaque rotation d'axe pour une utilisation avec l'opération de rotation suivante. L'algorithme se présente comme suit:
Décalez le point sur l'origine.
Point of Rotation = (X1, Y1, Z1)
Point Location = (X1+A, Y1+B, Z1+C)
(Point Location - Point of Rotation) = (A, B, C).
Effectuez une rotation autour de l'axe Z.
A' = A*cos ZAngle - B*sin ZAngle
B' = A*sin ZAngle + B*cos ZAngle
C' = C.
Ensuite, effectuez une rotation autour de l'axe Y.
C'' = C'*cos YAngle - A'*sin YAngle
A'' = C'*sin YAngle + A'*cos YAngle
B'' = B'
Effectuez maintenant la dernière rotation, autour de l'axe X.
B''' = B''*cos XAngle - C''*sin XAngle
C''' = B''*sin XAngle + C''*cos XAngle
A''' = A''
Enfin, ajoutez ces valeurs au point de rotation d'origine.
Rotated Point = (X1+A''', Y1+B''', Z1+C''');
J'ai trouvé cela lien très utile. Il définit comment effectuer des rotations individuelles autour des axes X, Y et Z.
Mathématiquement, vous pouvez définir l'ensemble des opérations comme suit:
Voici ce que vous pouvez utiliser pour faire pivoter n'importe quel axe, que ce soit x, y ou z. Rx, Ry et Rz désignent respectivement la rotation autour des as x, y, z.
Pour les rotations autour d'un axe arbitraire en trois dimensions avec des matrices, j'ai une page ici . L'explication et la dérivation liées des matrices ( ici ) incluent la matrice de rotation/traduction suivante. C'est la matrice qui donne le résultat de la rotation du point (x, y, z) autour de la ligne passant par (a, b, c) avec le vecteur de direction ⟨u, v, w⟩ par l'angle thêta.
Le résultat est ce point en trois dimensions:
La page comprend un lien vers un téléchargement de code source. Si vous voulez faire des rotations de manière interactive, vous pouvez le faire sur ce site . Essayez l'exemple de lien de rotation pour avoir une idée de ce qui se passe.
Une façon très soignée de programmer cela, surtout si vous êtes capable de fonctionner avec des matrices (comme dans Matlab) est la Rodrigues 'Rotation Formula .
La formule crée une matrice de rotation autour d'un axe défini par le vecteur unitaire d'un angle en utilisant une équation très simple:
Où est la matrice d'identité et est une matrice donnée par les composants du vecteur unitaire :
Notez qu'il est très important que le vecteur est un vecteur unitaire, c'est-à-dire la norme de doit être 1.
Vous pouvez vérifier que pour l'axe euclidien, la formule est exacte comme celles trouvées sur Wikipédia et publiées ici par Aakash Anuj.
J'utilise cette formule uniquement pour les rotations depuis que je l'ai découverte. J'espère que cela aide à n'importe qui.