如何用延迟渲染做点光阴影?

How to do point light shadows with deferred rendering?

我想知道如何使用延迟渲染对点光源阴影进行编程?

我没有看到点光源阴影。我认为这与以下行有关: float shadow = calculate_shadows(FragPos);至于定向阴影,我将 fragpos 与 lightSpaceMatrix (lightView * lightProj) 相乘并且有效,但对于点阴影,我没有 lightSpaceMatrix 可以使用。

灯光片段着色器

#version 420 core

out vec4 FragColor;
in vec2 _texcoord;

uniform vec3        camera_pos;
uniform sampler2D   gPosition;
uniform sampler2D   gNormal;
uniform sampler2D   gAlbedo;
uniform sampler2D   gSpecular;
uniform sampler2D   gMetalness;
uniform samplerCube gPointShadowmap;

uniform mat4 viewMatrix;
uniform vec3 lightPos;

vec3 FragPos;
vec3 Normal;

float calculate_shadows(vec3 light_space_pos)
{
    // perform perspective divide
    vec3 fragToLight = light_space_pos - vec3(0.0f, 0.0f, 0.0f);

    // get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
    float closestDepth = texture(gPointShadowmap, fragToLight).r; 

    // it is currently in linear range between [0,1], let's re-transform it back to original depth value
    closestDepth *= 25.0f;

    // now get current linear depth as the length between the fragment and light position
    float currentDepth = length(fragToLight);

    // test for shadows
    float bias = 0.05; // we use a much larger bias since depth is now in [near_plane, far_plane] range
    float shadow = currentDepth -  bias > closestDepth ? 1.0 : 0.0;        

    //FragColor = vec4(vec3(closestDepth / 25.0f), 1.0);  

    return shadow;
}

void main(void)
{
    FragPos = texture(gPosition, _texcoord).rgb;
    Normal = texture(gNormal, _texcoord).rgb;
    vec3 Diffuse = texture(gAlbedo, _texcoord).rgb;
    float Emissive = texture(gAlbedo, _texcoord).a;
    vec3 Specular = texture(gAlbedo, _texcoord).rgb;
    vec3 Metalness = texture(gMetalness, _texcoord).rgb;    // Reflection pass
    float AmbientOcclusion = texture(gSsao, _texcoord).r;

    vec3 lightColor = vec3(0.3);
    // ambient
    vec3 ambient = 0.3 * Diffuse;
    // diffuse
    vec3 lightDir = normalize(vec3(0.0, 0.0, 0.0) - FragPos);
    float diff = max(dot(lightDir, Normal), 0.0);
    vec3 diffuse = diff * lightColor;
    // specular
    vec3 viewDir = normalize(camera_pos - 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 = calculate_shadows(FragPos);                      
    vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular));    

    FragColor = vec4(lighting, 1.0);
}

pointshadows顶点着色器

#version 330 core

layout(location = 0) in vec3 position;

uniform mat4 model;

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

点阴影片段着色器

#version 330 core

in vec4 FragPos;

void main(void)
{
    float lightDistance = length(FragPos.xyz - vec3(0.0, 3.0, 0.0));

    // map to [0;1] range by dividing by far_plane
    lightDistance = lightDistance / 25.0;

    // write this as modified depth
    gl_FragDepth = lightDistance;
}

点阴影几何着色器

#version 330 core

layout (triangles) in;
layout (triangle_strip, max_vertices = 18) out;

uniform mat4 shadowMatrices[6];

out vec4 FragPos;

void main(void)
{
    for(int face = 0; face < 6; ++face)
    {
        gl_Layer = face; // built-in variable that specifies to which face we render.
        for(int i = 0; i < 3; ++i) // for each triangle's vertices
        {
            FragPos = gl_in[i].gl_Position;
            gl_Position = shadowMatrices[face] * FragPos;
            EmitVertex();
        }    
        EndPrimitive();
    }
}

温度点阴影class

#ifndef __POINTSHADOWPASS 
#define __POINTSHADOWPASS

#include "Content.h"

class PointShadowPass
{
private:
    static unsigned int _shadow_fbo;
public: 
    static unsigned int _shadow_texture;
    static glm::vec3 lightPos;
    static std::vector<glm::mat4> shadowTransforms;

    PointShadowPass() {}
    ~PointShadowPass() {}

    inline static void Initialise()
    {
        lightPos = glm::vec3(0.0f, 0.0f, 0.0f);

        glGenFramebuffers(1, &_shadow_fbo);

        glGenTextures(1, &_shadow_texture);
        glBindTexture(GL_TEXTURE_2D, _shadow_texture);

        for (unsigned int i = 0; i < 6; i++)
            glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);

        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

        glBindFramebuffer(GL_FRAMEBUFFER, _shadow_fbo);
        glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _shadow_texture, 0);
        glDrawBuffer(GL_NONE);
        glReadBuffer(GL_NONE);
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

    inline static void Render(unsigned int pointshadow_program, Camera* camera, std::vector<Actor*> _actors)
    {
        glDisable(GL_BLEND);        // Disable blending for opique materials
        glEnable(GL_DEPTH_TEST);    // Enable depth test

        glm::mat4 model;

        glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)1024 / (float)1024, 1.0f, 25.0f);
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
        shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));

        glViewport(0, 0, 1024, 1024);
        glBindFramebuffer(GL_FRAMEBUFFER, _shadow_fbo);
        glClear(GL_DEPTH_BUFFER_BIT);

        glUseProgram(pointshadow_program);
        for (unsigned int i = 0; i < 6; ++i)
            glUniformMatrix4fv(glGetUniformLocation(pointshadow_program, ("shadowMatrices[" + std::to_string(i) + "]").c_str()), 1, GL_FALSE, glm::value_ptr(shadowTransforms[i]));

        for (unsigned int i = 0; i < _actors.size(); i++)
        {
            model = _actors[i]->GetModelMatrix() * camera->GetViewMatrix();

            glUniformMatrix4fv(glGetUniformLocation(pointshadow_program, "model"), 1, GL_FALSE, glm::value_ptr(model)); // set the model matrix uniform

            _actors[i]->Render();
        }

        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }
};

std::vector<glm::mat4> PointShadowPass::shadowTransforms;
unsigned int PointShadowPass::_shadow_fbo;
unsigned int PointShadowPass::_shadow_texture;
glm::vec3 PointShadowPass::lightPos;

#endif

我设法显示了一些东西(阴影随相机旋转而移动)

看了你的评论,你似乎对延迟渲染中可以拥有哪些信息有一些误解?

您说所有坐标都必须在屏幕上space,这是不正确的。对于延迟渲染,您有一个 G-Buffer,您可以在其中放置您想要的任何类型的信息。要获取世界位置信息,您有两种选择,要么拥有世界位置缓冲区,这样您就知道每个片段在世界中的位置。或者您可以从深度缓冲区和相机投影矩阵返回计算此信息。

如果你有一个在前向渲染中工作的点阴影计算,你可以在延迟渲染中做同样的事情,在做所有光计算的着色器中你需要阴影立方体贴图,光位置,你像你一样做计算习惯了。

编辑: 查看 calculate_shadows(vec3 light_space_pos) 的代码,在延迟渲染中,您不会向它发送您在光线 space 中的位置,而是在世界 space 中的位置。所以函数应该是: calculate_shadows(vec3 frag_world_pos) 第一行 vec3 fragToLight = light_space_pos - vec3(0.0f, 0.0f, 0.0f);

应该是vec3 fragToLight = frag_world_pos- lightPos.

或者您在使用该函数之前进行此计算。无论哪种方式,您都需要点光源的位置来计算片段和光​​源之间的方向和距离。