I'm trying to implement shadow maps for Spotlight's, but alas I can't get them to work. I have verified that my fragment shader is getting the shadow map texture. I can sample from it in the traditional sense and display it to the screen, so I know its there.
My problem
- Actually getting the right coordinates and comparing that sample against the current depth value (No shadows appear)
If I'm understanding the process correctly, I have to transform the fragment from the space relative to the camera into the space occupied by the light when the shadow map was built.
I'm working with a deferred shading system, so I can easily get the current fragment's position in space by just sampling from a Position Map texture.
Here's how I'm trying to determine if a pixel is in shadow or not:
Fragment Shader:
in vec3 EyePos;
in mat4 LightMVP;
out vec4 fragColor;
uniform SpotLight spotLight;
uniform vec2 ScreenSize;
uniform sampler2D PositionMap;
uniform sampler2D ColorMap;
uniform sampler2D NormalMap;
uniform sampler2D SpecularMap;
uniform sampler2D ShadowMap;
// Takes in transformed position, samples shadow map, outputs shadow factor float
float CalcShadowFactor(vec4 LightSpacePos)
{
vec3 ProjCoords = LightSpacePos.xyz / LightSpacePos.w;
vec2 UVCoords;
UVCoords.x = 0.5 * ProjCoords.x + 0.5;
UVCoords.y = 0.5 * ProjCoords.y + 0.5;
float z = 0.5 * ProjCoords.z + 0.5;
float Depth = texture(ShadowMap, UVCoords).x;
if (Depth < z + 0.00001)
return 0.0;
else
return 1.0;
}
// Returns the texture coordinate
vec2 CalcTexCoord()
{
return gl_FragCoord.xy / ScreenSize;
}
void main(void)
{
vec2 TexCoord = CalcTexCoord(); // Used for sampling from input texture maps
vec4 WorldPos = texture2D(PositionMap, TexCoord); // Position in space
// ... omitted texture sampling for diffuse, normals, specular, etc ... //
vec4 LightSpace = (LightMVP) * WorldPos4;
float ShadowFactor = CalcShadowFactor(LightSpace);
fragColor = vec4(Color, 1.0) * CalcSpotLight(WorldPos.xyz, Normal, Specular, ShadowFactor);
}
The matrices lightV and lightP are the view and projection matrices used by the light when it takes a shadow map pass of the scene from its perspective.
The Vertex Shader:
#version 330
in vec4 vertex;
uniform mat4 mMatrix;
uniform mat4 pMatrix;
uniform mat4 vMatrix;
uniform mat4 lightV;
uniform mat4 lightP;
uniform vec3 eye;
out vec3 EyePos;
out mat4 LightMVP;
void main()
{
EyePos = eye;
mat4 worldMVP = pMatrix * vMatrix * mMatrix;
LightMVP = lightP * lightV * mMatrix;
gl_Position = worldMVP * vertex;
}
The shadow map texture (visualized)
The rendered scene
Questions
What am I doing wrong? Does any of this math seem off?
Does it matter if the shadow map texture is of a different resolution and aspect ratio than the camera? In this case it is exactly the same.
If nothing seems wrong, how else would I debug this then? I've tried just outputting a vec4 with the shadow factor, but all I get is bright white (as it isn't sampling right)
If it helps, I've been following the tutorials on OGLDev, so my deferred shading system is similar to theirs, and my shadow map is also like theirs (however they never did a tutorial for using both at the same time)
Update
I managed to brute-force a solution, however I don't understand why it works, and I'm not certain if it is even the correct solution.
For calculating my LightMVP mat4, I mutliply the camera's projection matrix by the inverse light view matrix, which then gets passed into my fragment shader and multiplied by the world position, where the world position is derived from the texture Position Map.
LightMVP = (pMatrix) * inverse(lightV);
vec4 LightSpace = (LightMVP) * WorldPos;
Is there anything wrong with this approach?