Tutoriels iOS


précédentsommairesuivant

IX. Tutoriel 7. Éclairage avec relief

Ce tutoriel suppose que vous connaissiez les rudiments d'éclairage en OpenGL, ce que lumière ambiante, diffuse et spéculaire veulent dire et les mathématiques derrière. Il ne couvre pas la théorie de l'éclairage Phong, ni comment les facteurs ambiant, diffus et spéculaire sont calculés. Il y a un grand nombre d'articles et de documentations sur le Net, suivez ce lien pour plus de détails.

Ce tutoriel montre comment réaliser un éclairage par point sur un shader avec les reliefs. Le bump mapping ajoute des détails à la scène en perturbant les normales de la surface des objets, que l'on utilise ensuite dans le pixel shader pour le calcul de l'éclairage. Il en résulte une surface irrégulière. La capture d'écran ci-dessous montre la même scène rendue avec et sans bumps (dans l'exemple de code fourni, vous pouvez basculer entre les deux scènes en utilisant le bouton switch).

IX-A. Code de la procédure

Du point de vue CPU, les positions de la lumière et de la caméra sont envoyées au shader dans le système de coordonnées monde.

Tout d'abord, nous obtenons l'inverse de la matrice modèle de l'objet comme suit :

 
Sélectionnez
    //Obtention de la matrice modèle
    mat4f &modelBumpMeshMat =  mesh->GetTransfromationMatrix();
    mat4f modelInv = modelBumpMeshMat.inverse();

Puis nous multiplions la position de la lumière par l'inverse de la matrice modèle pour obtenir sa position dans l'espace modèle :

 
Sélectionnez
    //Position de la lumière dans l'espace monde
    vec4f lightPosition = modelInv * lightPos;
   
    // Envoi des uniformes au shader
    m_pActiveShader->SetUniform3fv("lightPosModel", 1, &lightPosition.x);

En ce qui concerne la position de la caméra, elle se situe toujours à l'origine (0, 0, 0). La matrice de vue transforme chaque objet depuis l'espace monde vers l'espace caméra, donc si nous multiplions la position de la caméra située à (0, 0, 0, 1) par l'inverse de la matrice de vue, nous obtenons la position de la caméra dans l'espace monde. Puis nous multiplions cette position par l'inverse de la matrice modèle pour obtenir la position de la caméra dans l'espace objet :

 
Sélectionnez
    vec4f cameraPos = inv( modelMatrix ) * (inv(ViewMatrix) * vec4(0, 0, 0, 1) 

Pour une expression compacte :

 
Sélectionnez
vec4f cameraPos= modelInv * m_pCamera->GetPosition();

m_pCamera->GetPosition() calcule l'inverse de la matrice de vue, que nous multiplions par le vecteur homogène vec4f(0, 0, 0, 1.f). Notez qu'effectuer la multiplication d'une matrice « M » 4x4 par un vecteur « v » homogène 4x1 extrait la partie translation de la matrice (M[12] M[13] M[14]).

Maintenant que nous avons la position de la caméra dans l'espace monde, nous l'envoyons au shader.

 
Sélectionnez
m_pActiveShader->SetUniform3fv("camPosModel", 1, &cameraPos.x);

De plus, nous devons envoyer les paramètres de la lumière et les propriétés du matériau définis par les vecteurs ambiant, diffus et spéculaire.

Pour les paramètres de la lumière :

 
Sélectionnez
    m_pActiveShader->SetUniform4fv("lightColorAmbient", 1, &lightAmbient.x);
    m_pActiveShader->SetUniform4fv("lightColorDiffuse", 1, &lightDiffuse.x);
    m_pActiveShader->SetUniform4fv("lightColorSpecular", 1, &lightSpecular.x);

Pour les propriétés du matériau, l'envoi se fait dans la fonction Render de l'objet CMeshEntity comme suit :

 
Sélectionnez
            // Envoi du paramètre ambiant
            if(shader->matColorAmbient != -1)
            {
                glUniform4fv(shader->matColorAmbient, 1, material->ambient);
            }
           
            // Envoi du paramètre diffus
            if(shader->matColorDiffuse != -1)
            {
                glUniform4fv(shader->matColorDiffuse, 1, material->diffuse);
            }
           
            // Envoi du paramètre spéculaire
            if(shader->matColorSpecular != -1)
            {
                glUniform4fv(shader->matColorSpecular, 1, material->specular);
            }
           
             // Envoi du paramètre de brillance
            if(shader->matShininess != -1)
            {
                glUniform1f(shader->matShininess, material->shininess);
            }

Passons ensuite au vertex shader. Nous commençons par construire la matrice tangente utilisée pour passer tous les vecteurs dans le même système de coordonnées tangent (espace tangent). Le vecteur direction de la lumière et demi-angle sont convertis vers l'espace tangent.

 
Sélectionnez
    // Calcul du vecteur bitangent  (ceci peut être fait sur le CPU)
    vec3 bitangent = cross(normal, tangent);
    // Création de la matrice de l'espace tangent 
    mat3 tangentSpace = mat3(tangent, bitangent, normal);
   
    // Obtention du vecteur direction de la lumière du vertex actuel
    v_lightVector =  lightPosModel - position.xyz  ;
    // Conversion du vecteur direction de la lumière vers l'espace tangent
    v_lightVector = v_lightVector * tangentSpace;
    // Normalisation
    v_lightVector = normalize(v_lightVector);

    // Obtention de la direction de la caméra du vertex actuel
    v_halfVector = camPosModel - position.xyz ;
    // Conversion vers l'espace tangent
    v_halfVector = v_halfVector * tangentSpace;
    // Normalisation
    v_halfVector = normalize(v_halfVector);
    // Calcul du vecteur demi-angle
    v_halfVector = (v_halfVector + v_lightVector) /2.0;
    // Normalisation
    v_halfVector = normalize(v_halfVector) ;

Dans le pixel shader, nous créons une normale par pixel, perturbée à partir de la normal map. Puis nous calculons la couleur finale du pixel par la somme des contributions ambiante, diffuse et spéculaire de la lumière.

 
Sélectionnez
    // Obtention de la couleur diffuse par vertex
    vec4 color  = texture2D(texture0, texCoord) ;
   
    // Obtention de la normale par pixel
    vec3 bump = texture2D(textureBump, texCoord).rgb * 2.0 - 1.0;
    // Inversion de la normale pour les faces arrière (si le face culling est activé, cette étape peut être supprimée)
    if (!gl_FrontFacing)
        bump = - bump;
   
    // Calcul de la contribution de la lumière
    // 1- lamber ou facteur diffus
    float lamber = max(0.0, dot(normalize(v_lightVector), bump) );
   
    //2- facteur spéculaire 
    float specular = 0.0;
    if (dot(bump, v_lightVector) < 0.0)
        specular = 0.0;
    else
        specular = max(0.0, pow(dot(normalize(v_halfVector), bump), matShininess)) ;

    // Obtention des couleurs finales ambiantes, diffuses et spéculaires 
    vec4 finalAmbientContrib  = lightColorAmbient  * color /** matColorAmbient.xyz*/;
    vec4 finalDiffuseContrib  = lightColorDiffuse  * color *  lamber * matColorDiffuse;
    vec4 finalSpecularContrib = lightColorSpecular  * specular * matColorSpecular;
   
    // La couleur finale est la somme des composantes ambiante, diffuse et spéculaire 
    gl_FragColor = finalAmbientContrib + (finalDiffuseContrib + finalSpecularContrib)  ;
Image non disponible
Scène éclairée sans relief
Image non disponible
Scène éclairée avec relief

précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Abdallah DIB. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.