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. 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
    exemple : description hiérarchique. Placer le bras d'un bonhomme par rapport à son squelette.     exemple : projection orthographique (cf. td 1)

    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, gmMaterial, 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. 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:

eq301.gif

[...]

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.