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 :
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 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); } }
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 ?
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; }
Voici ce que dit la doc d'OpenGL :
Donc j'ai fait ce qu'a dit la doc, j'ai désactivé le depth testing lorsque la surface est translucide :- 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.
Voila le résultat :
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); } }
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
Partager