Skip to content

Commit 1fc3d9a

Browse files
Add shadowmapping example (raysan5#3653)
1 parent 34a9163 commit 1fc3d9a

File tree

9 files changed

+489
-0
lines changed

9 files changed

+489
-0
lines changed

examples/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ SHADERS = \
560560
shaders/shaders_palette_switch \
561561
shaders/shaders_postprocessing \
562562
shaders/shaders_raymarching \
563+
shaders/shaders_shadowmap \
563564
shaders/shaders_shapes_textures \
564565
shaders/shaders_simple_mask \
565566
shaders/shaders_spotlight \

examples/Makefile.Web

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ SHADERS = \
466466
shaders/shaders_palette_switch \
467467
shaders/shaders_postprocessing \
468468
shaders/shaders_raymarching \
469+
shaders/shaders_shadowmap \
469470
shaders/shaders_shapes_textures \
470471
shaders/shaders_simple_mask \
471472
shaders/shaders_spotlight \
1.53 MB
Binary file not shown.
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#version 120
2+
3+
precision mediump float;
4+
5+
// This shader is based on the basic lighting shader
6+
// This only supports one light, which is directional, and it (of course) supports shadows
7+
8+
// Input vertex attributes (from vertex shader)
9+
varying in vec3 fragPosition;
10+
varying in vec2 fragTexCoord;
11+
//varying in vec4 fragColor;
12+
varying in vec3 fragNormal;
13+
14+
// Input uniform values
15+
uniform sampler2D texture0;
16+
uniform vec4 colDiffuse;
17+
18+
// Input lighting values
19+
uniform vec3 lightDir;
20+
uniform vec4 lightColor;
21+
uniform vec4 ambient;
22+
uniform vec3 viewPos;
23+
24+
// Input shadowmapping values
25+
uniform mat4 lightVP; // Light source view-projection matrix
26+
uniform sampler2D shadowMap;
27+
28+
uniform int shadowMapResolution;
29+
30+
void main()
31+
{
32+
// Texel color fetching from texture sampler
33+
vec4 texelColor = texture2D(texture0, fragTexCoord);
34+
vec3 lightDot = vec3(0.0);
35+
vec3 normal = normalize(fragNormal);
36+
vec3 viewD = normalize(viewPos - fragPosition);
37+
vec3 specular = vec3(0.0);
38+
39+
vec3 l = -lightDir;
40+
41+
float NdotL = max(dot(normal, l), 0.0);
42+
lightDot += lightColor.rgb*NdotL;
43+
44+
float specCo = 0.0;
45+
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(l), normal))), 16.0); // 16 refers to shine
46+
specular += specCo;
47+
48+
vec4 finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0)));
49+
50+
// Shadow calculations
51+
vec4 fragPosLightSpace = lightVP * vec4(fragPosition, 1);
52+
fragPosLightSpace.xyz /= fragPosLightSpace.w; // Perform the perspective division
53+
fragPosLightSpace.xyz = (fragPosLightSpace.xyz + 1.0f) / 2.0f; // Transform from [-1, 1] range to [0, 1] range
54+
vec2 sampleCoords = fragPosLightSpace.xy;
55+
float curDepth = fragPosLightSpace.z;
56+
// Slope-scale depth bias: depth biasing reduces "shadow acne" artifacts, where dark stripes appear all over the scene.
57+
// The solution is adding a small bias to the depth
58+
// In this case, the bias is proportional to the slope of the surface, relative to the light
59+
float bias = max(0.0008 * (1.0 - dot(normal, l)), 0.00008);
60+
int shadowCounter = 0;
61+
const int numSamples = 9;
62+
// PCF (percentage-closer filtering) algorithm:
63+
// Instead of testing if just one point is closer to the current point,
64+
// we test the surrounding points as well.
65+
// This blurs shadow edges, hiding aliasing artifacts.
66+
vec2 texelSize = vec2(1.0f / float(shadowMapResolution));
67+
for (int x = -1; x <= 1; x++)
68+
{
69+
for (int y = -1; y <= 1; y++)
70+
{
71+
float sampleDepth = texture2D(shadowMap, sampleCoords + texelSize * vec2(x, y)).r;
72+
if (curDepth - bias > sampleDepth)
73+
{
74+
shadowCounter++;
75+
}
76+
}
77+
}
78+
finalColor = mix(finalColor, vec4(0, 0, 0, 1), float(shadowCounter) / float(numSamples));
79+
80+
// Add ambient lighting whether in shadow or not
81+
finalColor += texelColor*(ambient/10.0)*colDiffuse;
82+
83+
// Gamma correction
84+
finalColor = pow(finalColor, vec4(1.0/2.2));
85+
gl_FragColor = finalColor;
86+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#version 120
2+
3+
// Input vertex attributes
4+
attribute vec3 vertexPosition;
5+
attribute vec2 vertexTexCoord;
6+
attribute vec3 vertexNormal;
7+
attribute vec4 vertexColor;
8+
9+
// Input uniform values
10+
uniform mat4 mvp;
11+
uniform mat4 matModel;
12+
uniform mat4 matNormal;
13+
14+
// Output vertex attributes (to fragment shader)
15+
varying vec3 fragPosition;
16+
varying vec2 fragTexCoord;
17+
varying vec4 fragColor;
18+
varying vec3 fragNormal;
19+
20+
// NOTE: Add here your custom variables
21+
22+
void main()
23+
{
24+
// Send vertex attributes to fragment shader
25+
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
26+
fragTexCoord = vertexTexCoord;
27+
fragColor = vertexColor;
28+
fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0)));
29+
30+
// Calculate final vertex position
31+
gl_Position = mvp*vec4(vertexPosition, 1.0);
32+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#version 330
2+
3+
// This shader is based on the basic lighting shader
4+
// This only supports one light, which is directional, and it (of course) supports shadows
5+
6+
// Input vertex attributes (from vertex shader)
7+
in vec3 fragPosition;
8+
in vec2 fragTexCoord;
9+
//in vec4 fragColor;
10+
in vec3 fragNormal;
11+
12+
// Input uniform values
13+
uniform sampler2D texture0;
14+
uniform vec4 colDiffuse;
15+
16+
// Output fragment color
17+
out vec4 finalColor;
18+
19+
// Input lighting values
20+
uniform vec3 lightDir;
21+
uniform vec4 lightColor;
22+
uniform vec4 ambient;
23+
uniform vec3 viewPos;
24+
25+
// Input shadowmapping values
26+
uniform mat4 lightVP; // Light source view-projection matrix
27+
uniform sampler2D shadowMap;
28+
29+
uniform int shadowMapResolution;
30+
31+
void main()
32+
{
33+
// Texel color fetching from texture sampler
34+
vec4 texelColor = texture(texture0, fragTexCoord);
35+
vec3 lightDot = vec3(0.0);
36+
vec3 normal = normalize(fragNormal);
37+
vec3 viewD = normalize(viewPos - fragPosition);
38+
vec3 specular = vec3(0.0);
39+
40+
vec3 l = -lightDir;
41+
42+
float NdotL = max(dot(normal, l), 0.0);
43+
lightDot += lightColor.rgb*NdotL;
44+
45+
float specCo = 0.0;
46+
if (NdotL > 0.0) specCo = pow(max(0.0, dot(viewD, reflect(-(l), normal))), 16.0); // 16 refers to shine
47+
specular += specCo;
48+
49+
finalColor = (texelColor*((colDiffuse + vec4(specular, 1.0))*vec4(lightDot, 1.0)));
50+
51+
// Shadow calculations
52+
vec4 fragPosLightSpace = lightVP * vec4(fragPosition, 1);
53+
fragPosLightSpace.xyz /= fragPosLightSpace.w; // Perform the perspective division
54+
fragPosLightSpace.xyz = (fragPosLightSpace.xyz + 1.0f) / 2.0f; // Transform from [-1, 1] range to [0, 1] range
55+
vec2 sampleCoords = fragPosLightSpace.xy;
56+
float curDepth = fragPosLightSpace.z;
57+
// Slope-scale depth bias: depth biasing reduces "shadow acne" artifacts, where dark stripes appear all over the scene.
58+
// The solution is adding a small bias to the depth
59+
// In this case, the bias is proportional to the slope of the surface, relative to the light
60+
float bias = max(0.0002 * (1.0 - dot(normal, l)), 0.00002) + 0.00001;
61+
int shadowCounter = 0;
62+
const int numSamples = 9;
63+
// PCF (percentage-closer filtering) algorithm:
64+
// Instead of testing if just one point is closer to the current point,
65+
// we test the surrounding points as well.
66+
// This blurs shadow edges, hiding aliasing artifacts.
67+
vec2 texelSize = vec2(1.0f / float(shadowMapResolution));
68+
for (int x = -1; x <= 1; x++)
69+
{
70+
for (int y = -1; y <= 1; y++)
71+
{
72+
float sampleDepth = texture(shadowMap, sampleCoords + texelSize * vec2(x, y)).r;
73+
if (curDepth - bias > sampleDepth)
74+
{
75+
shadowCounter++;
76+
}
77+
}
78+
}
79+
finalColor = mix(finalColor, vec4(0, 0, 0, 1), float(shadowCounter) / float(numSamples));
80+
81+
// Add ambient lighting whether in shadow or not
82+
finalColor += texelColor*(ambient/10.0)*colDiffuse;
83+
84+
// Gamma correction
85+
finalColor = pow(finalColor, vec4(1.0/2.2));
86+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#version 330
2+
3+
// Input vertex attributes
4+
in vec3 vertexPosition;
5+
in vec2 vertexTexCoord;
6+
in vec3 vertexNormal;
7+
in vec4 vertexColor;
8+
9+
// Input uniform values
10+
uniform mat4 mvp;
11+
uniform mat4 matModel;
12+
uniform mat4 matNormal;
13+
14+
// Output vertex attributes (to fragment shader)
15+
out vec3 fragPosition;
16+
out vec2 fragTexCoord;
17+
out vec4 fragColor;
18+
out vec3 fragNormal;
19+
20+
// NOTE: Add here your custom variables
21+
22+
void main()
23+
{
24+
// Send vertex attributes to fragment shader
25+
fragPosition = vec3(matModel*vec4(vertexPosition, 1.0));
26+
fragTexCoord = vertexTexCoord;
27+
fragColor = vertexColor;
28+
fragNormal = normalize(vec3(matNormal*vec4(vertexNormal, 1.0)));
29+
30+
// Calculate final vertex position
31+
gl_Position = mvp*vec4(vertexPosition, 1.0);
32+
}

0 commit comments

Comments
 (0)