Bonjour, je sui actuellement dans un projet 3D avec OpenGL 3 et je fais face à un léger problème : Si par exemple une face est tournée vers le Soleil elle sera pleinement éclairée et ce que l’on soit devant ou derrière la face, alors que si la face est observée en contre-jour elle est censée apparaître sombre. Pour remédier à cela il suffit d’inverser le sens des normales lorsque la caméra est derrière la face, mais encore faut-il détecter si la caméra est derrière la face, a priori rien de plus simple :
Selon le signe du produit scalaire on sait si la caméra est devant ou derrière la face et selon le cas on va prendre la normale ou son opposée :
Le problème c’est que je constate des défauts d’affichage sans comprendre l’origine du problème :
Je ne comprends pas d’où peuvent bien venir ces zones sombres, ça sous-entend qu’à certains endroits l’angle normale-vecteurVertexCam est obtu et pourtant je me suis bien assuré que les normales pointaient vers le haut, la caméra est bien "devant" les faces
Le décor est créé avec Blender 2.93, les sommets, attributs et matériaux sont stockés dans des fichiers .obj et .mtl.
Voici le code simplifié :
typedef struct OBJ2_VBO //Structure représentant le VBO
{
std::vector<float> coordVertices;
std::vector<float> coordTex;
std::vector<float> normals;
std::vector<float> colorDiff;
std::vector<float> colorSpec;
std::vector<GLuint> textures;
std::vector<int> attribNumtex;
GLuint bufferVRAM;
GLuint VAO;
}OBJ2_VBO;
Chargement :
bool OBJ2_LoadOBJ(std::string path,OBJ2_VBO *vbo,const bool mipmap)
{
//Lecture fichiers .obj et .mtl et stockage dans vbo->coordVertices, vbo->coordTex, ...
glGenVertexArrays(1,&vbo->VAO);
glGenBuffers(1,&vbo->bufferVRAM);
glBindVertexArray(vbo->VAO);
glBindBuffer(GL_ARRAY_BUFFER,vbo->bufferVRAM); //Bindage vers espace mémoire VRAM
glBufferData(GL_ARRAY_BUFFER,vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)+vbo->normals.size()*sizeof(float)+vbo->colorDiff.size()*sizeof(float)+vbo->colorSpec.size()*sizeof(float)+vbo->attribNumtex.size()*sizeof(int),nullptr,GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER,0,vbo->coordVertices.size()*sizeof(float),&vbo->coordVertices[0]); //Mise en mémoire coordonnées vertices
if(vbo->coordTex.size()!=0)
glBufferSubData(GL_ARRAY_BUFFER,vbo->coordVertices.size()*sizeof(float),vbo->coordTex.size()*sizeof(float),&vbo->coordTex[0]); //Mise en mémoire coordonnées texture
if(vbo->normals.size()!=0)
glBufferSubData(GL_ARRAY_BUFFER,vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float),vbo->normals.size()*sizeof(float),&vbo->normals[0]); //Mise en mémoire normales
if(vbo->colorDiff.size()!=0)
glBufferSubData(GL_ARRAY_BUFFER,vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)+vbo->normals.size()*sizeof(float),vbo->colorDiff.size()*sizeof(float),&vbo->colorDiff[0]); //Mise en mémoire couleurs
if(vbo->colorSpec.size()!=0)
glBufferSubData(GL_ARRAY_BUFFER,vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)+vbo->normals.size()*sizeof(float)+vbo->colorDiff.size()*sizeof(float),vbo->colorSpec.size()*sizeof(float),&vbo->colorSpec[0]);
if(vbo->attribNumtex.size()!=0)
glBufferSubData(GL_ARRAY_BUFFER,vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)+vbo->normals.size()*sizeof(float)+vbo->colorDiff.size()*sizeof(float)+vbo->colorSpec.size()*sizeof(float),vbo->attribNumtex.size()*sizeof(int),&vbo->attribNumtex[0]); //Mise en mémoire attributs
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,2*sizeof(float),(void*)(vbo->coordVertices.size()*sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)(vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(3,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)(vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)+vbo->normals.size()*sizeof(float)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(4,3,GL_FLOAT,GL_FALSE,3*sizeof(float),(void*)(vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)+vbo->normals.size()*sizeof(float)+vbo->colorDiff.size()*sizeof(float)));
glEnableVertexAttribArray(4);
glVertexAttribIPointer(5,1,GL_INT,sizeof(int),(void*)(vbo->coordVertices.size()*sizeof(float)+vbo->coordTex.size()*sizeof(float)+vbo->normals.size()*sizeof(float)+vbo->colorDiff.size()*sizeof(float)+vbo->colorSpec.size()*sizeof(float)));
glEnableVertexAttribArray(5);
glBindBuffer(GL_ARRAY_BUFFER,0);
glBindVertexArray(0);
}
Rendu :
void OBJ2_DrawVBO(OBJ2_VBO *vbo,const GLuint shader)
{
int compteurVBOs=0;
glBindVertexArray(vbo->VAO);
if(shader!=0)
{
if(vbo->textures.size()!=0) //Envoi textures au fragment shader
{
int texShader[vbo->textures.size()];
int compteurTex=0;
while(1)
{
glActiveTexture(GL_TEXTURE0+compteurTex);
glBindTexture(GL_TEXTURE_2D,vbo->textures[compteurTex]);
texShader[compteurTex]=compteurTex;
compteurTex++;
if(compteurTex==vbo->textures.size())
break;
}
glUniform1iv(glGetUniformLocation(shader,"tex"),vbo->textures.size(),texShader);
}
}
glDrawArrays(GL_TRIANGLES,0,vbo->coordVertices.size()/3); //Rendu
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(0);
}
{
glUseProgram(shaderBasique);
glUniformMatrix4fv(glGetUniformLocation(shaderBasique,"projection"),1,false,glm::value_ptr(cam->getMatriceProjection()));
glUniformMatrix4fv(glGetUniformLocation(shaderBasique,"modele"),1,false,glm::value_ptr(cam->getMatriceModele()));
glUniformMatrix4fv(glGetUniformLocation(shaderBasique,"vue"),1,false,glm::value_ptr(cam->getMatriceVue()));
//Envoi matrices au vertex shader
glUniform3f(glGetUniformLocation(shaderBasique,"posSoleil"),posSoleil.x,posSoleil.y,posSoleil.z);
glUniform3f(glGetUniformLocation(shaderBasique,"posCam"),cam->getPosition().x,cam->getPosition().y,cam->getPosition().z);
OBJ2_DrawVBO(...);
}
Vertex shader :
#version 330 core
layout (location=0) in vec3 vertex;
layout (location=1) in vec2 coordTex;
layout (location=2) in vec3 normale;
layout (location=3) in vec3 colorDiff;
layout (location=4) in vec3 colorSpec;
layout (location=5) in int numtex;
uniform mat4 projection;
uniform mat4 modele;
uniform mat4 vue;
uniform vec3 posCam;
out vec2 coordTexFrag;
out vec3 normaleFrag;
out vec3 couleurFrag;
flat out int numtexFrag;
void main(void)
{
vec4 vertex2=vec4(vertex,1.0);
gl_Position=projection*vue*modele*vertex2;
coordTexFrag=coordTex;
numtexFrag=numtex;
vec3 vecteurVertCam=normalize(vec3(posCam.x-vertex.x,posCam.y-vertex.y,posCam.z-vertex.z));
if(dot(vecteurVertCam,normalize(normale))>=0.0) //C'est ici qu'on détecte si la caméra est devant ou derrière la face
normaleFrag=normalize(normale);
else
normaleFrag=-normalize(normale);
couleurFrag=colorDiff;
}
Fragment shader :
#version 330 core
uniform sampler2D tex[32];
uniform vec3 posSoleil;
in vec2 coordTexFrag;
flat in int numtexFrag;
in vec3 normaleFrag;
in vec3 couleurFrag;
out vec4 FragColor;
void main(void)
{
float facteurEclairage=dot(posSoleil,normaleFrag); //Calcul éclairage selon inclinaison rayons Soleil
facteurEclairage=clamp(facteurEclairage,0.15,1.0);
vec4 couleurFinale;
if(numtexFrag!=-1)
couleurFinale=texture(tex[numtexFrag],coordTexFrag)*vec4(couleurFrag,1.0);
else
couleurFinale=vec4(couleurFrag,1.0);
couleurFinale[0]*=facteurEclairage;
couleurFinale[1]*=facteurEclairage;
couleurFinale[2]*=facteurEclairage;
FragColor=couleurFinale;
}
Merci par avance si quelqu’un parvient à résoudre ce mystère