[OpenGL 3] Savoir si la caméra est derrière une face

Problème étrange

a marqué ce sujet comme résolu.

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 :

Caméra devant la face
Caméra devant la face

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 :

Caméra derrière la face
Caméra derrière la face

Le problème c’est que je constate des défauts d’affichage sans comprendre l’origine du problème :

Capture d'écran
Capture d’écran

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

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte