简体   繁体   中英

Shadow mapping not working in OpenGL ES 3.0 on Android

I am trying to implement shadow mapping in my project for almost a week, and none of methods seem to work. The depth map texture seem to be empty.

I have been digging the whole internet and nothing helped me. Maybe I'm missing something in my code.

Here I start by creating the FBO and a Depth Map texture :

//  create depthMap
int[] depthMapPtr = new int[1];
GLES30.glGenTextures(1, depthMapPtr, 0);
depthMap = depthMapPtr[0];

//  use depthMap
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, depthMap);

GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_DEPTH_COMPONENT16, size, size, 
    0, GLES30.GL_DEPTH_COMPONENT, GLES30.GL_UNSIGNED_SHORT, null);

GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);

//  create fbo
int[] fboPtr = new int[1];
GLES30.glGenFramebuffers(1, fboPtr, 0);
fbo = fboPtr[0];

//  use fbo
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo);
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, 
    GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_TEXTURE_2D, depthMap, 0);

//  draw/read buffers
int[] buffer = {GLES30.GL_NONE};
GLES30.glDrawBuffers(1, buffer, 0);
GLES30.glReadBuffer(GLES30.GL_NONE);

Then I define the depth shaders to render my scene on :

VERTEX SHADER FOR DEPTH :

#version 300 es

layout (location = 0) in vec3 vPos;

uniform mat4 mLightSpace;
uniform mat4 mModel;

void main()
{
    gl_Position = mLightSpace * mModel * vec4(vPos, 1.0);
}

FRAGMENT SHADER FOR DEPTH :

#version 300 es


//out float fragDepth;

void main()
{
    //fragDepth = gl_FragCoord.z;
}

(the comments change nothing, the result is the same).

Before rendering the scene from the shadow perspective, I use this piece of code to change the viewPort, clear depth buffer, bind the FBO :

GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);

//  clear the depth
GLES30.glClear(GLES30.GL_DEPTH_BUFFER_BIT);

GLES30.glViewport(0, 0, size, size);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo);


//  use the shader program for the shadows
useProgramShadow();

After I finish rendering the depth, I prepare everything to render the scene the usual way :

GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);

GLES30.glViewport(0, 0, GLWindow.width, GLWindow.height);
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT);

GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, depthMap);


useProgram();

Than I pass all the uniforms + the View/Projection matrix from the light perspective, and I render the scene.

I find the fragment position from the light perspective in the vertex shader with those lines :

const mat4 tMat = mat4(
    0.5, 0.0, 0.0, 0.0,
    0.0, 0.5, 0.0, 0.0,
    0.0, 0.0, 0.5, 0.0,
    0.5, 0.5, 0.5, 1.0
);

/* ... */

vFragPosLight = tMat * mLightSpace * mModel * vec4(vPosition, 1.0);

To then get the vFragPosLight and the depthMap texture

in vec4 vFragPosLight;
uniform sampler2DShadow depthMap;

...in the fragment shader and calculate the shadow with this line :

textureProj(depthMap, vFragPosLight);

...which always returns 0!

There is no errors with the shader compilations, no texture to framebuffer binding error, everything seems to be working find, but the depthMap is empty.

I really appreciate you for your help and thank you for taking your time to read!

I still don't know what the exact problem was, but I've read and used the Shadow Mapping part in this book about OpenGL ES 3.0 which worked.

It's possible that I had to disable all the color rendering components with glColorMask set to False.

when you create frame buffer, you need to check if the frame buffer is successfully created.

glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
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);
// set up hardware comparison
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
                GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC,
                GL_LEQUAL);
//android use GL_DEPTH_COMPONENT16
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT,
             GL_UNSIGNED_SHORT,
             NULL);
glBindTexture(GL_TEXTURE_2D, 0);

glGenFramebuffers(1, &mDepthFbo);
glBindFramebuffer(GL_FRAMEBUFFER, mDepthFbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
glDrawBuffers(1, GL_NONE);
glReadBuffer(GL_NONE);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, depthTexture);

if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER)) {
    LOGI("frame buffer success");
} else {
    LOGI("frame buffer fail");
}

I have the same problem with you, finally I found the reason is framebuffer create failed, so I fixed the GL_DEPTH_COMPONENT to GL_DEPTH_COMPONENT16, framebuffer success and depth map is OK!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM