Bonjour, je suis entrain de coder un petit simulateur censé afficher un paysage avec montagnes et vallées, arbres, rivières ... Pour le moment, j'ai créé un maillage pour le sol sculpté grâce à une heihtmap générée par Perlin Noise. J'ai ensuite codé un fragment shader pour afficher différentes textures selon l'altitude (Sable, herbe, neige). J'ai ensuite ajouté des arbres, cette partie n'est pas encore tout à fait terminé mais je m'attaque tout de même à un point délicat : Les ombres. J'utilise OpenGL 2.1 et je code en C++ ; pour les ombres, j'utilise un FBO afin de stocker le contenu du Z-buffer dans une texture (La shadowmap), j'effectue ensuite deux passes du rendu, une première en projection ortho où la caméra est positionnée à la place de la source de lumière et où je récupère les matrices de modelview et de projection et une deuxième pour le rendu normal. Dans celle-ci, les matrices de la première passe sont envoyées au vertex shader afin de calculer la profondeur de chaque sommet du point de vue de la source de lumière avant de l'envoyer au fragment shader, puis la shadowmap est envoyée au fragment shader qui calcule pour le fragment en cours sa position équivalente dans la shadowmap et en déduit la profondeur du point le plus proche de la caméra dans l'alignement du fragment, puis cette profondeur est comparée à celle du fragment calculée par le vertex shader ; si celle-ci est supérieure à celle retrouvée dans la shadowmap, alors ça signifie qu'il y a un objet entre le fragment et la source de lumière, donc le fragment est assombri.
Voici mon code simplifié :
Initialisation du FBO :
Rendu :Code:bool SHD_InitFBO(SHD_TypeFBO type,SHD_FBO *fbo,const int wWindow,const int hWindow) { glGenFramebuffers(1,&fbo->buffer); //Création FBO glGenTextures(1,&fbo->shadowMap); glBindTexture(GL_TEXTURE_2D,fbo->shadowMap); if(type==SHD_DEPTH_BUFFER) { glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT,wWindow,hWindow,0,GL_DEPTH_COMPONENT,GL_FLOAT,NULL); //Allocation mémoire shadowmap glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); //Paramètres texture glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); glBindFramebuffer(GL_FRAMEBUFFER,fbo->buffer); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,fbo->shadowMap,0); //Attachement FBO-texture } glDrawBuffer(GL_NONE); //Accès tampon couleur interdit en lecture et écriture glReadBuffer(GL_NONE); GLenum status=glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status!=GL_FRAMEBUFFER_COMPLETE) { printf("Erreur frame buffer : 0x%x\n",status); return false; } else return true; }
Fonction SHD_FBO_StartFirstPass() :Code:float cibleSun[3]={cam->getPosition()[0],cam->getPosition()[1],cam->getPosition()[2]}; //La source de lumière est orientée vers la caméra SHD_FBO_StartFirstPass(&fbo,posSun,cibleSun,-100,100,-100,100,NEAR_LIGHT,FAR_LIGHT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-100,100,-100,100,NEAR_LIGHT,FAR_LIGHT); //Paramètres projection glClear(GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); posSun[0]=cam->getPosition()[0]+DIST_SUN*cos(angleSoleilH*M_PI/180)*cos(angleSoleilV*M_PI/180); posSun[1]=cam->getPosition()[1]+DIST_SUN*sin(angleSoleilH*M_PI/180); posSun[2]=cam->getPosition()[2]-DIST_SUN*cos(angleSoleilH*M_PI/180)*sin(angleSoleilV*M_PI/180); gluLookAt(posSun[0],posSun[1],posSun[2],cibleSun[0],cibleSun[1],cibleSun[2],0,0,1); //Positionnement source de lumière //Rendu ... SHD_FBO_EndFirstPass(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(FOVY,4.0/3,NEAR,FAR); //Projection perspective glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(cam->getPosition()[0],cam->getPosition()[1],cam->getPosition()[2], cam->getCible()[0],cam->getCible()[1],cam->getCible()[2],0,0,1); //Positionnement caméra SHD_FBO_StartShadows(shader,&fbo,6); //Rendu ... SHD_FBO_EndShadows(shader);
Fonction SHD_FBO_EndFirstPass() :Code:void SHD_FBO_StartFirstPass(SHD_FBO *fbo,const float *posLight,const float *targetLight,const float left,const float right,const float bottom,const float top,const float nearLight,const float farLight) { glBindFramebuffer(GL_FRAMEBUFFER,fbo->buffer); fbo->projectionLum=glm::mat4(1.0); fbo->projectionLum=glm::ortho(left,right,bottom,top,nearLight,farLight); //Récupération matrice de projection glm::vec3 pos(posLight[0],posLight[1],posLight[2]); glm::vec3 cible(targetLight[0],targetLight[1],targetLight[2]); glm::vec3 up(0,0,1); fbo->modelviewLum=glm::mat4(1.0); fbo->modelviewLum=glm::lookAt(pos,cible,up); //Récupération matrice modelview }
Fonction SHD_FBO_StartShadows() :Code:void SHD_FBO_EndFirstPass(void) { glBindFramebuffer(GL_FRAMEBUFFER,0); }
Fonction SHD_FBO_EndShadows() :Code:void SHD_FBO_StartShadows(const GLuint shader,SHD_FBO *fbo,const int numTexShadowmap) { glUniform1i(glGetUniformLocation(shader,"enableShadows"),true); glUniformMatrix4fv(glGetUniformLocation(shader,"projectionLight"),1,false,glm::value_ptr(fbo->projectionLum)); glUniformMatrix4fv(glGetUniformLocation(shader,"modelviewLight"),1,false,glm::value_ptr(fbo->modelviewLum)); //Envoi matrices au vertex shader if(numTexShadowmap==1) glActiveTexture(GL_TEXTURE1); else if(numTexShadowmap==2) glActiveTexture(GL_TEXTURE2); else if(numTexShadowmap==3) glActiveTexture(GL_TEXTURE3); else if(numTexShadowmap==4) glActiveTexture(GL_TEXTURE4); else if(numTexShadowmap==5) glActiveTexture(GL_TEXTURE5); else if(numTexShadowmap==6) glActiveTexture(GL_TEXTURE6); else if(numTexShadowmap==7) glActiveTexture(GL_TEXTURE7); else if(numTexShadowmap==8) glActiveTexture(GL_TEXTURE8); else if(numTexShadowmap==9) glActiveTexture(GL_TEXTURE9); else if(numTexShadowmap==10) glActiveTexture(GL_TEXTURE10); else if(numTexShadowmap==11) glActiveTexture(GL_TEXTURE11); else if(numTexShadowmap==12) glActiveTexture(GL_TEXTURE12); else if(numTexShadowmap==13) glActiveTexture(GL_TEXTURE13); glBindTexture(GL_TEXTURE_2D,fbo->shadowMap); glActiveTexture(GL_TEXTURE0); glUniform1i(glGetUniformLocation(shader,"tex"),0); //Envoi texture en cours au fragment shader glUniform1i(glGetUniformLocation(shader,"shadowMap"),numTexShadowmap); //Envoi shadowmap au fragment shader }
Vertex shader :Code:void SHD_FBO_EndShadows(const GLuint shader) { glUniform1i(glGetUniformLocation(shader,"enableShadows"),false); }
Fragment shader :Code:#version 120 uniform bool enableShadows=false; uniform mat4 projectionLight; //Matrice point de vue source de lumière uniform mat4 modelviewLight; out vec4 posLight; //Profondeur envoyée au fragment shader void main(void) { vec4 vertex=gl_Vertex; gl_Position=gl_ModelViewProjectionMatrix*vertex; //Gestion éclairage ... if(enableShadows) { vertex.w=1.0; posLight=projectionLight*modelviewLight*vertex; //Calcul profondeur point de vue source de lumière } gl_TexCoord[0]=gl_MultiTexCoord0; }
Sans le paramètre bias du fragment shader, j'obtiens un résultat un peu étrange sur le sol :Code:#version 120 uniform sampler2D tex; uniform bool enableShadows=false; in vec4 posLight; //Profondeur calculée par le vextex shader uniform sampler2D shadowMap; void main(void) { //Texturing ... if(enableShadows) { vec3 posLight3D; vec2 coordTexShadowMap; posLight3D.x=posLight.x/posLight.w; //Calcul projection posLight3D.y=posLight.y/posLight.w; posLight3D.z=posLight.z/posLight.w; coordTexShadowMap.x=0.5*posLight3D.x+0.5; //Calcul texel équivalent shadowmap coordTexShadowMap.y=0.5*posLight3D.y+0.5; const float bias=0.00005; //Marge d'erreur { float distLumPoint=0.5*posLight3D.z+0.5; //Distance lumière-fragment float distLumPointProche=texture2D(shadowMap,coordTexShadowMap).x; //Distance lumière-fragment le plus proche dans le même alignement if(distLumPointProche<distLumPoint+bias) { gl_FragColor[0]/=2.0; //Assombrissement gl_FragColor[1]/=2.0; gl_FragColor[2]/=2.0; } } } }
Forum1-1.jpg
Avec le paramètre bias, ça donne une espèce d'ombre permanente surgie de je ne sais où :
Forum2.jpg
Cette ombre apparaît et disparaît par intermittence lorsque la caméra se déplace et de plus, l'ombre des arbres n'est pas très jojo :
Forum3.jpg
Voilà, je ne vois pas ce qui cloche dans mon code, si quelqu'un peut m'aider merci beaucoup.
-----