L3IF Images
    année 2004-2005
    http://www710.univ-lyon1.fr/~jciehl/
 
       
TD1 - Transformations/Visualisation 3D
   
 
     Si une fonction ne donne pas le résultat prévu, 
essayez un des tutoriaux interactifs de Nate Robin (version Windows) 
version Linux
 
 
 
1. Quelques précisions : coordonnées et transformations openGL
      Il y a deux méthodes pour placer des objets dans
 une scène openGL. Soit spécifier directement les matrices
4x4  de changement de repère (transformation du repère local
de l'objet vers le repère de la scène), soit utiliser les fonctions
limitées à la description d'une translation, d'une rotation,
d'un changement d'échelle. Ces transformations élémentaires
sont composées par openGL afin de déterminer la matrice homogène
de changement de repère (cf. Annexes pour quelques
précisions sur le calcul des compositions).
  
      openGL gère 2 repères : un repère
 correspond à la scène et permet de décrire la position
 des objets, le deuxième décrit la camera et détermine 
la visualisation ainsi que la projection utilisée.
  
      openGL calcule automatiquement la composition de transformations.
 Pour rendre cette composition plus souple et permettre de décrire
de manière hiérarchique les différents repères,
openGL conserve une pile des transformations successives. La pile utilisée
 pour placer les objets dans la scène, est identifiée par GL_MODELVIEW.
 L'autre pile permet de spécifier la visualisation de la scène
 et le type de projection utilisée, elle est identifiée par
GL_PROJECTION. Il est également possible de placer la matrice
identité sur le sommet de pile afin de démarrer la description
d'une nouvelle composition de transformations. Les opérations push
et pop sont également disponibles.
  
      exemple : positionner un objet (transformation monde -> camera)
   
     	glMatrixMode(GL_MODELVIEW); 
   	glLoadIdentity();             // pas de transformation
   	glTranslatef(tx, ty, tz);     // translation 
   	glRotatef(a, axe_x, axe_y, axe_z); // rotation de a degrés autour du vecteur axe_x, axe_y, axe_z
     
      exemple : description hiérarchique.
 Placer le bras d'un bonhomme par rapport à son squelette.  
    repere_tronc()
tracé_du_tronc(); 
glPushMatrix();           // conserver la matrice du repere global
   	glRotatef(40., 0,0,1);   // tranformation locale pour le bras gauche (rotation / repere du tronc)
   	tracé_du_bras(); 
   	glPopMatrix();           // revenir au repere global
   	glPushMatrix();         // conserver la matrice du repere global
   	glRotatef(-40., 0,0,1);    // transformation locale pour le bras droit (rotation / repere du tronc)
   	tracé_du_bras(); 
   	glPopMatrix();          // revenir au repere global   
      exemple : projection orthographique (cf. TD Introduction)
   
     	glMatrixMode(GL_PROJECTION); 
   	glLoadIdentity(); 
   	glOrtho(-1.,1., -1.,1., 1.,-1.);
     
  
      exemple : projection perspective (cf. TD Introduction)
   
 	glMatrixMode(GL_PROJECTION); 
   	glLoadIdentity(); 
   	gluPerspective(60., 1., 1., 100.);
   
     Résumé des fonctions utiles: 
         description dans le manuel 
de programmation (chapitre 3)
 
         manpages 
 
 
     Quelques précisions sur les manipulations et l'ordre 
de composition des transformations, tirées du manuel, cf. Annexe.
 
 
 
2. Décrire des objets
     OpengGL est capable de dessiner un certain nombre de
primitives : des points, des lignes, des triangles, des quadrangles, des
polygones convexes. Toute géométrie est décrite comme
un ensemble de ces primitives. Elles sont elles-mêmes décrites
par des sommets et des propriétés associées : couleur,
normale à la surface, coordonnées de textures, transparence,
etc.
 
     Les fonctions glVertex() 
permettent de décrire la position d'un sommet dans le repère 
courant. Les propriétés définies par les fonctions glColor, 
glNormal, glMaterial, glTexCoord, etc. sont associées au sommet suivant 
(n'oubliez pas que GL est une machine à état).
 
     exemple : un sommet bleu
     glColor3f(0.0, 0.0, 1.0);
     glNormal3f(0.0, 1.0, 0.0);
     glVertex3f(0.0, 0.0, 0.0);
 
  
 
3. Rappels / Exercices
 
     Définissez une projection orthographique et dessinez 
un triangle ou un rectangle coloré en modifiant minigl du 
td précedent.
 
     Animation.  En utilisant le callback idle de glut 
animez votre objet (une rotation ou un changement d'échelle, par exemple). 
 
     Manipulation.  En utilisant le callback keyboard 
ou mouse de glut modifiez la position de la camera ou de votre objet.
 
     Définissez une projection perspective.
 
     Utilisez l'élimination des faces cachées 
automatique (Z-Buffer).
 
 
4. Questions Subsidiaires
      Définissez une carte 2D, extrudez la géométrie 
représentée et déplacez-vous à l'intérieur.
 
     Comment détecter la collision avec la géométrie 
lors d'un déplacement ?
 
     Ajoutez des matières, des sources de lumières, 
des textures, des animations, etc.
   
 
 
5. Annexes
 Extraits à ne pas manquer du manuel de programmation
 
 
 
Thinking about Transformations
    
Let's start with a simple case of two transformations: a 45-degree counterclockwise 
rotation about the origin around the z-axis, and a translation 
down the x-axis. Suppose that the object you're drawing is small 
compared to the translation (so that you can see the effect of the translation), 
and that it's originally located at the origin. If you rotate the object first
and then translate it, the rotated object appears on the x-axis. 
If you translate it down the x-axis first, however, and then rotate 
about the origin, the object is on the line y=x, as shown in Figure 
3-4. In general, the order of transformations is critical. If you do transformation 
A and then transformation B, you almost always get something different than 
if you do them in the opposite order. 
     
 
 Figure 3-4 : Rotating First or Translating First  
     
Now let's talk about the order in which you specify a series of transformations.
 All viewing and modeling transformations are represented as 4x4 matrices. 
Each successive glMultMatrix*() or transformation command multiplies 
a new 4x4 matrix M by the current modelview matrix C to yield 
CM. Finally, vertices v are multiplied by the current modelview 
matrix. This process means that the last transformation command called in 
your program is actually the first one applied to the vertices: CMv. 
Thus, one way of looking at it is to say that you have to specify the matrices 
in the reverse order. Like many other things, however, once you've gotten 
used to thinking about this correctly, backward will seem like forward. 
    
Consider the following code sequence, which draws a single point using 
three transformations:
    
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMultMatrixf(N);                /* apply transformation N */
glMultMatrixf(M);                /* apply transformation M */
glMultMatrixf(L);                /* apply transformation L */
glBegin(GL_POINTS);
glVertex3f(v);                   /* draw transformed vertex v */
glEnd();
    
With this code, the modelview matrix successively contains I, N, 
NM, and finally NML, where I represents the identity 
matrix. The transformed vertex is NMLv. Thus, the vertex transformation 
is N(M(Lv)) - that is, v is multiplied first by L, the 
resulting Lv is multiplied by M, and the resulting MLv 
is multiplied by N. Notice that the transformations to vertex v
 effectively occur in the opposite order than they were specified. (Actually,
 only a single multiplication of a vertex by the modelview matrix occurs;
in this example, the N, M, and L matrices are already
multiplied 
  into a single matrix before it's applied to v.) 
   
  
   
General-Purpose Transformation Commands 
   
If you want to specify explicitly a particular matrix to be loaded as the
current matrix, use glLoadMatrix*(). Similarly, use glMultMatrix*()
 to multiply the current matrix by the matrix passed in as an argument. The
 argument for both these commands is a vector of sixteen values (m1, 
m2, ... , m16) that specifies a matrix M as follows:
    
 
    
[...]
 
Caution: If you're programming in C and you declare a matrix as 
m[4][4], then the element m[i][j] is in the ith 
column and jth row of the OpenGL transformation matrix. This is 
the reverse of the standard C convention in which m[i][j] is in 
row i and column j. To avoid confusion, you should declare
your matrices as m[16]. 
    
  - void glLoadMatrix{fd}(const TYPE *m); 
  
 
  - Sets the sixteen values of the current matrix to those specified 
by 
 
   m.
    
   - void glMultMatrix{fd}(const TYPE *m);
 
   - Multiplies the matrix specified by the sixteen values pointed 
to by 
 
   m by the current matrix and stores the result as the 
current matrix.  
    
Note: All matrix multiplication with OpenGL occurs as follows: Suppose
the current matrix is C and the matrix specified with glMultMatrix*() 
or any of the transformation commands is M. After multiplication, the
final matrix is always CM. Since matrix multiplication isn't generally 
commutative, the order makes a difference.