54f7dc10222f38b43ea8f16e27a39af878433fef
[blender.git] / source / blender / draw / engines / eevee / shaders / shadow_copy_frag.glsl
1 /* Copy the depth only shadowmap into another texture while converting
2  * to linear depth (or other storage method) and doing a 3x3 box filter. */
3
4 layout(std140) uniform shadow_render_block
5 {
6   /* Use vectors to avoid alignement padding. */
7   ivec4 shadowSampleCount;
8   vec4 shadowInvSampleCount;
9   vec4 filterSize;
10   int viewCount;
11   int baseId;
12   float cubeTexelSize;
13   float storedTexelSize;
14   float nearClip;
15   float farClip;
16   float exponent;
17 };
18
19 #ifdef CSM
20 uniform sampler2DArray shadowTexture;
21 #else
22 uniform samplerCube shadowTexture;
23 #endif
24
25 flat in int layerID;
26
27 #ifdef CSM
28 #  define cascadeID layerID
29 #else
30 #  define cascadeID 0
31 #endif
32
33 out vec4 FragColor;
34
35 #define linear_depth(z) \
36   ((nearClip * farClip) / (clamp(z, 0.0, 0.999999) * (nearClip - farClip) + farClip))
37
38 /* add bias so background filtering does not bleed into shadow map */
39 #define BACKGROUND_BIAS 0.05
40
41 #ifdef CSM
42 vec4 get_world_distance(vec4 depths, vec3 cos[4])
43 {
44   depths += step(vec4(0.9999), depths) * BACKGROUND_BIAS;
45   return clamp(
46       depths * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
47 }
48
49 float get_world_distance(float depth, vec3 cos)
50 {
51   depth += step(0.9999, depth) * BACKGROUND_BIAS;
52   return clamp(
53       depth * abs(farClip - nearClip), 0.0, 1e10); /* Same factor as in shadow_cascade(). */
54 }
55
56 #else /* CUBEMAP */
57 vec4 get_world_distance(vec4 depths, vec3 cos[4])
58 {
59   depths = linear_depth(depths);
60   cos[0] = normalize(abs(cos[0]));
61   cos[1] = normalize(abs(cos[1]));
62   cos[2] = normalize(abs(cos[2]));
63   cos[3] = normalize(abs(cos[3]));
64   vec4 cos_vec;
65   cos_vec.x = max(cos[0].x, max(cos[0].y, cos[0].z));
66   cos_vec.y = max(cos[1].x, max(cos[1].y, cos[1].z));
67   cos_vec.z = max(cos[2].x, max(cos[2].y, cos[2].z));
68   cos_vec.w = max(cos[3].x, max(cos[3].y, cos[3].z));
69   return depths / cos_vec;
70 }
71
72 float get_world_distance(float depth, vec3 cos)
73 {
74   depth = linear_depth(depth);
75   cos = normalize(abs(cos));
76   float cos_vec = max(cos.x, max(cos.y, cos.z));
77   return depth / cos_vec;
78 }
79 #endif
80
81 /* Marco Salvi's GDC 2008 presentation about shadow maps pre-filtering techniques slide 24 */
82 #define ln_space_prefilter_step(ref, sample) exp(sample - ref)
83 #define ln_space_prefilter_finalize(ref, sum) (ref + log(SAMPLE_WEIGHT * sum))
84
85 #define SAMPLE_WEIGHT 0.11111
86
87 #ifdef ESM
88 void prefilter(vec4 depths, float ref, inout float accum)
89 {
90   accum += dot(ln_space_prefilter_step(ref, depths), vec4(1.0));
91 }
92 #else /* VSM */
93 void prefilter(vec4 depths, float ref, inout vec2 accum)
94 {
95   vec4 depths_sqr = depths * depths;
96   accum += vec2(dot(vec4(1.0), depths), dot(vec4(1.0), depths_sqr)) * SAMPLE_WEIGHT;
97 }
98 #endif
99
100 #ifdef CSM
101 vec3 get_texco(vec2 uvs, vec2 ofs)
102 {
103   return vec3(uvs + ofs, float(cascadeID));
104 }
105 #else /* CUBEMAP */
106 const vec3 minorAxisX[6] = vec3[6](vec3(0.0f, 0.0f, -1.0f),
107                                    vec3(0.0f, 0.0f, 1.0f),
108                                    vec3(1.0f, 0.0f, 0.0f),
109                                    vec3(1.0f, 0.0f, 0.0f),
110                                    vec3(1.0f, 0.0f, 0.0f),
111                                    vec3(-1.0f, 0.0f, 0.0f));
112
113 const vec3 minorAxisY[6] = vec3[6](vec3(0.0f, -1.0f, 0.0f),
114                                    vec3(0.0f, -1.0f, 0.0f),
115                                    vec3(0.0f, 0.0f, 1.0f),
116                                    vec3(0.0f, 0.0f, -1.0f),
117                                    vec3(0.0f, -1.0f, 0.0f),
118                                    vec3(0.0f, -1.0f, 0.0f));
119
120 const vec3 majorAxis[6] = vec3[6](vec3(1.0f, 0.0f, 0.0f),
121                                   vec3(-1.0f, 0.0f, 0.0f),
122                                   vec3(0.0f, 1.0f, 0.0f),
123                                   vec3(0.0f, -1.0f, 0.0f),
124                                   vec3(0.0f, 0.0f, 1.0f),
125                                   vec3(0.0f, 0.0f, -1.0f));
126
127 vec3 get_texco(vec2 uvs, vec2 ofs)
128 {
129   uvs += ofs;
130   return majorAxis[layerID] + uvs.x * minorAxisX[layerID] + uvs.y * minorAxisY[layerID];
131 }
132 #endif
133
134 void main()
135 {
136   /* Copy the depth only shadowmap into another texture while converting
137    * to linear depth and do a 3x3 box blur. */
138
139 #ifdef CSM
140   vec2 uvs = gl_FragCoord.xy * storedTexelSize;
141 #else /* CUBEMAP */
142   vec2 uvs = gl_FragCoord.xy * cubeTexelSize * 2.0 - 1.0;
143 #endif
144
145   /* Center texel */
146   vec3 co = get_texco(uvs, vec2(0.0));
147   float depth = texture(shadowTexture, co).r;
148   depth = get_world_distance(depth, co);
149
150   if (filterSize[cascadeID] == 0.0) {
151 #ifdef ESM
152     FragColor = vec4(depth);
153 #else /* VSM */
154     FragColor = vec2(depth, depth * depth).xyxy;
155 #endif
156     return;
157   }
158
159 #ifdef ESM
160   float ref = depth;
161   float accum = 1.0;
162 #else /* VSM */
163   float ref = 0.0; /* UNUSED */
164   vec2 accum = vec2(depth, depth * depth) * SAMPLE_WEIGHT;
165 #endif
166
167   vec3 ofs = vec3(1.0, 0.0, -1.0) * filterSize[cascadeID];
168
169   vec3 cos[4];
170   cos[0] = get_texco(uvs, ofs.zz);
171   cos[1] = get_texco(uvs, ofs.yz);
172   cos[2] = get_texco(uvs, ofs.xz);
173   cos[3] = get_texco(uvs, ofs.zy);
174
175   vec4 depths;
176   depths.x = texture(shadowTexture, cos[0]).r;
177   depths.y = texture(shadowTexture, cos[1]).r;
178   depths.z = texture(shadowTexture, cos[2]).r;
179   depths.w = texture(shadowTexture, cos[3]).r;
180   depths = get_world_distance(depths, cos);
181   prefilter(depths, ref, accum);
182
183   cos[0] = get_texco(uvs, ofs.xy);
184   cos[1] = get_texco(uvs, ofs.zx);
185   cos[2] = get_texco(uvs, ofs.yx);
186   cos[3] = get_texco(uvs, ofs.xx);
187   depths.x = texture(shadowTexture, cos[0]).r;
188   depths.y = texture(shadowTexture, cos[1]).r;
189   depths.z = texture(shadowTexture, cos[2]).r;
190   depths.w = texture(shadowTexture, cos[3]).r;
191   depths = get_world_distance(depths, cos);
192   prefilter(depths, ref, accum);
193
194 #ifdef ESM
195   accum = ln_space_prefilter_finalize(ref, accum);
196 #endif
197   /* Clamp infinite sum. */
198   FragColor = vec2(clamp(accum, 0.0, 1e16)).xyxy;
199 }