mirror of
https://github.com/JoeyDeVries/LearnOpenGL.git
synced 2026-01-10 10:33:23 +08:00
Add source code for the cascaded shadow mapping guest article.
This commit is contained in:
114
src/8.guest/2021/2.csm/10.shadow_mapping.fs
Normal file
114
src/8.guest/2021/2.csm/10.shadow_mapping.fs
Normal file
@@ -0,0 +1,114 @@
|
||||
#version 460 core
|
||||
out vec4 FragColor;
|
||||
|
||||
in VS_OUT {
|
||||
vec3 FragPos;
|
||||
vec3 Normal;
|
||||
vec2 TexCoords;
|
||||
} fs_in;
|
||||
|
||||
uniform sampler2D diffuseTexture;
|
||||
uniform sampler2DArray shadowMap;
|
||||
|
||||
uniform vec3 lightDir;
|
||||
uniform vec3 viewPos;
|
||||
uniform float farPlane;
|
||||
|
||||
uniform mat4 view;
|
||||
|
||||
layout (std140, binding = 0) uniform LightSpaceMatrices
|
||||
{
|
||||
mat4 lightSpaceMatrices[16];
|
||||
};
|
||||
uniform float cascadePlaneDistances[16];
|
||||
uniform int cascadeCount; // number of frusta - 1
|
||||
|
||||
float ShadowCalculation(vec3 fragPosWorldSpace)
|
||||
{
|
||||
// select cascade layer
|
||||
vec4 fragPosViewSpace = view * vec4(fragPosWorldSpace, 1.0);
|
||||
float depthValue = abs(fragPosViewSpace.z);
|
||||
|
||||
int layer = -1;
|
||||
for (int i = 0; i < cascadeCount; ++i)
|
||||
{
|
||||
if (depthValue < cascadePlaneDistances[i])
|
||||
{
|
||||
layer = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (layer == -1)
|
||||
{
|
||||
layer = cascadeCount;
|
||||
}
|
||||
|
||||
vec4 fragPosLightSpace = lightSpaceMatrices[layer] * vec4(fragPosWorldSpace, 1.0);
|
||||
// perform perspective divide
|
||||
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||
// transform to [0,1] range
|
||||
projCoords = projCoords * 0.5 + 0.5;
|
||||
|
||||
// get depth of current fragment from light's perspective
|
||||
float currentDepth = projCoords.z;
|
||||
if (currentDepth > 1.0)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
// calculate bias (based on depth map resolution and slope)
|
||||
vec3 normal = normalize(fs_in.Normal);
|
||||
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||
if (layer == cascadeCount)
|
||||
{
|
||||
bias *= 1 / (farPlane * 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
bias *= 1 / (cascadePlaneDistances[layer] * 0.5f);
|
||||
}
|
||||
|
||||
// PCF
|
||||
float shadow = 0.0;
|
||||
vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0));
|
||||
for(int x = -1; x <= 1; ++x)
|
||||
{
|
||||
for(int y = -1; y <= 1; ++y)
|
||||
{
|
||||
float pcfDepth = texture(shadowMap, vec3(projCoords.xy + vec2(x, y) * texelSize, layer)).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, fs_in.TexCoords).rgb;
|
||||
vec3 normal = normalize(fs_in.Normal);
|
||||
vec3 lightColor = vec3(0.3);
|
||||
// ambient
|
||||
vec3 ambient = 0.3 * color;
|
||||
// diffuse
|
||||
float diff = max(dot(lightDir, normal), 0.0);
|
||||
vec3 diffuse = diff * lightColor;
|
||||
// specular
|
||||
vec3 viewDir = normalize(viewPos - fs_in.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(fs_in.FragPos);
|
||||
vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;
|
||||
|
||||
FragColor = vec4(lighting, 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user