IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

Problème de gestion de la transparence


Sujet :

OpenGL

  1. #1
    Membre averti
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Juillet 2013
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2013
    Messages : 15
    Par défaut Problème de gestion de la transparence
    Bonsoir,

    J'ai un petit problème de gestion de la transparence dans ma scène. J'ai un model qui possède des vitres et j'aimerais qu'on puisse voir à travers, quelles soient translucides sans être totalement transparentes.

    J'ai fais quelques screens pour vous montrer concrètement le problème :

    Vue du cockpit depuis l'extérieur, on voit bien que l'intérieur n'est pas correctement modélisé :
    -

    Vue du cockpit depuis l'intérieur, là c'est les vitres qui ne sont pas du tout modélisées :
    -

    Vue de côté :
    -

    Tous les matériaux transparents du model :
    -

    Dans mon code, la transparence est gérée dans la méthode bind() de la classe Material :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    void Material::bind()
    {
        m_uniformsBuffer.bind(BINDING_POINT);
     
        (m_twoSided != 1) ? glDisable(GL_CULL_FACE) : glEnable(GL_CULL_FACE);
     
        if(m_alphaBlending && m_blendMode != -1)
        {
            glEnable(GL_BLEND);
     
            switch(m_blendMode)
            {
            case BlendMode::Additive:
                glBlendFunc(GL_ONE, GL_ONE);
                break;
     
            case BlendMode::Default:
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                break;
            }
        }
        else
        {
            glDisable(GL_BLEND);
        }
     
    }
    La récupération des propriétés des matériaux se fait dans la méthode loadMaterial() de la classe ModelLoader :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    MaterialData ModelLoader::loadMaterial(unsigned int index, const aiMaterial* material)
    {
        [...]
     
        int twoSided = 1;
     
        if(material->Get(AI_MATKEY_TWOSIDED, twoSided) == AI_SUCCESS)
        {
            data.twoSided = twoSided;
        }
     
        float opacity = 1.0f;
     
        if(material->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS)
        {
            data.ambientColor.setW(opacity);
            data.diffuseColor.setW(opacity);
            data.specularColor.setW(opacity);
            data.emissiveColor.setW(opacity);
     
            if(opacity < 1.0f)
            {
                data.alphaBlending = true;
                data.twoSided = 1;
     
                int blendMode = aiBlendMode_Default;
     
                if(material->Get(AI_MATKEY_BLEND_FUNC, blendMode) == AI_SUCCESS)
                {
                    if(blendMode == aiBlendMode_Additive)
                        data.blendMode = aiBlendMode_Additive;
                    else
                        data.blendMode = aiBlendMode_Default;
                }
            }
            else
            {
                data.alphaBlending = false;
                data.blendMode = -1;
            }
        }
     
        [...]
     
        return data;
    }
    Lors de l'initialisation de ma scène, j'ai activé le test de profondeur (Depth Testing) et le backface culling. Je pense que le problème doit survenir lors du test de profondeur, tout ce qui se trouve derrière une surface transparente doit échouer lors de ce test et donc être ignoré, c'est bien ça ?

    Voici ce que dit la doc d'OpenGL :

    - If I draw a translucent primitive and draw another primitive behind it, I expect the second primitive to show through the first, but it's not there ?

    If you're drawing a polygon that's behind another polygon, and depth test is enabled, then the new polygon will typically lose the depth test, and no blending will occur. On the other hand, if you've disabled depth test, the new polygon will be blended with the existing polygon, regardless of whether it's behind or in front of it.

    - Do I need to render my primitives from back to front for correct rendering of translucent primitives to occur ?

    If your hardware supports destination alpha, you can experiment with different glBlendFunc() settings that use destination alpha. However, this won't solve all the problems with depth buffered translucent surfaces. The only sure way to achieve visually correct results is to sort and render your primitives from back to front.
    Donc j'ai fait ce qu'a dit la doc, j'ai désactivé le depth testing lorsque la surface est translucide :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    void Material::bind()
    {
        m_uniformsBuffer.bind(BINDING_POINT);
    
        (m_twoSided != 1) ? glDisable(GL_CULL_FACE) : glEnable(GL_CULL_FACE);
    
        if(m_alphaBlending && m_blendMode != -1)
        {
            glEnable(GL_BLEND);
            glDisable(GL_DEPTH_TEST);
    
            switch(m_blendMode)
            {
            case BlendMode::Additive:
                glBlendFunc(GL_ONE, GL_ONE);
                break;
    
            case BlendMode::Default:
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                break;
            }
        }
        else
        {
            glEnable(GL_DEPTH_TEST);
            glDisable(GL_BLEND);
        }
    
    }
    Voila le résultat :



    Sur ce screen on peut voir que les vitres arrières (les deux rectangles gris) sont visibles alors qu'elles ne le devraient pas. Le casque du pilote doit avoir un aspect vert à cause de la vitre au dessus du cockpit mais là ce n'est pas le cas...

    Quelqu'un aurait une idée pour résoudre ces problèmes ? Comment gérer la transparence correctement avec OpenGL ?

    Le reste du code source est dispo dans mon dépôt sur github, si ça peut vous aider, voila le lien : https://github.com/hardware/ObjectVi...ree/master/src
    Images attachées Images attachées      

  2. #2
    Expert confirmé

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 035
    Billets dans le blog
    12
    Par défaut
    Pour rendre plus ou moins correctement l'alpha blending, une premère chose est de décomposer le rendu :
    • D'abord rendre les objets non transparents ;
    • Trier les faces des objets transparents de la plus lointaine à la plus proche ;
    • Rendre les objets transparents.


    Une autre méthode peut être d'utiliser l'alpha to coverage, mais il faut d'abord activer le multisampling.
    Cette méthode te permettra de ne pas avoir à trier tes faces (mais tu devras quand même séparer le rendu des objets transparents et des opaques).
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  3. #3
    Membre averti
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Juillet 2013
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2013
    Messages : 15
    Par défaut
    ok donc j'ai modifié la méthode de rendu des models en suivant tes conseils (en décomposant le rendu) et ça marche nickel :



    Par contre je trouve que la boucle de rendu de la classe Model n'est pas optimisée. Avec la décomposition du rendu, je dois parcourir le tableau contenant les meshes deux fois :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    void Model::render()
    {
        m_vao->bind();
    
        for(unsigned int i = 0; i < m_meshes.size(); i++)
        {
            if( m_materials[i] != nullptr && ! m_materials[i]->isTranslucent() )
            {
                if(m_textures[i] != nullptr)
                {
                    m_textures[i]->bind(GL_TEXTURE0);
                }
    
                m_materials[i]->bind();
    
                drawElements(i, DrawingMode::Indexed | DrawingMode::BaseVertex);
            }
        }
    
        for(unsigned int i = 0; i < m_meshes.size(); i++)
        {
            if( m_materials[i] != nullptr && m_materials[i]->isTranslucent() )
            {
                glDepthMask(GL_FALSE);
                glEnable(GL_BLEND);
    
                m_materials[i]->bind();
    
                drawElements(i, DrawingMode::Indexed | DrawingMode::BaseVertex);
    
                glDisable(GL_BLEND);
                glDepthMask(GL_TRUE);
            }
        }
    
        m_vao->release();
    }
    Je vois pas comment faire pour gérer la décomposition du rendu sans parcourir deux fois le tableaux des meshes.
    Images attachées Images attachées  

  4. #4
    Expert confirmé

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 035
    Billets dans le blog
    12
    Par défaut
    Là, ça devient rigolo !
    Ce que je fais c'est séparer mes meshes en submeshes (ce que j'ail l'impression que tu fais avec ton paramètre "i" de ta fonction "drawElements").
    Je stocke donc 2 listes : celle avec les submeshes ayant un matériau avec de l'alpha blend (ou au moins une passe si les matériaux sont multi-passes) et celle avec les submeshes ayant un matériau n'ayant pas d'alpha blend.
    Ensuite je rends la première liste, puis la seconde.
    La création et la modification de ces 2 listes s'effectue lorsqu'on modifie un matériau ou qu'on ajoute/supprime une géométrie.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  5. #5
    Membre averti
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Juillet 2013
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2013
    Messages : 15
    Par défaut
    Je viens d'essayer ton idée. J'ai crée deux tableaux, un pour les meshes ayant un matériau avec l'alpha blend et un autre pour les meshes ayant un matériau opaque. Mais j'ai du faire une erreur lors du remplissage de ces deux tableaux... :



    Il doit y avoir un problème avec les indices des meshes mais je vois pas pourquoi...

    C'est dans cette méthode que je remplis les deux tableaux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    void Model::initialize(vector<shared_ptr<ModelData>> modelData)
    {
        QOpenGLContext* context = QOpenGLContext::currentContext();
    
        Q_ASSERT(context);
    
        m_funcs = context->versionFunctions<QOpenGLFunctions_4_3_Core>();
        m_funcs->initializeOpenGLFunctions();
    
        m_meshManager     = m_scene->meshManager();
        m_textureManager  = m_scene->textureManager();
        m_materialManager = m_scene->materialManager();
    
        for(shared_ptr<ModelData>& data : modelData)
        {
            if(data->materialData.alphaBlending)
            {
                shared_ptr<Mesh> mesh = m_meshManager->getMesh(data->meshData.name);
    
                if(mesh == nullptr)
                {
                    mesh = m_meshManager->addMesh(data->meshData.name,
                                                  data->meshData.numIndices,
                                                  data->meshData.baseVertex,
                                                  data->meshData.baseIndex);
                }
    
                m_translucentMeshes.push_back(mesh);
            }
            else
            {
                shared_ptr<Mesh> mesh = m_meshManager->getMesh(data->meshData.name);
    
                if(mesh == nullptr)
                {
                    mesh = m_meshManager->addMesh(data->meshData.name,
                                                  data->meshData.numIndices,
                                                  data->meshData.baseVertex,
                                                  data->meshData.baseIndex);
                }
    
                m_opaqueMeshes.push_back(mesh);
            }
    
            if(data->textureData.hasTexture)
            {
                shared_ptr<Texture> texture = m_textureManager->getTexture(data->textureData.filename);
    
                if(texture == nullptr)
                {
                    texture = m_textureManager->addTexture(data->textureData.filename);
                }
    
                m_textures.push_back(texture);
            }
            else
            {
                m_textures.push_back(nullptr);
            }
    
            shared_ptr<Material> material = m_materialManager->getMaterial(data->materialData.name);
    
            if(material == nullptr)
            {
                material = m_materialManager->addMaterial(data->materialData.name,
                                                          data->materialData.ambientColor,
                                                          data->materialData.diffuseColor,
                                                          data->materialData.specularColor,
                                                          data->materialData.emissiveColor,
                                                          data->materialData.shininess,
                                                          data->materialData.shininessStrength,
                                                          data->materialData.twoSided,
                                                          data->materialData.blendMode,
                                                          data->materialData.alphaBlending,
                                                          data->textureData.hasTexture);
            }
    
            m_materials.push_back(material);
        }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    void Model::render()
    {
        m_vao->bind();
    
        for(unsigned int i = 0; i < m_opaqueMeshes.size(); i++)
        {
            if(m_materials[i] != nullptr)
            {
                if(m_textures[i] != nullptr)
                {
                    m_textures[i]->bind(GL_TEXTURE0);
                }
    
                m_materials[i]->bind();
    
                drawElements(i, DrawingMode::Indexed | DrawingMode::BaseVertex, m_opaqueMeshes);
            }
        }
    
        for(unsigned int i = 0; i < m_translucentMeshes.size(); i++)
        {
            if(m_materials[i] != nullptr)
            {
                glDepthMask(GL_FALSE);
                glEnable(GL_BLEND);
    
                m_materials[i]->bind();
    
                drawElements(i, DrawingMode::Indexed | DrawingMode::BaseVertex, m_translucentMeshes);
    
                glDisable(GL_BLEND);
                glDepthMask(GL_TRUE);
            }
        }
    
        m_vao->release();
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void Model::drawElements(unsigned int index, int mode, vector<shared_ptr<Mesh>>& meshes)
    {
        // Mode non géré pour l'instant
        Q_UNUSED(mode);
     
        m_funcs->glDrawElementsBaseVertex(
            GL_TRIANGLES,
            meshes[index]->getNumIndices(),
            GL_UNSIGNED_INT,
            reinterpret_cast<void*>((sizeof(unsigned int)) * meshes[index]->getBaseIndex()),
            meshes[index]->getBaseVertex()
        );
    }
    EDIT :
    Petite précision : Dans mon projet, un model c'est un objet entier et un mesh c'est une partie de cet objet (un submesh pour toi).

    EDIT 2 :
    Je passe le sujet en résolu comme le problème initial a été réglé. Le reste c'est de l'optimisation, je chercherai de mon côté. Merci dragonjoker59 pour ton aide
    Images attachées Images attachées  

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problème de gestion d'erreurs
    Par champijulie dans le forum PostgreSQL
    Réponses: 3
    Dernier message: 13/05/2005, 17h18
  2. Problème de gestion d'un octree
    Par MaxPayne dans le forum OpenGL
    Réponses: 9
    Dernier message: 06/04/2005, 10h17
  3. problème de gestion de fenêtre
    Par clemsouz dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 03/11/2004, 14h35
  4. Problème de gestion fichiers
    Par glutock dans le forum ASP
    Réponses: 2
    Dernier message: 08/04/2004, 11h55
  5. [TFrame] Problème de gestion du OnMouseDown avec une Frame
    Par xherault dans le forum Composants VCL
    Réponses: 5
    Dernier message: 23/05/2003, 15h35

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo