2
Transformations de modélisation
Les transformations sur les objets permettent de déplacer les objets,
de les orienter différemment et / ou de changer leur forme.
En particulier, les transformations affines nous ont permis de passer
du système de coordonnées du « monde » à celui de l’écran.
Une transformation peut être vue soit comme un changement de
repère ou soit comme une transformation des sommets de l’objet.
La transformation vient modifier les points de l’objet sans changer
le repère de l’objet.
Cela définit un nouveau repère: les points des objets sont alors
redéfinis selon ce nouveau repère.
3
Transformation affine des sommets d’un objet
Ces transformations sont représentées aussi sous forme matricielle :
v = M u
où M est une matrice d’ordre 4 : | 11 12 13 14|
M = | 21 22 23 24|
| 31 32 33 34|
| 0 0 0 1 |
Nous avons 12 degrés de liberté pour une transformation sur un point p
quelconque : p | 1|
| 2|
| 3|
| 1 |
Pour une transformation sur un vecteur, 9 éléments ont une influence :
v = M u où u | 1|
| 2|
| 3|
| 0 |
4
Transformation via un changement de repère
Au lieu d’appliquer une transformation aux sommets d’un objet
tout en conservant le système de coordonnées utilisé intact, on
effectue un changement de repère.
Soit le repère R1 (u, v, w, O),
soit une transformation affine représentée par la matrice M1,
le nouveau repère après transformation est :
R2 (M1 u, M1 v, M1 w, M1 O).
Soit un point P défini dans le repère R1, ce même point dans le repère
R2 est défini par M1
-1 P.
5
Implantation en OpenGL des transformations
Dans OpenGL, il existe 2 matrices pour stocker la résultante des transformations
qui interviennent dans une application :
GL_MODELVIEW : (par défaut)
elle est unique même si on peut la voir comme le produit de 2 matrices :
° les transformations affines à appliquer aux objets,
° celles permettant de passer du repère des objets à celui de la caméra.
GL_PROJECTION :
° les transformations permettant de définir la forme et l’orientation
du volume de visualisation.
La primitive glMatrixMode permet de choisir la matrice où les transformations
s’appliqueront :
void glMatrixMode(GLenum mode);
Spécifie laquelle des matrices sera modifiée par la suite selon la valeur
de mode : GL_MODELVIEW ou GL_PROJECTION.
Il n’est possible de modifier qu’une seule matrice à la fois.
6
Soit Q la matrice associée au mode GL_MODELVIEW, cette matrice est appliquée
à n’importe quel sommet d’un objet qui est défini après l’initialisation de Q.
Soit p un tel sommet, alors la transformation suivante s’applique : Qp.
En modifiant Q, nous changeons l’état du système.
À n’importe quel objet qui est défini après la modification de Q, la transformation
modifiée s’applique :
glBegin(GL_POLYGON);
glVertex3f(0.0, 0.0, 0.0); glVertex3f(10.0, 0.0, 0.0); glVertex3f(0.0, 10.0, 0.0);
glEnd();
glTranslatef(25.0, 0.0, 0.0);
glBegin(GL_POLYGON);
glVertex3f(0.0, 0.0, 0.0); glVertex3f(10.0, 0.0, 0.0); glVertex3f(0.0, 10.0, 0.0);
glEnd();
Note : On ne peut pas insérer glTranslatef à l’intérieur
de glBegin() / glEnd().
7
Lorsque vous écrivez un programme en OpenGL, vous devez vous assurer que
la matrice MODEL_VIEW est initialisée correctement :
void glLoadIdentity();
Initialise la matrice active à la matrice identité d’ordre 4.
void glLoadMatrix{fd}(const TYPE * m);
Initialise la matrice active à partir d’un vecteur à 16 éléments
où ceux-ci sont rangés colonne par colonne.
void glMultMatrix{fd}(const TYPE * m);
Post-multiplie la matrice active à partir d’un vecteur à 16 éléments
où ceux-ci sont rangés colonne par colonne.
Si C est la matrice active et M la matrice passée
en paramètre, alors la matrice active devient CM.
Dans les 2 primitives précédentes,
l’élément m[i][j] se trouve dans la
colonne i et sur la ligne j :
m1 m5 m9 m13
m2 m6 m10 m14
m3 m7 m11 m15
m4 m8 m12 m16
8
Des transformations élémentaires peuvent aussi être effectuées (post-multiplication)
à la matrice courante.
void glRotate{fd}(TYPE angle, TYPE vx, TYPE vy, TYPE vz);
Rotation dans le sens contraire des aiguilles d’une montre d’un angle en
degré autour d’un axe de rotation (qui passe par l’origine) dont la direction
est (vx, vy, vz).
void glTranslate{fd}(TYPE dx, TYPE dy, TYPE dz);
Déplacement d’un objet selon le vecteur (dx, dy, dz).
void glScale{fd}(TYPE sx, TYPE sy, TYPE sz);
Mise à l’échelle d’un objet selon les facteurs sx, sy et sz.
9
Exemple :
glMatrixMode(GL_MODELVIEW)
glLoadIdentity(); Q I
glTranslatef(4.0, 5.0, 6.0); Q QT(4.0, 5.0, 6.0)
glRotatef(45.0, 1.0, 2.0, 3.0) Q QR(45.0, 1.0, 2.0, 3.0)
glTranslatef(-4.0, -5.0, -6.0); Q QT(-4.0, -5.0, -6.0)
ce qui donne
q = Q p équivaut à :
q = T(4.0, 5.0, 6.0) R(45.0, 1.0, 2.0, 3.0) T(-4.0, -5.0, -6.0) p.
Ordre selon lequel il vous faut spécifier une série de transformations
La dernière primitive de transformation que votre programme appelle est en réalité
la première appliquée aux sommets.
En réalité, il ne se produit qu’une seule multiplication d’un sommet par la matrice
MODEL_VIEW car les matrices sont déjà multipliées en une seule matrice avant
d’être appliquées à p.
10
Sauvegarde de la matrice de transformation courante
À une étape donnée de notre programme, il se peut que l’on veuille sauvegarder la
matrice de transformation courante pour y avoir accès ultérieurement.
OpenGL permet ceci en gérant des piles de transformations.
Les fonctions suivantes sont disponibles :
glPushMatrix();
Sachant que la matrice de transformation courante est sur le dessus de la
pile, cette fonction effectue une copie de cette matrice et la place sur le
dessus de la pile.
Cette copie sera modifiée dès que la matrice de transformation courante est
modifiée dans le programme.
glPopMatrix();
Cette fonction enlève du dessus de la pile la copie de la matrice de
transformation courante.
La matrice de transformation courante devient alors la dernière matrice
sauvegardée.
11
void Affichage( void )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 0.0, 0.0);
glLoadIdentity();
glRotatef(theta, vx, vy, vz); glTranslatef(2.0, 2.0, 2.0);
glutSolidSphere(0.5, 10, 20);
glLoadIdentity();
glColor3f(0.0, 1.0, 0.0);
glBegin(GL_LINES);
glVertex3f(0, 0, 0); glVertex3f(vx, vy, vz);
glEnd();
/* Cela force le système à afficher les points aussitôt que possible. */
glFlush();
/* Permet de transférer l'image à l'écran. */
glutSwapBuffers(); }
Exemple I : Affichage d’un axe et d’une sphère laquelle a subi une rotation autour
de cet axe.
sphère
axe
12
Exemple I (suite) :
void sphere_en_rotation()
{
theta += 0.05;
if (theta > 360.0) theta -= 360.0;
Affichage();
}
Permet de changer la direction de l’axe selon le bouton de la souris choisi.
void souris(int bouton, int etat, int x, int y)
{
if ( (bouton == GLUT_LEFT_BUTTON) &
(etat == GLUT_DOWN)) vx = vx + 1.0;
if ( (bouton == GLUT_MIDDLE_BUTTON) &
(etat == GLUT_DOWN)) vy = vy + 1.0;
if ( (bouton == GLUT_RIGHT_BUTTON) &
(etat == GLUT_DOWN)) vz = vz + 1.0;
}
Permet d’afficher une sphère en rotation autour d’un axe de direction (vx, vy, vz).
13
Exemple I (suite et fin) :
void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(800, 500);
glutInitWindowPosition(500, 100);
glutCreateWindow("Transformations");
glutDisplayFunc(Affichage);
Initialisation();
/* La fonction sphere_en_rotation sera exécutée lorsque tous les
événements générés ont déjà été pris en compte. Cette fonction
est particulièrement utile pour créer des effets d'animation. */
glutIdleFunc(sphere_en_rotation);
glutReshapeFunc(reconfiguration);
glutMouseFunc(souris);
glEnable(GL_DEPTH_TEST);
glutMainLoop();
}
14
Exemple II :
void Affichage( void )
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Le système de coordonnées se trouve initialement au centre du cube.
// Vous devez déplacer le système de coordonnées vers une extrémité du cube.
glPushMatrix();
glColor3f(1.0, 0.0, 0.0);
// Translation de (1, 0, 0) pour établir le point d'articulation.
// Rotation autour de l'axe des z d'un angle "epaule".
glRotatef((GLfloat) epaule, 0.0, 0.0, 1.0);
glTranslatef(1.0, 0.0, 0.0);
glPushMatrix();
glScalef(2.0, 0.4, 1.0);
glutSolidCube(1.0);
glPopMatrix();
Affichage d’un bras articulé.
static int epaule = 0, coude = 0, doigt = 0;
static GLint w = 100, h = 100;
15
Exemple II (suite) :
glColor3f(0.0, 1.0, 0.0);
// Translation de (1.5, 0, 0) pour établir le point d'articulation.
// Rotation autour de l'axe des z d'un angle "coude".
// Translation de (1, 0, 0) pour se déplacer vers la prochaine articulation.
glTranslatef(1.0, 0.0, 0.0);
glRotatef((GLfloat) coude, 0.0, 0.0, 1.0);
glTranslatef(1.5, 0.0, 0.0);
glPushMatrix();
glScalef(3.0, 0.2, 1.0);
glutSolidCube(1.0);
glPopMatrix();
glColor3f(0.0, 0.0, 1.0);
16
Exemple II (suite) :
// Translation de (0.5, 0, 0) pour établir le point d'articulation.
// Rotation autour de l'axe des z d'un angle "doigt".
// Translation de (1.5, 0, 0) pour se déplacer vers la prochaine
// articulation.
glTranslatef(1.5, 0.0, 0.0);
glRotatef((GLfloat) doigt, 0.0, 0.0, 1.0);
glTranslatef(0.5, 0.0, 0.0);
glPushMatrix();
glScalef(1.0, 0.1, 0.1);
glutSolidCube(1.0);
glPopMatrix();
glPopMatrix();
glFlush();
glutSwapBuffers();
}
17
Exemple II (suite et fin) :
void clavier(unsigned char cle, int x, int y)
{
switch(cle)
{
case 'e' : // Rotation à l'épaule.
epaule = (epaule + 5) % 360; glutPostRedisplay(); break;
case 'E' :
epaule = (epaule - 5) % 360; glutPostRedisplay(); break;
case 'c' : // Rotation au coude.
coude = (coude + 5) % 360; glutPostRedisplay(); break;
case 'C' :
coude = (coude - 5) % 360; glutPostRedisplay(); break;
case 'd' : // Rotation au doigt.
doigt = (doigt + 5) % 360; glutPostRedisplay(); break;
case 'D' :
doigt = (doigt - 5) % 360; glutPostRedisplay(); break;
default: break;
}
}