0

I was wondering how I would go about programming point light shadows with deferred rendering??

The point light shadows just dont show up for me. I think it is to do with the following line: float shadow = calculate_shadows(FragPos); as for directional shadows I multiple the fragpos with a lightSpaceMatrix (lightView * lightProj) and that worked, but for point shadows I dont have a lightSpaceMatrix to use.

light fragment shader

#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 vertex shader

#version 330 core

layout(location = 0) in vec3 position;

uniform mat4 model;

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

pointshadows fragment shader

#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;
}

pointshadows geometry shader

#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();
    }
}

Temp PointShadow 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

I managed to get something showing (shadows move with camera rotation)

Got this. But still doesnt work

Charl1e
  • 75
  • 1
  • 9
  • 1
    I don't understand the question. If you want to use [Shadow Mapping](https://de.wikipedia.org/wiki/Shadow_Mapping), the a depth map, as seen from the light source is of need. Regardless on forward rendering or deferred rendering. You have to use the information stored in the G-buffer and the depth map of the light source, to determine if a fragment is in shadow or not. – Rabbid76 Jun 19 '18 at 21:32
  • Basically, I want to render shadows from a point light source, not directional light. So I need to capture the scene around the point light using a cubemap. – Charl1e Jun 19 '18 at 21:34
  • 2
    Yes, but this is independent on forward rendering or deferred rendering. – Rabbid76 Jun 19 '18 at 21:41
  • thats why Im not sure, I know how to implement it using forward rendering but not deferred rendering. I just wasnt sure how to implement the shadow calculation code in the shader. For example, In a tutorial he has this line: vec3 fragToLight = fragPos - lightPos; but this uses forward rendering and wouldnt work with deferred, hmm – Charl1e Jun 19 '18 at 21:44
  • 2
    @CharlieWheate: "*I know how to implement it using forward rendering but not deferred rendering.*" I don't understand why you don't. It should be the same thing either way. – Nicol Bolas Jun 19 '18 at 22:13
  • but deferred rendering is screenspace isnt it? – Charl1e Jun 19 '18 at 22:28
  • Even with deferred rendering, you somehow need the worldspace position of fragments (otherwise you couldn't calculate the illumination in first place). – BDL Jun 20 '18 at 07:24

1 Answers1

1

Reading your comments it seems you have some misconceptions about what informations you can have in defered rendering?

You said that all the coordinates have to be in screenspace which isn't true. For deffered rendering you have a G-Buffer and in it you can put whatever kind of information you want. To get world position information you have two choices, either you have a world position buffer, so you know where each of your fragment is in the world. Or you can compute this information back from the depth buffer and camera projection matrix.

If you have a point shadow calculation that works in forward rendering you can do the same in deferred rendering, in the shader that does all the light calculation you need the shadow cubemap, light position and you do the calculation like you used to.

EDIT: looking at your code for calculate_shadows(vec3 light_space_pos), in deferred rendering you don't send it your position in lightspace, but the position in world space. So the function should be: calculate_shadows(vec3 frag_world_pos) you have for the first line vec3 fragToLight = light_space_pos - vec3(0.0f, 0.0f, 0.0f);

which should be vec3 fragToLight = frag_world_pos- lightPos.

Or you do this calculation before using the function. Eitherway, you need the position of your point light to calculate the direction and distance between your fragment and the light.

florent teppe
  • 529
  • 5
  • 13
  • still not working, I have updated my question with some code. – Charl1e Jun 20 '18 at 11:18
  • how do I get the fragment in world space? – Charl1e Jun 20 '18 at 11:45
  • Well you have a fragPos sampler2D, It contains the position of your fragment in the world no? If it doesn't then, when you draw your objects, you need to output the value of the fragment position in the world to a texture attached to your framebuffer. – florent teppe Jun 20 '18 at 11:48
  • Ye see what you mean, hmm so it should be working. Originally i thought different because the fragpos is being set to the positions which is a texture, so surely its not in world space? hmm – Charl1e Jun 20 '18 at 12:07
  • @CharlieWheate could you give the fragment shader of your objects? Because I really wonder what is **uniform sampler2D gPosition;** supposed to be in your case if it isn't the world position of your fragment written to a texture. – florent teppe Jun 20 '18 at 12:10