Tutoriels iOS


précédentsommairesuivant

VIII. Tutoriel 6. Réflexion de l'eau

Ce tutoriel montre comment on peut implémenter la réflexion de surface en temps réel. La partie la plus importante est le rendu de la texture de réflexion basé sur la position de la caméra. Nous utilisons un Frame Buffer Object (FBO) pour effectuer un rendu offscreen du reflet de la scène dans une texture. Cette texture est passée à un shader pour simuler la surface de l'eau.

Image non disponible

Pour trouver la position de la caméra miroir, nous avons à partir du schéma ci-dessus :

 
Sélectionnez
Zc = Zb + 2 * x Eq 1)
where x = H - Zb

En substituant x dans l'équation (Eq 1), la hauteur finale de la position du reflet est égale à :

 
Sélectionnez
Zb = 2H - Zc 

VIII-A. Code de la procédure

Dans CwaterEntity, nous créons une cible de rendu offscreen avec une texture couleur et un buffer de rendu de profondeur. La fonction PrepareReflectionPass active le frame buffer object pour le rendu offscreen, et nous retrouvons les positions de la caméra miroir et de la cible comme expliqué avant :

 
Sélectionnez
    // Activation du FBO pour le rendu offscreen
    m_pOffscreenRT->Enable();

    // Envoi de la hauteur de l'eau au shader et activation du rejet, pour couper tous les objets sous l'eau
    shader->SetUniform1i("enableDiscardScene",1) ;
    shader->SetUniform1f("waterHeight", m_fWaterHeight);
   
    // Effacement du contexte
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    vec3f camPos = camera->GetPosition(); // Position de la caméra
    vec3f camTarget = camPos + camera->GetForwardVector();// Cible 

    // Si la caméra est au-dessus de l'eau, inverser sa position
    if(camPos.z >= m_fWaterHeight)
    {
       
        // Position de la caméra miroir 
        camPos.z = 2.0f * m_fWaterHeight - camPos.z;
        camTarget.z = 2.0f * m_fWaterHeight - camTarget.z;

        vec3f forwardVector = camTarget - camPos; // Trouver le vecteur forward à partir des nouvelles positions
        vec3f sideVector = camera->GetRigthVector(); // Obtention du vecteur right
        vec3f reflectionCamUp = sideVector.crossProduct(forwardVector); //Obtention du vecteur up
       
        // Mise en place de la matrice vue miroir 
        mat4f m;
        m = mat4f::createLookAt(camPos, camTarget, reflectionCamUp);
        m_mLookAt =  m_mMirror * m;
    }

Maintenant que nous avons la texture de réflexion, la prochaine étape est de l'utiliser pour effectuer le rendu de la surface de l'eau. La surface de l'eau est composée d'un simple rectangle auquel nous appliquons la texture de la réflexion. Pour troubler la texture de la réflexion, nous utilisons une texture normale sur différentes directions u,v.

Dans le pixel shader, nous utilisons deux coordonnées de texture avec un facteur de répétition pour créer la texture normale. Les coordonnées de la texture résultante sont combinées avec les coordonnées du fragment pour créer la texture miroir :

 
Sélectionnez
   // Définition du nombre de tuiles de la surface d'eau (répétition de la texture)
    const float tile_factor = 20.0;
    const float noise_factor = 0.03;
   
    vec2 texCoordNormal0 = v_texCoord * tile_factor;
    texCoordNormal0 += time ;

    vec2 texCoordNormal1 = v_texCoord * tile_factor;
    texCoordNormal1.s -= time ;
    texCoordNormal1.t += time ;

// Coordonnées tex utilisées pour troubler le vecteur texCoordReflection
    vec3 normal0 = texture2D(normal, texCoordNormal0).rgb * 2.0 - 1.0;
    vec3 normal1 = texture2D(normal, texCoordNormal1).rgb * 2.0 - 1.0;
    vec3 normal = normalize(normal0 + normal1);
   
    // Ajustement des coordonnées de la texture selon la taille de l'écran
    vec2 texCoordReflection = vec2(gl_FragCoord.x * screenWidth, gl_FragCoord.y * screenHeight);
   
    // Les coordonnées de la texture finale sont troublées par la normale multipliée par un facteur de bruit
    vec2 texCoordFinal = texCoordReflection.xy + noise_factor * normal.xy;

    gl_FragColor =  texture2D( texture0, texCoordFinal); 

Dans ce tutoriel nous ne traitons pas le cas où la caméra se situe en dessous de la surface, situation dans laquelle nous avons besoin d'une passe supplémentaire pour faire la capture de la texture de réfraction. En réalité, sous l'eau nous pouvons toujours voir le monde réfracté, cette texture additionnelle est utilisée pour simuler l'effet de réfraction. La couleur finale est obtenue par le mélange des textures de réflexion et réfraction selon la formule de Fresnel.

Le but du tutoriel était de présenter une simulation simple et rapide de réflexion d'eau sur mobile. Vous pourrez trouver des simulations de surfaces d'eau plus avancées sur le net.

Pour optimiser, nous pouvons réduire la taille de la texture de réflexion en réduisant la taille du frame buffer object de sortie dans le CwaterEntity. La taille actuelle est fixée à 256, essayez différentes valeurs pour entrevoir l'impact sur la qualité/performance.

 
Sélectionnez
m_pOffscreenRT->Initialize(kCONTEXT_COLOR | kCONTEXT_DEPTH,  256);

Une autre optimisation consiste à remplacer l'opération de rejet du pixel shader lors du rendu du terrain. Cette opération est utilisée pour ne pas prendre en compte les pixels situés au-dessus de l'eau lors de la capture de la texture de réflexion. Ce qui pourrait être effectué en ajustant les plans de coupe de la matrice de projection.

Voir le SDK de Imagination Technologies (exemple de réflexion d'eau).

Image non disponible

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.