Eclairage

1.    Activation

        C’est pour ce genre de choses que l’on apprécie la simplicité d’OpenGL, car activer l’éclairage se fait par :

glEnable(GL_LIGHTING) ;                 // Active la gestion des lumières
glEnable(GL_LIGHT0) ;                      // allume la lampe 0

C’est tout.
Pour allumer une autre lampe, mettre GL_LIGHTi au lieu de GL_LIGHT0. Il y a au minimum 8 lampes disponibles. On a toujours GL_LIGHTi = GL_LIGHT0 + i. Pour éteindre, on utilise glDisable.
Le nombre maximal de lumières est obtenu en appelant : glGetIntegerv(GL_MAX_LIGHTS, &nb_lights)

2.           Paramètres

            Il faut quand même donner un minimum d’information sur la lampe, comme la couleur et la position de la lampe.

                                                                            i.      Un peu de théorie

            Dans la réalité, les sources de lumières sont des volumes (par exemple un filament), et la lumière se réfléchit à l’infini sur tous les objets.
Il est impossible de simuler un tel comportement, surtout quand il faut calculer une image en quelques millisecondes. Des simplifications ont été apportées :

-         les sources de lumière sont des points.

-         la lumière ne se réfléchit pas sur les objets.

Pour plus de réalisme, les sources disposent de plusieurs paramètres qui n’ont pas forcément d’équivalent réel (voir le paragraphe suivant). Une chose par contre ne change pas : la couleur visible d’un objet dépend à la fois de sa couleur propre et celle de la lampe, et l’intensité de la lumière qu’il reçoit dépend de l’angle de la surface avec la direction vers la source lumineuse.

                                                                       ii.      Tout sur la lampe

Tiré tout droit de la spécification OpenGL :

Paramètre

Type

Par défaut

Description

acm

Couleur

(0,0,0,0)

Intensité ambiante : la lumière ambiante est présente partout dans la scène, elle n’a pas de direction

dcli

Couleur

(0,0,0,0) sauf lampe 0 : (1,1,1,1)

Intensité de diffusion : c’est l’intensité « réelle » de la source, elle part dans tous les sens depuis la source

scli

Couleur

Idem

Intensité du « spot » : comme la lumière diffuse, sauf qu’elle n’est émise qu’à l’intérieur d’un cône

Ppli

Position

(0,0,1,0)

Position

sdli

Direction

(0,0,-1)

Direction du spot (vecteur)

srli

Réel

0

Exposant du spot (entre 0 et 128)

crli

Réel

180

Angle du cône du spot (180 ou entre 0 et 90)

k0i

Réel

1.0

Atténuation constante (entre 0 et ¥)

k1i

Réel

0

Atténuation linéaire

k2i

Réel

0

Atténuation quadrique

 

                                                                 iii.      Et sur les matériaux

            Les mêmes paramètres existent pour spécifier la « réponse » de la surface d’un objet :

Paramètre

Type

Par défaut

Description

acm

Couleur

(0.2,0.2,0.2,1.0)

Couleur ambiante

dcm

Couleur

(0.8,0.8,0.8,1.0)

Couleur de diffusion

scm

Couleur

(0,0,0,1)

Couleur au « spot »

ecm

Couleur

(0,0,0,1)

Couleur émise

srm

Réel

0

Exposant au « spot »

 

2.           Fonctions OpenGL

            Les fonctions suivantes permettent de spécifier tous les paramètres précédents :

·        Pour une source lumineuse :

void glLightf( Glenum light, Glenum pname, GLfloat param )
void glLighti( Glenum light, Glenum pname, GLint param )

light = GL_LIGHTi
pname = GL_SPOT_EXPONENT, GL_SPOT_CUTOFF, GL_CONSTANT_ATTENUATION,  GL_LINEAR_ATTENUATION, ou GL_QUADRATIC_ATTENUATION
et param = la nouvelle valeur

void glLightfv( GLenum light, GLenum pname, const Glfloat *params)
void glLightiv( GLenum light, GLenum pname, const GLint *params)

light = GL_LIGHTi
pname = GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_POSITION, GL_SPOT_DIRECTION, GL_SPOT_EXPONENT, GL_SPOT_CUTOFF,
L_CONSTANT_ATTENUATION, GL_LINEAR_ATTENUATION, ou GL_QUADRATIC_ATTENUATION
param = la nouvelle valeur

