OpenGL et GLSL, ombres
Répondre à la discussion
Affichage des résultats 1 à 2 sur 2

OpenGL et GLSL, ombres



  1. #1
    CaptainElec

    OpenGL et GLSL, ombres


    ------

    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 :

    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;
    }
    Rendu :

    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_StartFirstPass() :

    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_EndFirstPass() :
    Code:
    void SHD_FBO_EndFirstPass(void)
    {
        glBindFramebuffer(GL_FRAMEBUFFER,0);
    }
    Fonction SHD_FBO_StartShadows() :

    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
    }
    Fonction SHD_FBO_EndShadows() :

    Code:
    void SHD_FBO_EndShadows(const GLuint shader)
    {
        glUniform1i(glGetUniformLocation(shader,"enableShadows"),false);
    }
    Vertex 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;
    }
    Fragment shader :

    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;
    			}
    		}
    	}
    }
    Sans le paramètre bias du fragment shader, j'obtiens un résultat un peu étrange sur le sol :

    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.

    -----
    Images attachées Images attachées  

  2. #2
    CaptainElec

    Re : OpenGL et GLSL, ombres

    Re, j'ai résolu une partie du problème, c'est une erreur toute bête dans le fragment shader :

    Code:
    if(distLumPointProche<distLumPoint+bias)
    C'est en fait :

    Code:
    if(distLumPointProche<distLumPoint-bias)
    Au passage, les ombres sont bien plus belles.
    J'ai un autre problème qui est apparu du coup, il y a un écart entre chaque arbre et son ombre respective, je me suis renseigné et ce problème est courant lorsqu'on manipule des ombres avec OpenGL et s'appelle le Peter Panning (Référence à Peter Pan car on a l'impression que l'arbre est en lévitation) et il est dit que la solution consiste à épaissir les surfaces, mais dans mon projet je ne peux pas épaissir le sol car ça fausserait la gestion de la gravité.

Discussions similaires

  1. Différences entre "uniforme" et "varying" variable (GLSL)
    Par invite1b8cbfb5 dans le forum Programmation et langages, Algorithmique
    Réponses: 0
    Dernier message: 14/01/2017, 16h18
  2. [ada]Gtk+opengl
    Par invite5b15e04d dans le forum Programmation et langages, Algorithmique
    Réponses: 6
    Dernier message: 24/10/2015, 19h04
  3. probleme 3D opengl c+
    Par invite85257474 dans le forum Programmation et langages, Algorithmique
    Réponses: 2
    Dernier message: 22/11/2011, 17h16
  4. Opengl
    Par invite591b481e dans le forum Logiciel - Software - Open Source
    Réponses: 0
    Dernier message: 17/05/2010, 11h39
  5. Firefox, mozilla et opengl
    Par inviteb271042d dans le forum Logiciel - Software - Open Source
    Réponses: 0
    Dernier message: 13/12/2005, 14h48