OpenGL shadow map incorrect shadows over the object

I implement the shadow map with directional light in an android Native OpenGL C++ application, the shadow is rendered correctly but there some bugs in my code that makes the result as in the attached image:

enter image description here

as shown there are strange triangulated shadows over the model, the implementation as follow:

first create the depth buffer and the depth map as follow:

if (sun->castShadow) {
    glCullFace(GL_FRONT);
    glGenFramebuffers(1, &depthMapFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
    glGenTextures(1, &depthMap);
    glBindTexture(GL_TEXTURE_2D, depthMap);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
    glDrawBuffers(1, GL_NONE);
    glReadBuffer(GL_NONE);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glCullFace(GL_BACK);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        LOGI("framebuffer incomplete");
    }
}

the internal format for glTexImage2D is not work with GL_Float so I used GL_UNSIGNED_SHORT.

then I render the scene from light view, first the light vector is (50,100,50) and I have a confliction about direct light direction is it the direction towards the light or from the light but that value create the shadow and the scene is rendered well with different light components. the code is:

    if (sun->castShadow) {
        double delta = GetCurrentTime() - firstFrame;
        glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
        glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
        glClear(GL_DEPTH_BUFFER_BIT);
        glm::vec3 pos = player->getPosition();
        glm::vec3 tar = pos + (-sun->direction);
        glm::mat4 lightSpaceProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, -20.0f, 500.0f);
        glm::mat4 lightSpaceView = glm::lookAt(pos, tar, glm::vec3(0, 1, 0));
        lightSpaceMatrix = lightSpaceProjection * lightSpaceView;
        shaders.setDepthLightSpaceUniform(lightSpaceMatrix);
        terrain->renderDepth(delta);
        for (item_it it = engineItems.begin(); it != engineItems.end(); ++it) {
            if (it->get()->castShadow)
                it->get()->renderDepth(delta);
        }
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

finally render the scene normally:

shaders.setLightsUniforms(directlights, pointlights, spotlights);
shaders.setViewUniforms(camera);
double first = GetCurrentTime() - firstFrame;
terrain->render(first);
for (item_it it = engineItems.begin(); it != engineItems.end(); ++it) {
    it->get()->render(first);
}

the fragment shader part of the direct light calculations is:

    vec3 calcDirectLight(DirectLight light,vec3 norm,vec3 tLightPos,vec3 diffColor,vec3 specColor){ 
    vec3 lightDir ;
    if(Has_normal_map==1)
        lightDir= normalize(tLightPos-tFragPos);
    else
        lightDir = normalize(light.direction - tFragPos);

    float diff = max(dot(lightDir,norm), 0.0);
    vec3 diffuse = light.color * diff * diffColor;

    vec3 viewDir = normalize(tViewPos - tFragPos);      
    vec3 halfwayDir = normalize(lightDir + viewDir);
    float spec = pow(max(dot(norm, halfwayDir), 0.0), 32.0);
    vec3 specular = shininess * spec *specColor* light.color;
    vec3 result;
    if(light.castShadow==1){
        vec3 projCoords = FragPosLightSpace.xyz / FragPosLightSpace.w;
        projCoords = projCoords * 0.5 + 0.5;
        float shadow = 1.0; 
        for (int i=0;i<4;i++){
            shadow -= 0.2*(1.0-texture( shadowMap, projCoords.xy + poissonDisk[i]/700.0).r);
        } 
        if(projCoords.z > 1.0)
            shadow = 0.0; 
        result =light.intensity* shadow * (diffuse + specular);
    }
    else
        result =light.intensity* (diffuse + specular);
    return result;
}

there are some other bugs but this is the major one

Upvotes: 2

Views: 568

Answers (1)

tuket
tuket

Reputation: 3951

I belive that the problem is here:

if(Has_normal_map==1)
    lightDir= normalize(tLightPos-tFragPos);
else
    lightDir = normalize(light.direction - tFragPos);

I see that you are using a directional light. To compute the direction of a directional light is simply:

lightDir = light.direction

Also, I don't understant why you use a diferent formula for computing the light direction depending on whether Has_normal_map or not. I belive that the direction of the light doesn't depend on the normal map. I hope that solves your bug.

Upvotes: 4

Related Questions