Shadow Mapping OpenGL阴影并不总是绘制,而绘制的地方是光的位置

Posted

技术标签:

【中文标题】Shadow Mapping OpenGL阴影并不总是绘制,而绘制的地方是光的位置【英文标题】:Shadow Mapping OpenGL shadow not always drawing, and drawing where the position of the light is 【发布时间】:2020-03-15 16:18:40 【问题描述】:

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

我已经调试这个错误大约两个星期,研究互联网,甚至试图围绕这个问题,但我只能说阴影几乎从未出现,当它出现时,它就是光的地方is Pos 是 x 和 z 的项。我尝试按照教程中的方式做所有事情大约 10 次,我还尝试检查这个网站是否有类似的问题,但我发现的每一种方式都不是我的情况。

发现

在此Image(1) 中,您可以看到当光线在其顶部时阴影不可见,但当 lightPos.x 变量约为 -4.5 或 4.5 时,它在此 Image (2) 上可见,此lightPos.z 变量也是如此。出现时的阴影是在lightPos所在的位置绘制的,在图片中是用红线圈出来的。

我使用多个着色器,一个用于光影计算 (ShadowMapping) 一个用于基本深度映射 (ShadowMapGen) 这是我的 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();

我希望有人会看到这个,谢谢你的时间。

【问题讨论】:

【参考方案1】:

我尝试按照教程中的方式做所有事情大约 10 次

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

m_lightSpaceMatrix = m_lightProjection * m_lightView; 

到目前为止,一切都很好,但是在您的“ShadowMapGen”顶点着色器中,您写道:

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

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

【讨论】:

刚刚测试过,它可以工作。是的,你是对的,我不敢相信我忽略了这个小细节。感谢您的宝贵时间。 没有花费我太多时间,这是我看的第一件事...... :)

以上是关于Shadow Mapping OpenGL阴影并不总是绘制,而绘制的地方是光的位置的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL 阴影贴图

Tutorial - Deferred Rendering Shadow Mapping 转

box shadow 单边阴影 两边阴影

用CSS3怎么实现盒阴影 box-shadow?

shadow阴影

阴影:box_shadow