Attention à la position de la lampe : comme toutes les coordonnées entrées, elles dont immédiatement multipliées par la matrice ModelView. Si celle-ci change, il faut repositionner les lampes.

void glLightModelf( GLenum pname, GLfloat param )
void glLightModeli( GLenum pname, GLint param )
void glLightModelfv( GLenum pname, const GLfloat *params )
void glLightModeliv( GLenum pname, const GLint *params )


Pname

param

GL_LIGHT_MODEL_AMBIENT (fv ou iv seulement)

Intensité ambiante de la scène, par défaut (0.2, 0.2, 0.2, 1.0)

GL_LIGHT_MODEL_LOCAL_VIEWER

0 : les reflets des spots sont calculés sur l’axe –z

¹ 0 : par rapport à la position de l’œil

GL_LIGHT_MODEL_TWO_SIDE

0 : seule la face « front » est calculée

¹ 0 : les deux faces d’une surface sont calculées

 

·        Pour un matériau :

            Les propriétés de surface d’un polygone peuvent être différentes suivant la face que la face est « front » ou « back » (voir glFrontFace, ou le paragraphe sur le culling).

  void glMaterialfv( GLenum face, GLenum pname, const GLfloat *params )
  void glMaterialiv( GLenum face, GLenum pname, const GLint *params )

La page man est tellement bien faite que je ne vois pas l’intérêt de la refaire :

Face

Specifies which face or faces are being updated. Must be one of GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK.

Pname

Specifies the material parameter of the face or faces that is being updated. Must be one of GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_EMISSION, GL_SHININESS, GL_AMBIENT_AND_DIFFUSE, or GL_COLOR_INDEXES.

Params

Specifies a pointer to the value or values that pname will be set to.


glMaterial assigns values to material parameters.  There are two matched sets of material parameters. One, the front-facing set, is used to shade points, lines, bitmaps, and all polygons (when two-sided lighting is disabled), or just front-facing polygons (when two-sided lighting is enabled). The other set, back-facing, is used to shade back-facing polygons only when two-sided lighting is enabled.  Refer to the glLightModel reference page for details concerning one- and two-sided lighting calculations.

[…]

GL_AMBIENT

params contains four integer or floating-point values that specify the ambient RGBA reflectance of the material.  Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to -1.0. Floating-point values are mapped directly.  Neither integer nor floating-point values are clamped. The default ambient reflectance for both front- and back-facing materials is (0.2, 0.2, 0.2, 1.0).

GL_DIFFUSE

params contains four integer or floating-point values that specify the diffuse RGBA reflectance of the material. Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to -1.0. Floating-point values are mapped directly.  Neither integer nor floating-point values are clamped. The default diffuse reflectance for both front- and back-facing materials is (0.8, 0.8, 0.8, 1.0).

GL_SPECULAR

params contains four integer or floating-point values that specify the specular RGBA reflectance of the material.  Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to -1.0. Floating-point values are mapped directly.  Neither integer nor floating-point values are clamped.  The default specular reflectance for both front- and back-facing materials is (0.0, 0.0, 0.0, 1.0).

GL_EMISSION

params contains four integer or floating-point values that specify the RGBA emitted light intensity of the material.  Integer values are mapped linearly such that the most positive representable value maps to 1.0, and the most negative representable value maps to -1.0. Floating-point values are mapped directly.  Neither integer nor floating-point values are clamped. The default emission intensity for both front- and back-facing materials is (0.0, 0.0, 0.0, 1.0).

GL_SHININESS

params is a single integer or floating-point value that specifies the RGBA specular exponent of the material. Integer and floating-point values are mapped directly. Only values in the range [0,128] are accepted. The default specular exponent for both front- and back-facing materials is 0.

GL_AMBIENT_AND_DIFFUSE

Equivalent to calling glMaterial twice with the same parameter values, once with GL_AMBIENT and once with GL_DIFFUSE.

 

3.           Les normales

            Une fois que la source lumineuse est définie, ainsi que les caractéristiques du matériau, il reste encore une chose : l’angle d’incidence de la lumière. Cela ne change pas la couleur d’une surface, mais l’intensité de l’éclairage qu’elle reçoit.
            L’angle d’incidence est l’angle entre la normale à une surface et la droite partant de la source lumineuse et passant par le point d’incidence. Il faut impérativement préciser pour chaque point la « normale » de ce point (plus rigoureusement, la normale à la surface dont ce point fait partie). Le principe est le même que pour glColor, la normale est une des variables d’état d’OpenGL, qui est modifiée par l’une des fonctions suivantes :

