opengl-esglslframebufferopengl-es-3.0shadow-mapping

OpenGL ES3 framebuffer draw depth in red scale


So after hard work to make directional light shadow map work finally I can see a shadow map rendered on a quad but it is drawn only with depth GL_DEPTH_COMPONENT16 and type GL_UNSIGNED_SHORT , or GL_DEPTH_COMPONENT32F and type GL_FLOAT but it is in red scale not gray scale

Depth map

the problem is I used many methods to calculate the depth to draw the shadow but no shadow appears.

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_COMPONENT16, 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);

            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);

            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_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");
}

and the fragment is:

uniform mediump sampler2DShadow  shadowMap;
......
float bias = 0.005;
float visibility = 1.0;
for (int i=0;i<4;i++){
    int index = i;
    visibility -= 0.2*(1.0-texture( shadowMap, vec3(FragPosLightSpace.xy + poissonDisk[index]/700.0,  (FragPosLightSpace.z-bias)/FragPosLightSpace.w) ));           
}
result =light.intensity* (visibility * (diffuse + specular));

Solution

  • ...but it is in red scale not gray scale

    A texture with an depth component format, such as GL_DEPTH_COMPONENT16 or GL_DEPTH_COMPONENT32F has only 1 color channel, the red color channel.
    If you read data from a texture sampler, where a depth component texture is bound to, then the green, blue and alpha channel are set automatically.

    The Image Format specification of Khronos group says:

    Image formats do not have to store each component. When the shader samples such a texture, it will still resolve to a 4-value RGBA vector. The components not stored by the image format are filled in automatically. Zeros are used if R, G, or B is missing, while a missing Alpha always resolves to 1.

    Note: Texture swizzling can change what the missing values are.

    Because of that, the red color is set, the green and blue color is set to 0 and the alpha channel is 1. The causes the opaque red surface.

    If you want to read a grayscale color from a depth component texture, then you have to read the red color channel and you have to apply the red color channel to the green and blue color, too.

    You have to adapt the code like this:

    float depth          = texture( shadowMap, ..... ).r;
    vec3  depthGrayscale = vec3( depth );
    

    or this:

    vec3  depthGrayscale = texture( shadowMap, ..... ).rrr;