COMPOSER LES ROTATIONS

 

La méthode qu'on a utilisée pour déterminer la matrice de rotation autour de l'origine du repère (0,0,0) est générale. Voyons un peu ce qui se passe pour 2 rotations consécutives.

On fait une première rotation [R1] de "centre" C1 suivie d'une seconde [R2] de "centre" C2.

Un point P sera d'abord roté par [R1] en P1 puis par [R2] en P2. On écrit ce qui se passe :

1ère rotation : P1 = [R1]*P + C1 - [R1]*C1
2nde rotation : P2 = [R2]*P1 + C2 - [R2]*C2

On touille tout ça :

P2 = [R2]*([R1]*P + C1 - [R1]*C1) + C2 - [R2]*C2
P2 = ([R2]*[R1])*P - ([R2]*[R1])*C1 + [R2]*(C1-C2) + C2

On a vu comment on fait le produit de 2 matrices, j'appelle [S] le produit [R2]*[R1].

Au résultat, la composition de nos 2 matrices sera :

                 +------------------------------------+
                 |                                    |
                 |           P2 = [S]*P + D           |
                 |                                    |
                 |  avec :                            |
                 |    [S] = [R2]*[R1]                 |
                 |    D = C2 - [S]*C1 + [R2]*(C1-C2)  |
                 |                                    |
                 +------------------------------------+

Le premier résultat interressant est que 2 rotations consécutives des points d'un objet demandent autant de calculs qu'une seule. En effet, il faut toujours faire le produit d'une matrice par un vecteur et ajouter un vecteur translation pour tenir compte des "centres" de rotation.

T Le second, qui ne s'invente pas, est que l'inverse de [S] est = à [S]. Par conséquent, toutes les optimisations dont on a parlé plus haut sont toujours valables.

Enfin, comme les rotations conservent les longueurs, les 9 termes des matrices de rotations sont inférieurs ou égaux à 1 en valeur absolue.

Et quelque soit le nombre de rotations en cascade, cela reste vrai.

Pour faire bonne mesure, ils restent toujours vrai si on insère des translations entre des rotations.

Et pour illustrer cela, on va faire la rotation générale: un angle donné autour d'une axe quelconque.

Je vous passe le calcul, voici le résultat :

         |                                                            | 
         | Ux²+Ca*(1-Ux²)      Ux*Uy*(1-Ca)-Uz*Sa  Ux*Uz*(1-Ca)+Uy*Sa | 
   [R] = | Ux*Uy*(1-Ca)+Uz*Sa  Uy²+Ca*(1-Uy²)      Uy*Uz*(1-Ca)-Ux*Sa | 
         | Ux*Uz*(1-Ca)-Uy*Sa  Uy*Uz*(1-Ca)+Ux*Sa  Uz²+Ca*(1-Uz²)     | 
         |                                                            | 
                                                                        
   où :                                                                 
     Sa = sin(a), Ca = cos(a), a étant l'angle de rotation              
     Ux,Uy,Uz les coordonnées du vecteur UNITAIRE U qui défini la       
     direction de la droite autour de laquelle on tourne.               
     ATTENTION : inverser U et une rotation d'un angle a équivaut à une 
     rotation de -a.                                                    

Pour obtenir cette formule, on a fait les rotations de manière à amener le vecteur U coincidant avec Oz, puis on a fait tourner l'objet de son angle a autour de l'axe z'Oz. On a enfin effectué les rotations inverses qui ramènent U à "sa place" (l'axe z'Oz est totalement arbitraire, on aurait pu choisir n'importe quel autre axe).

Et une direction ne suffit pas pour caractériser une droite, [R] est la matrice de rotation pour une droite passant par l'origine. Gérer le cas de vecteur unitaire U et passant par un point C est exactement ce que l'on a fait jusqu'à présent :

T = [R]*P + C - [R]*C

Comme pour la « rotation des demomakers », il est possible de précalculer les 9 coefficients en 10 multiplications en procédant de la façon suivante :

        ca = cos(a)
        co = 1 - ca
        sa = sin(a)
        t1 = Ux*co
        t2 = Ux*t1
        R(1,1) = ca + t2
        t3 = Uy*t1
        t4 = Uz*sa
        R(2,1) = t3 + t4
        R(1,2) = t3 - t4
        t3 = Uz*t1
        t4 = Uy*sa
        R(3,1) = t3 - t4
        R(1,3) = t3 + t4
        t1 = Uy*co
        t3 = Uy*t1
        R(2,2) = t3 + ca
        R(3,3) = 1 - t2 - t3
        t2 = Uz*t1
        t3 = Ux*sa
        R(3,2) = t2 + t3
        R(2,3) = t2 - t3

Voilà, 10 multiplications/11 additions.

N'importe quelle rotation, celle des "demomakers" par exemple peut se mettre sous la forme de la rotation d'un angle a autour d'un vecteur unitaire U. Il suffit pour cela de remarquer que U est un vecteur propre de la matrice de rotation et que la somme des éléments de la diagonale vaut 1+2*cos(a).

Effectuer le passage d'une forme à l'autre n'a pas d'intérêt pratique immédiat, mais cela montre qu'il y a une équivalence entre les différentes représentations des rotations. On doit choisir la plus adaptée à l'application.

Par exemple, lorsqu'on affectue des animations fluides, l'angle de rotation reste petit pour passer d'une image à la suivante. Celà mène à une optimisation importante : celle des angles petits. Ce genre d'approximation permet aussi de tracer des cercles (enfin "presque" des cercles) avec un minimum de calculs. Mais revenons à notre rotation, la matrice lorsque l'angle est petit peut être approximée par :

          |                     |
          |  1      Uz*a  -Uy*a |
    [R] ~ | Uz*a     1     Ux*a |    avec a en radians.
          | Uy*a   -Ux*a    1   |
          |                     |

Le calcul brutal de la transformation demande 6 mul/6 add et en appliquant la méthode de Winograd vue plus haut dans le cas général, cela nous mène à :

    Précalcul de 3 vecteurs A,B et C :

    A(1) = Ux*a
    A(2) = Uy*a
    A(3) = Uz*a

    B(1) = A(2)*A(3)
    B(2) = A(1)*A(3)
    B(3) = A(1)*A(2)

    C(1) = Px - Py*Pz
    C(2) = Py - Px*Pz
    C(3) = Pz - Px*Py

    Pour chaque point P calculer T = [R]*P :

    Tx = [Py-A(2)]*[Pz+A(3)] + B(1) + C(1)
    Ty = [Px+A(1)]*[Pz+A(3)] - B(2) + C(2)
    Tz = [Px-A(1)]*[Py+A(2)] + B(3) + C(3)

Soit 3 mul/12 add ! C'est à ma connaissance le plus petit nombre de multiplications jamais atteint pour une rotation générale si on exclue la recherche dans des tables énormes et les méthodes CORDIC.

La contrepartie (il y en a toujours une :(( est que la matrice obtenue avec cette aproximation n'a plus une norme égale à 1 exactement. Conclusion, si on applique trop souvent cette transformation sans "recalibrage", les objets sont déformés. Mais bon, je suis content de moi :-) Revenons aux choses sérieuses ...

Jusqu'à présent, on a considéré que les rotations/translations d'ojets. Mais pour l'animation d'un monde en 3 dimensions cela ne suffit pas : il faut gérer les mouvements de la caméra.