void glNormal3b( GLbyte nx, GLbyte ny, GLbyte nz )
void glNormal3d( GLdouble nx, GLdouble ny, GLdouble nz )
void glNormal3f( GLfloat nx, GLfloat ny, GLfloat nz )
void glNormal3i( GLint nx, GLint ny, GLint nz )
void glNormal3s( GLshort nx, GLshort ny, GLshort nz )
void glNormal3bv( const GLbyte *v )

            Les paramètres correspondent au coordonnées du vecteur normal. ATTENTION : il doit être UNITAIRE (de norme 1). Il est possible de rendre unitaire automatiquement les vecteurs entrés, mais cela entraîne un calcul supplémentaire : glEnable(GL_NORMALIZE). Pour éviter cette perte de temps, qui, pour les scènes assez complexes, peut devenir importante, on peut calculer soit_même la normale avec la fonction ci-dessous :

void Vecteur_Unite(float vector[3])
{
       float length;
      
      
// Calcul de la norme du vecteur               
       length = (float)sqrt((vector[0]*vector[0]) + (vector[1]*vector[1]) + (vector[2]*vector[2]));
      
       if(length == 0.0f) length = 1.0f;  //évite une violente erreur !!!
       vector[0] /= length;
       vector[1] /= length;
       vector[2] /= length;
}

// Points p1, p2, & p3 spécifiés dans le sens trigonométrique
void Normale(float v[3][3], float out[3])
{
       float v1[3],v2[3];
       static const int x = 0;
       static const int y = 1;
       static const int z = 2;

       // Calcul de 2 vecteurs à partir des 3 points
       v1[x] = v[0][x] - v[1][x];
       v1[y] = v[0][y] - v[1][y];
       v1[z] = v[0][z] - v[1][z];
       v2[x] = v[1][x] - v[2][x];
       v2[y] = v[1][y] - v[2][y];
       v2[z] = v[1][z] - v[2][z];

       // calcul du produit vectoriel
       out[x] = (v1[y]*v2[z] - v1[z]*v2[y]);
       out[y] = (v1[z]*v2[x] - v1[x]*v2[z]);
       out[z] = (v1[x]*v2[y] - v1[y]*v2[x]);

       // on le réduit à un vecteur unité
       Vecteur_Unite(out);
}

 

4. Exemple de scène avec lumière

Voici l’exemple le plus simple :

void Init_light()
{
                         //différents paramètres
            GLfloat ambient[] = {0.15f,0.15f,0.15f,1.0f};
            GLfloat diffuse[] = {0.5f,0.5f,0.5f,1.0f};
            GLfloat light0_position [] = {0.0f, -10.0f, 0.0f, 0.0f};
            GLfloat specular_reflexion[] = {0.8f,0.8f,0.8f,1.0f};
            GLubyte shiny_obj = 128;

                        //positionnement de la lumière avec les différents paramètres
            glEnable(GL_LIGHTING);
            glLightfv(GL_LIGHT0,GL_AMBIENT,ambient);
            glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse);
            glLightfv(GL_LIGHT0,GL_POSITION,light0_position);
            glEnable(GL_LIGHT0);

                         //spécification de la réflexion sur les matériaux
            glEnable(GL_COLOR_MATERIAL);
            glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);
            glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
            glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
            glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,specular_reflexion);
            glMateriali(GL_FRONT_AND_BACK,GL_SHININESS,shiny_obj);
}

Appliquez à un cube, cela donne :

           

            Sans lumière particulière                             Avec une lumière moyennement forte

Sources et éxécutable

Notez qu'ici, j'ai utilisé 2 fois les tableaux "ambient" et "diffuse". Ceci n'est pas du tout obligatoire. je ne l'ai fait que pour simplifier les choses. Il y a des tonnes d'effets différents, donc, testez vous_même. Notez également qu'en ce qui concerne la réfléxion sur les matériaux, vous pouvez changer ces proporiétés avant de dessiner chaque objet, qui aura alors des caractéristiques lumineuses propres. (le bois ne reflète pas la lumière comme le métal...)

       

Page précédente    Page suivante