Shadow Mapping OpenGL shadow 并不总是绘制,并且在光线的位置绘制

Shadow Mapping OpenGL shadow not always drawing, and drawing where the position of the light is

我一直在尝试使用 LearnOpenGL 作为源在我的自定义引擎中进行基本的阴影贴图。 link 可以找到确切的教程:here.

我已经调试这个错误大约两周了,研究互联网,甚至试图解决这个问题,但我只能说阴影几乎从不出现,当它出现时它在哪里光是 Pos 是 x 和 z 的项。我尝试完全按照教程中的方法进行大约 10 次,我也尝试查看此网站是否有类似问题,但对于我发现的每一种方式,这都不是我的情况。

调查结果

在这个 Image(1) you can see that the shadow is not visible when the light is on top of it, but it is then visible on this Image (2) 中,当 lightPos.x 变量在 -4.5 或 4.5 左右时,lightPos.z 变量也是如此。出场时的影子是画在lightPos所在的地方,图中用红线圈起来的地方

我使用多个着色器,一个用于光影计算 (ShadowMapping),一个用于基本深度映射 (ShadowMapGen) 这是我的 ShadowMapping 着色器:

ShadowMapping 顶点

version 460
in vec3 vertexIn;
in vec3 normalIn;
in vec2 textureIn;

out vec3 FragPos;
out vec3 normalOut;
out vec2 textureOut;

out vec4 FragPosLightSpace;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 lightSpaceMatrix;

void main()
{
    textureOut = textureIn;

    FragPos = vec3(model * vec4(vertexIn, 1.0));
    normalOut = mat3(transpose(inverse(model))) * normalIn;  
    FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);    

    gl_Position = projection * view * model * vec4(vertexIn, 1.0);
}

ShadowMapping 碎片

out vec4 FragColor;

in vec3 FragPos;
in vec3 normalOut;
in vec2 textureOut;

in vec4 FragPosLightSpace;

uniform sampler2D diffuseTexture;
uniform sampler2D shadowMap;

uniform vec3 lightPos;
uniform vec3 viewPos;

float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightdir)
{
    // perform perspective divide
    vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
    // transform to [0,1] range
    projCoords = projCoords * 0.5 + 0.5;
    // get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
    float closestDepth = texture(shadowMap, projCoords.xy).r; 
    // get depth of current fragment from light's perspective
    float currentDepth = projCoords.z;
    // check whether current frag pos is in shadow
    float bias = max(0.05 * (1.0 - dot(normalOut, lightdir)), 0.005);

    // check whether current frag pos is in shadow
//    float shadow = currentDepth - bias > closestDepth  ? 1.0 : 0.0;
//    // PCF
    float shadow = 0.0;

    vec2 texelSize = 1.0 / textureSize(shadowMap, 0);
    for(int x = -1; x <= 1; ++x)
    {
        for(int y = -1; y <= 1; ++y)
        {
            float pcfDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; 
            shadow += currentDepth - bias > pcfDepth  ? 1.0 : 0.0;        
        }    
    }

    shadow /= 9.0;

    // keep the shadow at 0.0 when outside the far_plane region of the light's frustum.
        if(projCoords.z > 1.0)
        shadow = 0.0;

    return shadow;
}

void main()
{           
    vec3 color = texture(diffuseTexture, textureOut).rgb;
    vec3 normal = normalize(normalOut);
    vec3 lightColor = vec3(1.0f);
    // ambient
    vec3 ambient = 0.30 * color;
    // diffuse
    vec3 lightDir = normalize(lightPos - FragPos);
    float diff = max(dot(lightDir, normal), 0.0);
    vec3 diffuse = diff * lightColor;
    // specular
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, normal);
    float spec = 0.0;
    vec3 halfwayDir = normalize(lightDir + viewDir);  
    spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
    vec3 specular = spec * lightColor;    
    // calculate shadow
    float shadow = ShadowCalculation(FragPosLightSpace, lightDir);                      
    vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;    

    FragColor = vec4(lighting, 1.0);
}

ShadowMapGen 顶点

此着色器的片段着色器为空

version 460

in vec3 vertexIn;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;

void main()
{
    gl_Position =  model * lightSpaceMatrix * vec4(vertexIn, 1.0);
}

变量初始化

lightPos = glm::vec3(-2.0f, 4.0f, -1.0f);
near_plane = 1.0f;
far_plane = 7.5f;

//SAMPLE 2D Uniform binding
TheShader::Instance()->SendUniformData("ShadowMapping_diffuseTexture", 0);
TheShader::Instance()->SendUniformData("ShadowMapping_shadowMap", 1);

深度图帧缓冲区生成

这就是我在场景构造函数中生成深度贴图/阴影贴图纹理的方式:

glGenFramebuffers(1, &depthMapFBO);
//Create depth texture
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_FLOAT, NULL); // Height and Width = 1024
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_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

float borderColor[] = { 1.0, 1.0, 1.0, 1.0 };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

//Attach depth texture as FBO's depth buffer
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

然后在引擎的 While 循环中运行的 Update() 函数中,我首先执行:

从光的角度渲染对象

//Light Projection and view Matrix 
m_lightProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
m_lightView = glm::lookAt(lightPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
//Calculate light matrix and send it.
m_lightSpaceMatrix = m_lightProjection * m_lightView;
TheShader::Instance()->SendUniformData("ShadowMapGen_lightSpaceMatrix", 1, GL_FALSE, m_lightSpaceMatrix);

//Render to Framebuffer depth Map
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);

//Set current Shader to ShadowMapGen
m_floor.SetShader("ShadowMapGen");
m_moon.SetShader("ShadowMapGen");
//Send model Matrix to current Shader
m_floor.Draw();
m_moon.Draw();
//Set current Shader back to ShadowMapping
m_moon.SetShader("ShadowMapping");
m_floor.SetShader("ShadowMapping");

glBindFramebuffer(GL_FRAMEBUFFER, 0);

从相机的角度渲染对象

glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Update Camera and Send the view and projection matrices to the ShadowMapping shader
m_freeCamera->Update();
m_freeCamera->Draw();

//Send Light Pos 
TheShader::Instance()->SendUniformData("ShadowMapping_lightPos", lightPos);
//Send LightSpaceMatrix
TheShader::Instance()->SendUniformData("ShadowMapping_lightSpaceMatrix", 1, GL_FALSE, m_lightSpaceMatrix);

//Activate Shadow Mapping texture
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthMap);

//Send model Matrix to ShadowMapping shaders
m_moon.Draw();  
m_floor.Draw();

希望有人能看到,谢谢您的宝贵时间。

I tried to do everything exactly like in the tutorial around 10 times

好吧,你似乎至少漏掉了一件明显的事情:

m_lightSpaceMatrix = m_lightProjection * m_lightView; 

到目前为止一切顺利,但在您的 "ShadowMapGen" 顶点着色器中,您写道:

gl_Position =  model * lightSpaceMatrix * vec4(vertexIn, 1.0);

所以你最终得到的是 model * projection * view 乘法顺序,无论你遵守哪种约定,这都没有意义。由于本教程使用默认的 GL 约定,您始终需要 projection * view * model * vertex 乘法顺序,本教程也正确使用了它。