EEVEE-Next: Fix missing shadow caused by ray going below surface
[blender.git] / source / blender / draw / engines / eevee_next / shaders / eevee_shadow_tracing_lib.glsl
blob2cc071c43407ce0f5c1f83ca6079dd248ea67224
1 /* SPDX-FileCopyrightText: 2023 Blender Authors
2  *
3  * SPDX-License-Identifier: GPL-2.0-or-later */
5 /**
6  * Evaluate shadowing using shadow map ray-tracing.
7  */
9 #pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl)
10 #pragma BLENDER_REQUIRE(gpu_shader_math_matrix_lib.glsl)
11 #pragma BLENDER_REQUIRE(eevee_light_lib.glsl)
12 #pragma BLENDER_REQUIRE(eevee_shadow_lib.glsl)
13 #pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
14 #pragma BLENDER_REQUIRE(eevee_bxdf_sampling_lib.glsl)
15 #pragma BLENDER_REQUIRE(draw_view_lib.glsl)
16 #pragma BLENDER_REQUIRE(draw_math_geom_lib.glsl)
18 float shadow_read_depth_at_tilemap_uv(int tilemap_index, vec2 tilemap_uv)
20   /* Prevent out of bound access. Assumes the input is already non negative. */
21   tilemap_uv = min(tilemap_uv, vec2(0.99999));
23   ivec2 texel_coord = ivec2(tilemap_uv * float(SHADOW_MAP_MAX_RES));
24   /* Using bitwise ops is way faster than integer ops. */
25   const int page_shift = SHADOW_PAGE_LOD;
26   const int page_mask = ~(0xFFFFFFFF << SHADOW_PAGE_LOD);
28   ivec2 tile_coord = texel_coord >> page_shift;
29   ShadowSamplingTile tile = shadow_tile_load(shadow_tilemaps_tx, tile_coord, tilemap_index);
31   if (!tile.is_valid) {
32     return -1.0;
33   }
34   /* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */
35   /* TODO convert everything to uint to avoid signed int operations. */
36   texel_coord += ivec2(tile.lod_offset << SHADOW_PAGE_LOD);
37   /* Scale to LOD pixels (merge LOD0 pixels together) then mask to get pixel in page. */
38   ivec2 texel_page = (texel_coord >> int(tile.lod)) & page_mask;
39   ivec3 texel = ivec3((ivec2(tile.page.xy) << page_shift) | texel_page, tile.page.z);
41   return uintBitsToFloat(texelFetch(shadow_atlas_tx, texel, 0).r);
44 /* ---------------------------------------------------------------------- */
45 /** \name Shadow Map Tracing loop
46  * \{ */
48 #define SHADOW_TRACING_INVALID_HISTORY -999.0
50 struct ShadowMapTracingState {
51   /* Receiver Z value at previous valid depth sample. */
52   float receiver_depth_history;
53   /* Occluder Z value at previous valid depth sample. */
54   float occluder_depth_history;
55   /* Ray time at previous valid depth sample. */
56   float ray_time_history;
57   /* Z slope (delta/time) between previous valid sample (N-1) and the one before that (N-2). */
58   float occluder_depth_slope;
59   /* Multiplier and bias to the ray step quickly compute ray time. */
60   float ray_step_mul;
61   float ray_step_bias;
62   /* State of the trace. */
63   float ray_time;
64   bool hit;
67 ShadowMapTracingState shadow_map_trace_init(int sample_count, float step_offset)
69   ShadowMapTracingState state;
70   state.receiver_depth_history = -1.0;
71   state.occluder_depth_history = SHADOW_TRACING_INVALID_HISTORY;
72   state.ray_time_history = -1.0;
73   state.occluder_depth_slope = 0.0;
74   /* We trace the ray in reverse. From 1.0 (light) to 0.0 (shading point). */
75   state.ray_step_mul = -1.0 / float(sample_count);
76   state.ray_step_bias = 1.0 + step_offset * state.ray_step_mul;
77   state.hit = false;
78   return state;
81 struct ShadowTracingSample {
82   float receiver_depth;
83   float occluder_depth;
84   bool skip_sample;
87 /**
88  * This need to be instantiated for each `ShadowRay*` type.
89  * This way we can implement `shadow_map_trace_sample` for each type without too much code
90  * duplication.
91  * Most of the code is wrapped into functions to avoid to debug issues inside macro code.
92  */
93 #define SHADOW_MAP_TRACE_FN(ShadowRayType) \
94   ShadowMapTraceResult shadow_map_trace(ShadowRayType ray, int sample_count, float step_offset) \
95   { \
96     ShadowMapTracingState state = shadow_map_trace_init(sample_count, step_offset); \
97     for (int i = 0; (i <= sample_count) && (i <= SHADOW_MAX_STEP) && (state.hit == false); i++) { \
98       /* Saturate to always cover the shading point position when i == sample_count. */ \
99       state.ray_time = square(saturate(float(i) * state.ray_step_mul + state.ray_step_bias)); \
101       ShadowTracingSample samp = shadow_map_trace_sample(state, ray); \
103       shadow_map_trace_hit_check(state, samp); \
104     } \
105     return shadow_map_trace_finish(state); \
106   }
109  * We trace from a point on the light towards the shading point.
111  * This reverse tracing allows to approximate the geometry behind occluders while minimizing
112  * light-leaks.
113  */
114 void shadow_map_trace_hit_check(inout ShadowMapTracingState state, ShadowTracingSample samp)
116   /* Skip empty tiles since they do not contain actual depth information.
117    * Not doing so would change the z gradient history. */
118   if (samp.skip_sample) {
119     return;
120   }
121   /* For the first sample, regular depth compare since we do not have history values. */
122   if (state.occluder_depth_history == SHADOW_TRACING_INVALID_HISTORY) {
123     if (samp.occluder_depth < samp.receiver_depth) {
124       state.hit = true;
125       return;
126     }
127     state.occluder_depth_history = samp.occluder_depth;
128     state.receiver_depth_history = samp.receiver_depth;
129     state.ray_time_history = state.ray_time;
130     return;
131   }
132   /* Delta between previous valid sample. */
133   float ray_depth_delta = samp.receiver_depth - state.receiver_depth_history;
134   /* Delta between previous valid sample not occluding the ray. */
135   float time_delta = state.ray_time - state.ray_time_history;
136   /* Arbitrary increase the threshold to avoid missing occluders because of precision issues.
137    * Increasing the threshold inflates the occluders. */
138   float compare_threshold = abs(ray_depth_delta) * 1.05;
139   /* Find out if the ray step is behind an occluder.
140    * To be consider behind (and ignore the occluder), the occluder must not be cross the ray.
141    * Use the full delta ray depth as threshold to make sure to not miss any occluder. */
142   bool is_behind = samp.occluder_depth < (samp.receiver_depth - compare_threshold);
144   if (is_behind) {
145     /* Use last known valid occluder Z value and extrapolate to the sample position. */
146     samp.occluder_depth = state.occluder_depth_history + state.occluder_depth_slope * time_delta;
147     /* Intersection test will be against the extrapolated last known occluder. */
148   }
149   else {
150     /* Compute current occluder slope and record history for when the ray goes behind a surface. */
151     state.occluder_depth_slope = (samp.occluder_depth - state.occluder_depth_history) / time_delta;
152     state.occluder_depth_slope = clamp(state.occluder_depth_slope, -100.0, 100.0);
153     state.occluder_depth_history = samp.occluder_depth;
154     state.ray_time_history = state.ray_time;
155     /* Intersection test will be against the current sample's occluder. */
156   }
158   if (samp.occluder_depth < samp.receiver_depth) {
159     state.occluder_depth_history = samp.occluder_depth;
160     state.hit = true;
161     return;
162   }
163   /* No intersection. */
164   state.receiver_depth_history = samp.receiver_depth;
167 struct ShadowMapTraceResult {
168   bool has_hit;
169   float occluder_depth;
172 ShadowMapTraceResult shadow_map_trace_finish(ShadowMapTracingState state)
174   ShadowMapTraceResult result;
175   if (state.hit) {
176     result.occluder_depth = state.occluder_depth_history;
177     result.has_hit = true;
178   }
179   else {
180     result.occluder_depth = 0.0;
181     result.has_hit = false;
182   }
183   return result;
186 /** \} */
188 /* If the ray direction `L`  is below the horizon defined by N (normalized) at the shading point,
189  * push it just above the horizon so that this ray will never be below it and produce
190  * over-shadowing (since light evaluation already clips the light shape). */
191 vec3 shadow_ray_above_horizon_ensure(vec3 L, vec3 N)
193   float distance_to_plan = dot(L, -N);
194   if (distance_to_plan > 0.0) {
195     L += N * (0.01 + distance_to_plan);
196   }
197   return L;
200 /* ---------------------------------------------------------------------- */
201 /** \name Directional Shadow Map Tracing
202  * \{ */
204 struct ShadowRayDirectional {
205   /* Ray in local translated coordinate, with depth in [0..1] range in W component. */
206   vec4 origin;
207   vec4 direction;
208   LightData light;
211 ShadowRayDirectional shadow_ray_generate_directional(LightData light,
212                                                      vec2 random_2d,
213                                                      vec3 lP,
214                                                      vec3 lNg)
216   float clip_near = orderedIntBitsToFloat(light.clip_near);
217   float clip_far = orderedIntBitsToFloat(light.clip_far);
218   /* Assumed to be non-null. */
219   float z_range = clip_far - clip_near;
220   float dist_to_near_plane = -lP.z - clip_near;
222   /* `lP` is supposed to be in light rotated space. But not translated. */
223   vec4 origin = vec4(lP, dist_to_near_plane / z_range);
225   vec3 disk_direction = sample_uniform_cone(sample_cylinder(random_2d),
226                                             light_sun_data_get(light).shadow_angle);
228   disk_direction = shadow_ray_above_horizon_ensure(disk_direction, lNg);
230   /* Light shape is 1 unit away from the shading point. */
231   vec4 direction = vec4(disk_direction, -1.0 / z_range);
233   /* It only make sense to trace where there can be occluder. Clamp by distance to near plane. */
234   direction *= min(light_sun_data_get(light).shadow_trace_distance,
235                    dist_to_near_plane / disk_direction.z);
237   ShadowRayDirectional ray;
238   ray.origin = origin;
239   ray.direction = direction;
240   ray.light = light;
241   return ray;
244 ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state,
245                                             inout ShadowRayDirectional ray)
247   /* Ray position is ray local position with origin at light origin. */
248   vec4 ray_pos = ray.origin + ray.direction * state.ray_time;
250   int level = shadow_directional_level(ray.light, ray_pos.xyz - ray.light._position);
251   /* This difference needs to be less than 32 for the later shift to be valid.
252    * This is ensured by ShadowDirectional::clipmap_level_range(). */
253   int level_relative = level - light_sun_data_get(ray.light).clipmap_lod_min;
255   int lod_relative = (ray.light.type == LIGHT_SUN_ORTHO) ?
256                          light_sun_data_get(ray.light).clipmap_lod_min :
257                          level;
259   vec2 clipmap_origin = light_sun_data_get(ray.light).clipmap_origin;
260   vec2 clipmap_pos = ray_pos.xy - clipmap_origin;
261   vec2 tilemap_uv = clipmap_pos * exp2(-float(lod_relative)) + 0.5;
263   /* Compute offset in tile. */
264   ivec2 clipmap_offset = shadow_decompress_grid_offset(
265       ray.light.type,
266       light_sun_data_get(ray.light).clipmap_base_offset_neg,
267       light_sun_data_get(ray.light).clipmap_base_offset_pos,
268       level_relative);
269   /* Translate tilemap UVs to its origin. */
270   tilemap_uv -= vec2(clipmap_offset) / float(SHADOW_TILEMAP_RES);
271   /* Clamp to avoid out of tilemap access. */
272   tilemap_uv = saturate(tilemap_uv);
274   ShadowTracingSample samp;
275   samp.receiver_depth = ray_pos.w;
276   samp.occluder_depth = shadow_read_depth_at_tilemap_uv(ray.light.tilemap_index + level_relative,
277                                                         tilemap_uv);
278   samp.skip_sample = (samp.occluder_depth == -1.0);
279   return samp;
282 SHADOW_MAP_TRACE_FN(ShadowRayDirectional)
284 /** \} */
286 /* ---------------------------------------------------------------------- */
287 /** \name Punctual Shadow Map Tracing
288  * \{ */
290 struct ShadowRayPunctual {
291   /* Ray in tile-map normalized coordinates [0..1]. */
292   vec3 origin;
293   vec3 direction;
294   /* Tile-map to sample. */
295   int tilemap_index;
298 /* Return ray in UV clip space [0..1]. */
299 ShadowRayPunctual shadow_ray_generate_punctual(LightData light, vec2 random_2d, vec3 lP, vec3 lNg)
301   if (light.type == LIGHT_RECT) {
302     random_2d = random_2d * 2.0 - 1.0;
303   }
304   else {
305     random_2d = sample_disk(random_2d);
306   }
308   float clip_far = intBitsToFloat(light.clip_far);
309   float clip_near = intBitsToFloat(light.clip_near);
310   float clip_side = light_local_data_get(light).clip_side;
312   /* TODO(fclem): 3D shift for jittered soft shadows. */
313   vec3 projection_origin = vec3(0.0, 0.0, -light_local_data_get(light).shadow_projection_shift);
314   vec3 direction;
315   if (is_area_light(light.type)) {
316     random_2d *= light_area_data_get(light).size;
318     vec3 point_on_light_shape = vec3(random_2d, 0.0);
319     /* Progressively blend the shape back to the projection origin. */
320     point_on_light_shape = mix(
321         -projection_origin, point_on_light_shape, light_local_data_get(light).shadow_scale);
323     direction = point_on_light_shape - lP;
324     direction = shadow_ray_above_horizon_ensure(direction, lNg);
326     /* Clip the ray to not cross the near plane.
327      * Scale it so that it encompass the whole cube (with a safety margin). */
328     float clip_distance = clip_near + 0.001;
329     float ray_length = max(abs(direction.x), max(abs(direction.y), abs(direction.z)));
330     direction *= saturate((ray_length - clip_distance) / ray_length);
331   }
332   else {
333     float dist;
334     vec3 L = normalize_and_get_length(lP, dist);
335     /* Disk rotated towards light vector. */
336     vec3 right, up;
337     make_orthonormal_basis(L, right, up);
339     float shape_radius = light_spot_data_get(light).radius;
340     if (is_sphere_light(light.type)) {
341       /* FIXME(weizhen): this is not well-defined when `dist < light.spot.radius`. */
342       shape_radius = light_sphere_disk_radius(shape_radius, dist);
343     }
344     random_2d *= shape_radius;
346     random_2d *= light_local_data_get(light).shadow_scale;
347     vec3 point_on_light_shape = right * random_2d.x + up * random_2d.y;
349     direction = point_on_light_shape - lP;
350     direction = shadow_ray_above_horizon_ensure(direction, lNg);
352     /* Clip the ray to not cross the light shape. */
353     float clip_distance = light_spot_data_get(light).radius;
354     direction *= saturate((dist - clip_distance) / dist);
355   }
357   /* Apply shadow origin shift. */
358   vec3 local_ray_start = lP + projection_origin;
359   vec3 local_ray_end = local_ray_start + direction;
361   /* Use an offset in the ray direction to jitter which face is traced.
362    * This helps hiding some harsh discontinuity. */
363   int face_id = shadow_punctual_face_index_get(local_ray_start + direction * 0.5);
364   /* Local Light Space > Face Local (View) Space. */
365   vec3 view_ray_start = shadow_punctual_local_position_to_face_local(face_id, local_ray_start);
366   vec3 view_ray_end = shadow_punctual_local_position_to_face_local(face_id, local_ray_end);
368   /* Face Local (View) Space > Clip Space. */
369   /* TODO: Could be simplified since frustum is completely symmetrical. */
370   mat4 winmat = projection_perspective(
371       -clip_side, clip_side, -clip_side, clip_side, clip_near, clip_far);
372   vec3 clip_ray_start = project_point(winmat, view_ray_start);
373   vec3 clip_ray_end = project_point(winmat, view_ray_end);
374   /* Clip Space > UV Space. */
375   vec3 uv_ray_start = clip_ray_start * 0.5 + 0.5;
376   vec3 uv_ray_end = clip_ray_end * 0.5 + 0.5;
377   /* Compute the ray again. */
378   ShadowRayPunctual ray;
379   ray.origin = uv_ray_start;
380   ray.direction = uv_ray_end - uv_ray_start;
381   ray.tilemap_index = light.tilemap_index + face_id;
382   return ray;
385 ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state,
386                                             inout ShadowRayPunctual ray)
388   vec3 ray_pos = ray.origin + ray.direction * state.ray_time;
389   vec2 tilemap_uv = saturate(ray_pos.xy);
391   ShadowTracingSample samp;
392   samp.receiver_depth = ray_pos.z;
393   samp.occluder_depth = shadow_read_depth_at_tilemap_uv(ray.tilemap_index, tilemap_uv);
394   samp.skip_sample = (samp.occluder_depth == -1.0);
395   return samp;
398 SHADOW_MAP_TRACE_FN(ShadowRayPunctual)
400 /** \} */
402 /* ---------------------------------------------------------------------- */
403 /** \name Shadow Evaluation
404  * \{ */
406 /* Compute the world space offset of the shading position required for
407  * stochastic percentage closer filtering of shadow-maps. */
408 vec3 shadow_pcf_offset(LightData light, const bool is_directional, vec3 P, vec3 Ng, vec2 random)
410   if (light.pcf_radius <= 0.001) {
411     /* Early return. */
412     return vec3(0.0);
413   }
415   vec3 L = light_vector_get(light, is_directional, P).L;
416   if (dot(L, Ng) < 0.001) {
417     /* Don't apply PCF to almost perpendicular,
418      * since we can't project the offset to the surface. */
419     return vec3(0.0);
420   }
422   ShadowSampleParams params;
423   if (is_directional) {
424     params = shadow_directional_sample_params_get(shadow_tilemaps_tx, light, P);
425   }
426   else {
427     params = shadow_punctual_sample_params_get(light, P);
428   }
429   ShadowSamplingTile tile = shadow_tile_data_get(shadow_tilemaps_tx, params);
430   if (!tile.is_valid) {
431     return vec3(0.0);
432   }
434   /* Compute the shadow-map tangent-bitangent matrix. */
436   float uv_offset = 1.0 / float(SHADOW_MAP_MAX_RES);
437   vec3 TP, BP;
438   if (is_directional) {
439     TP = shadow_directional_reconstruct_position(
440         params, light, params.uv + vec3(uv_offset, 0.0, 0.0));
441     BP = shadow_directional_reconstruct_position(
442         params, light, params.uv + vec3(0.0, uv_offset, 0.0));
443   }
444   else {
445     mat4 wininv = shadow_punctual_projection_perspective_inverse(light);
446     TP = shadow_punctual_reconstruct_position(
447         params, wininv, light, params.uv + vec3(uv_offset, 0.0, 0.0));
448     BP = shadow_punctual_reconstruct_position(
449         params, wininv, light, params.uv + vec3(0.0, uv_offset, 0.0));
450   }
452   /* TODO: Use a mat2x3 (Currently not supported by the Metal backend). */
453   mat3 TBN = mat3(TP - P, BP - P, Ng);
455   /* Compute the actual offset. */
457   vec2 pcf_offset = random * 2.0 - 1.0;
458   pcf_offset *= light.pcf_radius;
460   /* Scale the offset based on shadow LOD. */
461   if (is_directional) {
462     vec3 lP = light_world_to_local(light, P);
463     float level = shadow_directional_level_fractional(light, lP - light._position);
464     float pcf_scale = mix(0.5, 1.0, fract(level));
465     pcf_offset *= pcf_scale;
466   }
467   else {
468     bool is_perspective = drw_view_is_perspective();
469     float dist_to_cam = distance(P, drw_view_position());
470     float footprint_ratio = shadow_punctual_footprint_ratio(
471         light, P, is_perspective, dist_to_cam, uniform_buf.shadow.tilemap_projection_ratio);
472     float lod = -log2(footprint_ratio) + light.lod_bias;
473     lod = clamp(lod, 0.0, float(SHADOW_TILEMAP_LOD));
474     float pcf_scale = exp2(lod);
475     pcf_offset *= pcf_scale;
476   }
478   vec3 ws_offset = TBN * vec3(pcf_offset, 0.0);
479   vec3 offset_P = P + ws_offset;
481   /* Project the offset position into the surface */
483 #ifdef GPU_NVIDIA
484   /* Workaround for a bug in the Nvidia shader compiler.
485    * If we don't compute L here again, it breaks shadows on reflection probes. */
486   L = light_vector_get(light, is_directional, P).L;
487 #endif
489   if (abs(dot(Ng, L)) > 0.999) {
490     return ws_offset;
491   }
493   offset_P = line_plane_intersect(offset_P, L, P, Ng);
494   ws_offset = offset_P - P;
496   if (dot(ws_offset, L) < 0.0) {
497     /* Project the offset position into the perpendicular plane, since it's closer to the light
498      * (avoids overshadowing at geometry angles). */
499     vec3 perpendicular_plane_normal = cross(Ng, normalize(cross(Ng, L)));
500     offset_P = line_plane_intersect(offset_P, L, P, perpendicular_plane_normal);
501     ws_offset = offset_P - P;
502   }
504   return ws_offset;
508  * Evaluate shadowing by casting rays toward the light direction.
509  */
510 ShadowEvalResult shadow_eval(LightData light,
511                              const bool is_directional,
512                              const bool is_transmission,
513                              vec3 P,
514                              vec3 Ng,
515                              int ray_count,
516                              int ray_step_count)
518 #ifdef EEVEE_SAMPLING_DATA
519 #  ifdef GPU_FRAGMENT_SHADER
520   vec2 pixel = floor(gl_FragCoord.xy);
521 #  elif defined(GPU_COMPUTE_SHADER)
522   vec2 pixel = vec2(gl_GlobalInvocationID.xy);
523 #  endif
524   vec3 blue_noise_3d = utility_tx_fetch(utility_tx, pixel, UTIL_BLUE_NOISE_LAYER).rgb;
525   vec3 random_shadow_3d = blue_noise_3d + sampling_rng_3D_get(SAMPLING_SHADOW_U);
526   vec2 random_pcf_2d = fract(blue_noise_3d.xy + sampling_rng_2D_get(SAMPLING_SHADOW_X));
527   float normal_offset = uniform_buf.shadow.normal_bias;
528 #else
529   /* Case of surfel light eval. */
530   vec3 random_shadow_3d = vec3(0.5);
531   vec2 random_pcf_2d = vec2(0.0);
532   /* TODO(fclem): Parameter on irradiance volumes? */
533   float normal_offset = 0.02;
534 #endif
536   /* We want to bias inside the object for transmission to go through the object itself. */
537   normal_offset = is_transmission ? -normal_offset : normal_offset;
539   P += shadow_pcf_offset(light, is_directional, P, Ng, random_pcf_2d);
541   /* Avoid self intersection. */
542   P = offset_ray(P, Ng);
543   /* The above offset isn't enough in most situation. Still add a bigger bias. */
544   /* TODO(fclem): Scale based on depth. */
545   P += Ng * normal_offset;
547   vec3 lP = is_directional ? light_world_to_local(light, P) :
548                              light_world_to_local(light, P - light._position);
549   vec3 lNg = light_world_to_local(light, Ng);
551   float surface_hit = 0.0;
552   for (int ray_index = 0; ray_index < ray_count && ray_index < SHADOW_MAX_RAY; ray_index++) {
553     vec2 random_ray_2d = fract(hammersley_2d(ray_index, ray_count) + random_shadow_3d.xy);
555     ShadowMapTraceResult trace;
556     if (is_directional) {
557       ShadowRayDirectional clip_ray = shadow_ray_generate_directional(
558           light, random_ray_2d, lP, lNg);
559       trace = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z);
560     }
561     else {
562       ShadowRayPunctual clip_ray = shadow_ray_generate_punctual(light, random_ray_2d, lP, lNg);
563       trace = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z);
564     }
566     surface_hit += float(trace.has_hit);
567   }
568   /* Average samples. */
569   ShadowEvalResult result;
570   result.light_visibilty = saturate(1.0 - surface_hit * float(ray_count));
571   result.occluder_distance = 0.0; /* Unused. Could reintroduced if needed. */
572   return result;
575 /** \} */