3
votes

I am trying to add real time shadow mapping to my Minecraft-like clone as per the tutorial: here

First what happens:

enter image description hereenter image description here

From what I can tell, the shadow map is rendering correctly? The problem seems to be during the final pass.

I create the depth texture:

glGenFramebuffers(1, &m_frameBufferId);
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferId);
glGenTextures(1, &m_depthTexture);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, 1024, 1024, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
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_NONE);

glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_depthTexture, 0);
glDrawBuffer(GL_NONE);

Note: I also tried using GL_COMPARE_R_TO_TEXTURE with sampler2DShadow in the shader. Same outcome.

Then run both passes:

// ====================    Shadow    =====================
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferId);
glViewport(0, 0, 1024, 1024);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

ShadowShader->Bind();
VCSceneGraph::Instance->RenderGraph();


// ====================    Final    =======================
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, 1280, 800);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

VoxelShader->Bind();
VCSceneGraph::Instance->RenderGraph();

Shadow Shader code:

// ====================    Vert    =====================
#version 330 core\n

in vec4 vertexPosition_modelspace;
uniform mat4 depthMVP;

void main()
{
    gl_Position =  depthMVP * vertexPosition_modelspace;
}

// ====================    Frag    =====================
#version 330 core\n

out float fragmentdepth;

void main()
{
    fragmentdepth = gl_FragCoord.z;
}

Final-Pass (Voxel Shader) code:

// ====================    Vert    =====================
#version 330 core\n

in vec3 position;
in int normal;
in vec4 color;

out vec4 colorVarying;
out vec4 ShadowCoord;

uniform mat4 modelViewProjectionMatrix;
uniform mat4 DepthBiasMVP;

void main()
{
    gl_Position =  modelViewProjectionMatrix * vec4(position, 1);
    ShadowCoord = DepthBiasMVP * vec4(position, 1);
    colorVarying = color;
}

// ====================    Frag    =====================
#version 330 core\n

in vec4 colorVarying;
in vec4 ShadowCoord;

out vec4 color;

uniform sampler2D  shadowMap;

void main()
{
    float visibility = 1.0;

    if ( texture(shadowMap, ShadowCoord.xy).z  <  ShadowCoord.z)
    {
        visibility = 0.5;
    }

    color.xyz = colorVarying.xyz * visibility;
    color.w = colorVarying.w;
}

I suspect my issue is in the code that updated the uniforms for the final pass:

// Re-create the exact same MVP matrix that was used for the shadow pass
glm::mat4 depthProjectionMatrix = glm::ortho<float>( -30, 30, -30, 30, -100, 100);
glm::mat4 depthViewMatrix = glm::lookAt(glm::vec3(0.5f, 2, 2), glm::vec3(0,0,0), glm::vec3(0,1,0));
depthViewMatrix = glm::translate(depthViewMatrix, -15.0f, 30.0f, 0.0f);
glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix;// * modelMatrix;

// Multiply it be the bias matrix
glm::mat4 biasMatrix
(
    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
);

glm::mat4 depthBiasMVP = biasMatrix * depthMVP;

// Create Camera's MVP
VCCamera* currentCamera = VCSceneGraph::Instance->CurrentRenderingCamera;
glm::mat4 ProjectionMatrix = currentCamera->ProjectionMatrix;
glm::mat4 ViewMatrix = currentCamera->ViewMatrix;
glm::mat4 MVP = ProjectionMatrix * ViewMatrix;// * modelMatrix;

// Update uniforms
glUniformMatrix4fv(m_unifMVP, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(m_unifDepthMVP, 1, GL_FALSE, &depthBiasMVP[0][0]);

EDIT:

I fixed the problem by making the Shadow texture the same resolution as the window. I cannot however explain WHY this fixes it. If anyone else want to take a crack at it I will accept your answer. The expected output is this: enter image description here

I should have also noted that full source is available at: GitHub.

1
Thank you the help. I added ShadowCoord.xyz = ShadowCoord.xyz / ShadowCoord.w; to my vertex shader after multiplying by the DepthBiasMVP but it had no effect. - Alec Thilenius
What results do you expect? Also, could you provide something like screenshot with your scene, camera and light source positions/directions in some 3D modeling software, so i can imagine what results should be considered 'correct'? From what i see on shadow map - there just shouldn't be any shadows, because your object have almost no shadow casting - maybe it even convex, hard to see on this view. - keltar
What happens if you set the second viewport to 1024 x 1024? - bwroga
Interestingly, nothing happens. In fact the value I set the second View port to seems irrelevant. The scene still renders as before. Odd... - Alec Thilenius
Umm, could you apply lighting to the surface or render wireframe on top of it? And indicate lighting position? With the current screenshots it is very hard to figure out what your geometry looks like. - SigTerm

1 Answers

1
votes

I compare your and my shadows and I suggest you tu use sampler2DShadow instead of sampler2D. This sampler is for shadows only and there are some functions for shadow projection (shadow2DProj and more). You can use it like this.

in vec4 colorVarying;
varying vec4 ShadowCoord;

out vec4 color;

uniform sampler2DShadow shadowMap;

float offset_lookup(sampler2DShadow map, vec4 loc, vec2 offset) {
    //Texture size (1024 x 1024)
    vec2 texmapscale = vec2(1.0/1024.0, 1.0/1024.0);
    //Set bias as you need (it corrects shadow acne)
    float bias = 0.001;
    vec4 result = shadow2DProj(map, vec4(loc.xy + offset * texmapscale * loc.w, loc.z, loc.w));
    if (loc.z > result.z + bias) {
        return 0.5;
    } else {
        return 1.0;
    }
}

void main() {
    float shadowFactor;
    shadowFactor = offset_lookup(shadowMap, ShadowCoord, vec2(0, 0));
    color = colorVarying * shadowFactor;
}

What is last parameter offset? You can make some shadow blur. 3x3 shadow blur:

//3x3 blur
    for (y = -1.5; y <= 1.5; y += 1.0)
        for (x = -1.5; x <= 1.5; x += 1.0)
            sum += offset_lookup(shadowMap, ShadowCoord, vec2(x, y));
    //I am no sure why 16 (insted of 9) but I use this and it works :D
    float shadeFactor = sum / 16.0;

Try it, maybe result will be exactly what you expect.

PS: Sorry for my English.