代码之家  ›  专栏  ›  技术社区  ›  Elias

C++与阴影矩阵比较,不产生阴影

  •  1
  • Elias  · 技术社区  · 7 年前

    我正在尝试实现阴影映射。我能够在帧缓冲区纹理上渲染深度贴图。并将其发送到着色器以及灯光正交矩阵,以测试阴影中是否有碎片。但结果并不正确。不是创建阴影,而是将所有碎片单独绘制,如果它们“位于”光线矩阵的内部。

    img

    正如您在左下角看到的,生成的深度纹理是正确的。

    我试过很多教程,但都没有提到像这样的问题。这可能是因为光线方向和正交投影是错误的,但我似乎找不到一个产生阴影的工作光线方向。

    这就是生成帧缓冲区和纹理的方式(在类标题中实例化了帧缓冲区和帧缓冲区纹理):

    glGenFramebuffers(1, &frameBuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
    
    //texture buffer for frame buffer
    glGenTextures(1, &framebufferTexture);
    glBindTexture(GL_TEXTURE_2D, framebufferTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 896, 504, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
    
    
    //Set framebufferTexture as our color attachment #0
    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
        GL_TEXTURE_2D, framebufferTexture, 0);
    
    glDrawBuffer(GL_NONE);
    

    这就是我创建深度纹理的方式

    glCullFace(GL_BACK);
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer);
    //Setup depth texture framebuffer rendering
    glEnable(GL_POLYGON_OFFSET_FILL);
    glPolygonOffset(2.0f, 2.0f);
    glViewport(0, 0, 896, 504);
    glClear(GL_DEPTH_BUFFER_BIT);
    
    glUniform1i(glGetUniformLocation(shaderProgram, "fragmentTypeTarget"), -1);
    
    
    glm::vec3 lightInvDir = glm::vec3(5, 17, 1);
    //Calculate the matrix for drawing the framebuffer
    //Make it an orthographic that takes the whole screen
    glm::mat4 depthProjectionMatrix = glm::ortho<float>(-17, 17, -17, 17, 0, 37);
    glm::mat4 depthViewMatrix = glm::lookAt(
        lightInvDir,
        glm::vec3(0, 0, 0),
        glm::vec3(0, 1, 0));
    glm::mat4 lightSpaceMatrix = depthProjectionMatrix * depthViewMatrix;
    
    //Render the objects
    for (int i = 0; i < objectPool.size(); i++) {
        objectPool[i]->draw(lightSpaceMatrix);
    }
    

    以下是我发送阴影贴图矩阵以绘制阴影的方式:

    glm::mat4 Model = glm::translate(glm::mat4(1.0), glm::vec3(x, y, z));
    glm::vec3 lightInvDir = glm::vec3(5, 17, 1);
        //Calculate the matrix for drawing the framebuffer
        //Make it an orthographic that takes the whole screen
        glm::mat4 depthProjectionMatrix = glm::ortho<float>(-17, 17, -17, 17, 0, 37);
        glm::mat4 depthViewMatrix = glm::lookAt(
            lightInvDir,
            glm::vec3(0, 0, 0),
            glm::vec3(0, 1, 0));
        glm::mat4 lightSpaceMatrix = depthProjectionMatrix * depthViewMatrix * Model;
    glUniformMatrix4fv(glGetUniformLocation(shader, "shadowMatrix"), 1, GL_FALSE, &lightSpaceMatrix[0][0]);
    

    我的片段着色器:

    #version 330 core
    layout(location = 0) out vec4 outColor;
    in vec2 UV;
    in vec4 ShadowCoord;
    uniform sampler2D textureSampler;
    uniform sampler2D shadowMap;
    uniform int fragmentTypeTarget;
    
    
    // 'colorImage' is a sampler2D with the depth image
    // read from the current depth buffer bound to it.
    float LinearizeDepth(in vec2 uv, sampler2D t)
    {
        float zNear = 1.0;    
        float zFar  = 5.0; 
        float depth = texture2D(t, uv).x;
        return (2.0 * zNear) / (zFar + zNear - depth * (zFar - zNear));
    }
    
    void main(){
    if(fragmentTypeTarget == -1){//draw frame buffer
    
    }else if(fragmentTypeTarget == 0){//Draw everything normal
        vec4 tex = texture2D(textureSampler, UV);
        outColor = vec4(tex.rgb, tex.a);
    }else if(fragmentTypeTarget == 1){//Draw depth texture
        //vec2 res = gl_FragCoord.xy / vec2(1024, 1024);
        outColor = texture(textureSampler, UV);
        float c = LinearizeDepth(UV, textureSampler);
        outColor = vec4(c, c, c, 1.0);
    }else if(fragmentTypeTarget == 2){//Draw everything but apply the shadow
        float visibility = 1.0;
        float bias = 0.0039;
    
        if(texture(shadowMap, ShadowCoord.xy).z < ShadowCoord.z){
            visibility = 0.3;
        }
        vec4 tex = texture2D(textureSampler, UV);
        outColor = visibility * vec4(tex.rgb, tex.a);
    }
    }
    

    #version 330 core
    in vec2 UVsIn;
    out vec2 UV;
    in vec3 position;
    in vec3 vertexColor;
    out vec3 fragmentColor;
    uniform mat4 mvp;
    uniform mat4 shadowMatrix;
    out vec4 ShadowCoord;
    
    void main(){
    gl_Position = mvp * vec4(position, 1.0);
    fragmentColor = vertexColor;
    UV = UVsIn;
    
    ShadowCoord = shadowMatrix * vec4(position, 1.0);
    }
    

    结果应该更像这样:

    img

    编辑:

    生成帧缓冲区纹理时,我使用了错误的比较函数。应该是“GL\u COMPARE\u R\u TO\u TEXTURE”,而不是“GL\u COMPARE\u REF\u TO\u TEXTURE”。

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
    

    这正是我想要的。

    我还发现纹理坐标是(s,t,r)而不是(x,y,z)。

    因为我想比较矩阵和纹理的深度,所以我需要使用r而不是z。 因此片段着色器的编写方式应如下所示:

    float visibility = 1.0;
    
    vec2 mapUV = ShadowCoord.xy * 0.5 + 0.5;
    float depthFrag = ShadowCoord.z * 0.5 + 0.5;
    
    float depthMap = texture(shadowMap, mapUV).r;//r instead of z since its (s, t, r)
    
    if(depthMap < depthFrag){
        visibility = 0.3;
    }
    
    vec4 tex = texture2D(textureSampler, UV);
    outColor = visibility * vec4(tex.rgb, tex.a);
    

    Rabbi76回复中还需要添加“*0.5+0.5”。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Rabbid76    7 年前

    阴影贴图的内容是深度范围[0.0,1.0]中的深度值(除非您通过以下方式更改深度范围): glDepthRange )

    ShadowCoord 是剪辑空间坐标。剪辑空间坐标可以通过 Perspective divide ( ShadowCoord.xyz/ShadowCoord.w )。由于阴影投影是正交的,因此可以跳过此操作,因为 ShadowCoord.w == 1.0 .

    因此,它必须是:

    vec2  mapUV     = ShadowCoord.xy * 0.5 + 0.5; // [-1.0, 1.0] -> [0.0, 1.0]
    float depthFrag = ShadowCoord.z  * 0.5 + 0.5; // [-1.0, 1.0] -> [0.0, 1.0]
    
    float depthMap  = texture(shadowMap, mapUV).r;
    
    if(depthMap < depthFrag) {
        visibility = 0.3;
    }
    
    推荐文章