diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index db846693286..de9c05a9b10 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -1237,11 +1237,6 @@ struct ShadowTileMapData { float half_size; /** Offset in local space to the tilemap center in world units. Used for directional winmat. */ float2 center_offset; - /** Filter radius of the light in pixels. */ - float filter_radius; - float _pad0; - float _pad1; - float _pad2; }; BLI_STATIC_ASSERT_ALIGN(ShadowTileMapData, 16) @@ -1259,9 +1254,10 @@ struct ShadowRenderView { float clip_distance_inv; /* Viewport to submit the geometry of this tilemap view to. */ uint viewport_index; - /* Filter radius for this view. */ - float filter_radius; - uint _pad1; + /* True if comming from a sun light shadow. */ + bool32_t is_directionnal; + /* If directionnal, distance along the negative Z axis of the near clip in view space. */ + float clip_near; }; BLI_STATIC_ASSERT_ALIGN(ShadowRenderView, 16) diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 72e6599e361..c386b066e0d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -30,19 +30,15 @@ void ShadowTileMap::sync_orthographic(const float4x4 &object_mat_, int2 origin_offset, int clipmap_level, float lod_bias_, - float filter_radius_, eShadowProjectionType projection_type_) { - if ((projection_type != projection_type_) || (level != clipmap_level) || - (filter_radius != filter_radius_)) - { + if ((projection_type != projection_type_) || (level != clipmap_level)) { set_dirty(); } projection_type = projection_type_; level = clipmap_level; light_type = eLightType::LIGHT_SUN; is_area_side = false; - filter_radius = filter_radius_; if (grid_shift == int2(0)) { /* Only replace shift if it is not already dirty. */ @@ -82,7 +78,6 @@ void ShadowTileMap::sync_cubeface(eLightType light_type_, float side_, float shift, eCubeFace face, - float filter_radius_, float lod_bias_) { if (projection_type != SHADOW_PROJECTION_CUBEFACE || (cubeface != face)) { @@ -95,13 +90,10 @@ void ShadowTileMap::sync_cubeface(eLightType light_type_, light_type = light_type_; is_area_side = is_area_light(light_type) && (face != eCubeFace::Z_NEG); - if ((clip_near != near_) || (filter_radius != filter_radius_) || (clip_far != far_) || - (half_size != side_)) - { + if ((clip_near != near_) || (clip_far != far_) || (half_size != side_)) { set_dirty(); } - filter_radius = filter_radius_; clip_near = near_; clip_far = far_; area_shift = shift; @@ -274,100 +266,15 @@ void ShadowPunctual::release_excess_tilemaps() } void ShadowPunctual::compute_projection_boundaries(eLightType light_type, - float light_radius, - float shadow_radius, float max_lit_distance, float &near, float &far, float &side, float &back_shift) { - /* - * In order to make sure we can trace any ray in its entirety using a single tile-map, we have - * to make sure that the tile-map cover all potential occluder that can intersect any ray shot - * in this particular shadow quadrant. - * - * To this end, we inflate the tile-map perspective sides to make sure the - * tile-map frustum starts where the rays cannot go. - * - * We are interesting in finding `I` the new origin and `n` the new near plane distances. - * - * I .... Intersection between tangent and - * /| projection center axis - * / | - * / | - * / | - * / | - * / | - * / | - * / | - * / | - * / | - * / ....| - * / .... | - * / ... | - * /. | - * / | - * Tangent to light shape .... T\--------------N - * / --\ Beta | - * / -\ | - * / --\ | - * /. --\ | - * / . -\ | - * / . Alpha -O .... Light center - * / . /-/ | - * Inflated side / . /--- -/ | - * . / . /---- --/ | - * . / /---- . --/ | - * /-------------/------------X .... Desired near plane (inscribed cube) - * /---- --/ .. | - * /---- / --/ ... | - * /---- / --/ .... | - * / -/ ....| .... Shadow radius - * / --/ | - * /--/ | - * F .... Most distant shadow receiver possible. - * - * F: The most distant shadowed point at the edge of the 45° cube-face pyramid. - * O: The light origin. - * T: The tangent to the circle of radius `radius` centered at the origin and passing through F. - * I: Intersection between tangent and the projection center axis. - * N: The shifted near plane center. - * X: Intersection between the near plane and the projection center axis. - * Alpha: FOT angle. - * Beta: OTN angle. - * - * NOTE: FTO, ONT and TNI are right angles. - */ - float cos_alpha = shadow_radius / max_lit_distance; - float sin_alpha = sqrt(1.0f - math::square(cos_alpha)); - float near_shift = M_SQRT2 * shadow_radius * 0.5f * (sin_alpha - cos_alpha); - float side_shift = M_SQRT2 * shadow_radius * 0.5f * (sin_alpha + cos_alpha); - float origin_shift = M_SQRT2 * shadow_radius / (sin_alpha - cos_alpha); - - float min_near = (max_lit_distance / 4000.0f) / M_SQRT3; - - if (is_area_light(light_type)) { - /* Make near plane be inside the inscribed cube of the shadow sphere. */ - near = max_ff(shadow_radius / M_SQRT3, min_near); - /* Subtract min_near to make the shadow center match the light center if there is no shadow - * tracing required. This avoid light leaking issues near the light plane caused by the - * shadow discard clipping. */ - back_shift = (near - min_near); - } - else { - /* Make near plane be inside the inscribed cube of the light sphere. */ - near = max_ff(light_radius / M_SQRT3, min_near); - back_shift = 0.0f; - } - far = max_lit_distance; - if (shadow_radius > 1e-5f) { - side = ((side_shift / (origin_shift - near_shift)) * (origin_shift + near)); - } - else { - side = near; - } + near = side = (max_lit_distance / 4000.0f) / M_SQRT3; + back_shift = 0.0f; } void ShadowPunctual::end_sync(Light &light, float lod_bias) @@ -375,8 +282,7 @@ void ShadowPunctual::end_sync(Light &light, float lod_bias) ShadowTileMapPool &tilemap_pool = shadows_.tilemap_pool; float side, near, far, shift; - compute_projection_boundaries( - light.type, light_radius_, shadow_radius_, max_distance_, near, far, side, shift); + compute_projection_boundaries(light.type, max_distance_, near, far, side, shift); float4x4 obmat_tmp = light.object_to_world; @@ -385,21 +291,20 @@ void ShadowPunctual::end_sync(Light &light, float lod_bias) tilemaps_.append(tilemap_pool.acquire()); } - tilemaps_[Z_NEG]->sync_cubeface( - light.type, obmat_tmp, near, far, side, shift, Z_NEG, light.pcf_radius, lod_bias); + tilemaps_[Z_NEG]->sync_cubeface(light.type, obmat_tmp, near, far, side, shift, Z_NEG, lod_bias); if (tilemaps_needed_ >= 5) { tilemaps_[X_POS]->sync_cubeface( - light.type, obmat_tmp, near, far, side, shift, X_POS, light.pcf_radius, lod_bias); + light.type, obmat_tmp, near, far, side, shift, X_POS, lod_bias); tilemaps_[X_NEG]->sync_cubeface( - light.type, obmat_tmp, near, far, side, shift, X_NEG, light.pcf_radius, lod_bias); + light.type, obmat_tmp, near, far, side, shift, X_NEG, lod_bias); tilemaps_[Y_POS]->sync_cubeface( - light.type, obmat_tmp, near, far, side, shift, Y_POS, light.pcf_radius, lod_bias); + light.type, obmat_tmp, near, far, side, shift, Y_POS, lod_bias); tilemaps_[Y_NEG]->sync_cubeface( - light.type, obmat_tmp, near, far, side, shift, Y_NEG, light.pcf_radius, lod_bias); + light.type, obmat_tmp, near, far, side, shift, Y_NEG, lod_bias); } if (tilemaps_needed_ == 6) { tilemaps_[Z_POS]->sync_cubeface( - light.type, obmat_tmp, near, far, side, shift, Z_POS, light.pcf_radius, lod_bias); + light.type, obmat_tmp, near, far, side, shift, Z_POS, lod_bias); } light.tilemap_index = tilemap_pool.tilemaps_data.size(); @@ -544,8 +449,7 @@ void ShadowDirectional::cascade_tilemaps_distribution(Light &light, const Camera /* Equal spacing between cascades layers since we want uniform shadow density. */ int2 level_offset = origin_offset + shadow_cascade_grid_offset(light.sun.clipmap_base_offset_pos, i); - tilemap->sync_orthographic( - object_mat_, level_offset, level, 0.0f, light.pcf_radius, SHADOW_PROJECTION_CASCADE); + tilemap->sync_orthographic(object_mat_, level_offset, level, 0.0f, SHADOW_PROJECTION_CASCADE); /* Add shadow tile-maps grouped by lights to the GPU buffer. */ shadows_.tilemap_pool.tilemaps_data.append(*tilemap); @@ -612,7 +516,7 @@ void ShadowDirectional::clipmap_tilemaps_distribution(Light &light, int2 level_offset = int2(math::round(light_space_camera_position / tile_size)); tilemap->sync_orthographic( - object_mat_, level_offset, level, lod_bias, light.pcf_radius, SHADOW_PROJECTION_CLIPMAP); + object_mat_, level_offset, level, lod_bias, SHADOW_PROJECTION_CLIPMAP); /* Add shadow tile-maps grouped by lights to the GPU buffer. */ shadows_.tilemap_pool.tilemaps_data.append(*tilemap); @@ -1460,15 +1364,18 @@ void ShadowModule::set_view(View &view, int2 extent) { /* Depth is cleared to 0 for TBDR optimization. */ {GPU_LOADACTION_CLEAR, GPU_STOREACTION_DONT_CARE, {0.0f, 0.0f, 0.0f, 0.0f}}, - {GPU_LOADACTION_CLEAR, GPU_STOREACTION_DONT_CARE, {1.0f, 1.0f, 1.0f, 1.0f}}, + {GPU_LOADACTION_CLEAR, + GPU_STOREACTION_DONT_CARE, + {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX}}, }); } else if (shadow_depth_fb_tx_.is_valid()) { - GPU_framebuffer_bind_ex( - render_fb_, - { - {GPU_LOADACTION_CLEAR, GPU_STOREACTION_DONT_CARE, {1.0f, 1.0f, 1.0f, 1.0f}}, - }); + GPU_framebuffer_bind_ex(render_fb_, + { + {GPU_LOADACTION_CLEAR, + GPU_STOREACTION_DONT_CARE, + {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX}}, + }); } else { GPU_framebuffer_bind(render_fb_); diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.hh b/source/blender/draw/engines/eevee_next/eevee_shadow.hh index b8d2bfd0986..29241d7975c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.hh @@ -101,7 +101,6 @@ struct ShadowTileMap : public ShadowTileMapData { int2 origin_offset, int clipmap_level, float lod_bias_, - float filter_radius, eShadowProjectionType projection_type_); void sync_cubeface(eLightType light_type_, @@ -111,7 +110,6 @@ struct ShadowTileMap : public ShadowTileMapData { float side, float shift, eCubeFace face, - float filter_radius, float lod_bias_); void debug_draw() const; @@ -456,8 +454,6 @@ class ShadowPunctual : public NonCopyable, NonMovable { * quadrant. */ void compute_projection_boundaries(eLightType light_type, - float light_radius, - float shadow_radius, float max_lit_distance, float &near, float &far, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_thickness_amend_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_thickness_amend_frag.glsl index d90280ccb84..2079fb4a164 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_thickness_amend_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_thickness_amend_frag.glsl @@ -50,11 +50,10 @@ void thickness_from_shadow_single(uint l_idx, /* Inverting this bias means we will over estimate the distance. Which removes some artifacts. */ P_offset -= texel_radius * shadow_pcf_offset(lv.L, Ng, pcf_random); - ShadowEvalResult result = shadow_sample( + float occluder_delta = shadow_sample( is_directional, shadow_atlas_tx, shadow_tilemaps_tx, light, P_offset); - - if (result.light_visibilty == 0.0) { - float hit_distance = result.occluder_distance; + if (occluder_delta > 0.0) { + float hit_distance = abs(occluder_delta); /* Add back the amount of offset we added to the original position. * This avoids self shadowing issue. */ hit_distance += (normal_offset + 1.0) * texel_radius; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl index fbb66f5b00d..f917de46f6b 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_curves_vert.glsl @@ -14,7 +14,6 @@ void main() DRW_VIEW_FROM_RESOURCE_ID; #ifdef MAT_SHADOW shadow_viewport_layer_set(int(drw_view_id), int(render_view_buf[drw_view_id].viewport_index)); - shadow_flat.filter_radius = render_view_buf[drw_view_id].filter_radius; #endif init_interface(); @@ -59,8 +58,10 @@ void main() #endif #ifdef MAT_SHADOW - shadow_clip.vector = shadow_clip_vector_get(drw_point_world_to_view(interp.P), - render_view_buf[drw_view_id].clip_distance_inv); + vec3 vs_P = drw_point_world_to_view(interp.P); + ShadowRenderView view = render_view_buf[drw_view_id]; + shadow_clip.position = shadow_position_vector_get(vs_P, view); + shadow_clip.vector = shadow_clip_vector_get(vs_P, view.clip_distance_inv); #endif gl_Position = drw_point_world_to_homogenous(interp.P); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl index 326b51d3b85..cba3a75e1d1 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl @@ -14,7 +14,6 @@ void main() DRW_VIEW_FROM_RESOURCE_ID; #ifdef MAT_SHADOW shadow_viewport_layer_set(int(drw_view_id), int(render_view_buf[drw_view_id].viewport_index)); - shadow_flat.filter_radius = render_view_buf[drw_view_id].filter_radius; #endif init_interface(); @@ -59,7 +58,9 @@ void main() #endif #ifdef MAT_SHADOW - shadow_clip.vector = shadow_clip_vector_get(drw_point_world_to_view(interp.P), - render_view_buf[drw_view_id].clip_distance_inv); + vec3 vs_P = drw_point_world_to_view(interp.P); + ShadowRenderView view = render_view_buf[drw_view_id]; + shadow_clip.position = shadow_position_vector_get(vs_P, view); + shadow_clip.vector = shadow_clip_vector_get(vs_P, view.clip_distance_inv); #endif } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl index 0bb7103c9c3..f049810961c 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl @@ -13,7 +13,6 @@ void main() DRW_VIEW_FROM_RESOURCE_ID; #ifdef MAT_SHADOW shadow_viewport_layer_set(int(drw_view_id), int(render_view_buf[drw_view_id].viewport_index)); - shadow_flat.filter_radius = render_view_buf[drw_view_id].filter_radius; #endif init_interface(); @@ -41,8 +40,10 @@ void main() #endif #ifdef MAT_SHADOW - shadow_clip.vector = shadow_clip_vector_get(drw_point_world_to_view(interp.P), - render_view_buf[drw_view_id].clip_distance_inv); + vec3 vs_P = drw_point_world_to_view(interp.P); + ShadowRenderView view = render_view_buf[drw_view_id]; + shadow_clip.position = shadow_position_vector_get(vs_P, view); + shadow_clip.vector = shadow_clip_vector_get(vs_P, view.clip_distance_inv); #endif gl_Position = drw_point_world_to_homogenous(interp.P); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_point_cloud_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_point_cloud_vert.glsl index 8d5cd94587d..ba1e705afa5 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_geom_point_cloud_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_geom_point_cloud_vert.glsl @@ -15,7 +15,6 @@ void main() DRW_VIEW_FROM_RESOURCE_ID; #ifdef MAT_SHADOW shadow_viewport_layer_set(int(drw_view_id), int(render_view_buf[drw_view_id].viewport_index)); - shadow_flat.filter_radius = render_view_buf[drw_view_id].filter_radius; #endif init_interface(); @@ -53,8 +52,10 @@ void main() #endif #ifdef MAT_SHADOW - shadow_clip.vector = shadow_clip_vector_get(drw_point_world_to_view(interp.P), - render_view_buf[drw_view_id].clip_distance_inv); + vec3 vs_P = drw_point_world_to_view(interp.P); + ShadowRenderView view = render_view_buf[drw_view_id]; + shadow_clip.position = shadow_position_vector_get(vs_P, view); + shadow_clip.vector = shadow_clip_vector_get(vs_P, view.clip_distance_inv); #endif gl_Position = drw_point_world_to_homogenous(interp.P); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl index 1c8b6899ffa..7642bbf212a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_light_eval_lib.glsl @@ -181,17 +181,16 @@ void light_eval_single(uint l_idx, float shadow = 1.0; if (light.tilemap_index != LIGHT_NO_SHADOW) { - ShadowEvalResult result = shadow_eval(light, - is_directional, - is_transmission, - is_translucent_with_thickness, - thickness, - P, - Ng, - lv.L, - ray_count, - ray_step_count); - shadow = result.light_visibilty; + shadow = shadow_eval(light, + is_directional, + is_transmission, + is_translucent_with_thickness, + thickness, + P, + Ng, + lv.L, + ray_count, + ray_step_count); } if (is_translucent_with_thickness) { diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl index 34be1379611..77ecdeca6c6 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl @@ -18,6 +18,11 @@ /** Control the scaling of the tile-map splat. */ const float pixel_scale = 4.0; +ShadowSamplingTile shadow_tile_data_get(usampler2D tilemaps_tx, ShadowCoordinates coord) +{ + return shadow_tile_load(tilemaps_tx, coord.tilemap_tile, coord.tilemap_index); +} + vec3 debug_random_color(ivec2 v) { float r = interlieved_gradient_noise(vec2(v), 0.0, 0.0); @@ -69,19 +74,24 @@ vec3 debug_tile_state_color(eLightType type, ShadowSamplingTile tile) SHADOW_TILEMAP_LOD)); } -ShadowSampleParams debug_shadow_sample_get(vec3 P, LightData light) +ShadowCoordinates debug_coord_get(vec3 P, LightData light) { if (is_sun_light(light.type)) { - return shadow_directional_sample_params_get(shadow_tilemaps_tx, light, P); + vec3 lP = light_world_to_local(light, P); + return shadow_directional_coordinates(light, lP); } else { - return shadow_punctual_sample_params_get(light, P); + vec3 lP = light_world_to_local_point(light, P); + int face_id = shadow_punctual_face_index_get(lP); + lP = shadow_punctual_local_position_to_face_local(face_id, lP); + return shadow_punctual_coordinates(light, lP, face_id); } } ShadowSamplingTile debug_tile_get(vec3 P, LightData light) { - return shadow_tile_data_get(shadow_tilemaps_tx, debug_shadow_sample_get(P, light)); + ShadowCoordinates coord = debug_coord_get(P, light); + return shadow_tile_data_get(shadow_tilemaps_tx, coord); } LightData debug_light_get() @@ -114,9 +124,9 @@ bool debug_tilemaps(vec3 P, LightData light) if ((px.y < SHADOW_TILEMAP_RES) && (tilemap_index <= light_tilemap_max_get(light))) { #if 1 /* Debug values in the tilemap_tx. */ - ivec2 tilemap_texel = shadow_tile_coord_in_atlas(px, tilemap_index); + uvec2 tilemap_texel = shadow_tile_coord_in_atlas(uvec2(px), tilemap_index); ShadowSamplingTile tile = shadow_sampling_tile_unpack( - texelFetch(shadow_tilemaps_tx, tilemap_texel, 0).x); + texelFetch(shadow_tilemaps_tx, ivec2(tilemap_texel), 0).x); /* Leave 1 px border between tile-maps. */ if (!any(equal(ivec2(gl_FragCoord.xy) % (SHADOW_TILEMAP_RES * debug_tile_size_px), ivec2(0)))) { @@ -155,9 +165,9 @@ void debug_tile_state(vec3 P, LightData light) void debug_atlas_values(vec3 P, LightData light) { - ShadowSampleParams samp = debug_shadow_sample_get(P, light); - float depth = shadow_read_depth(shadow_atlas_tx, shadow_tilemaps_tx, samp); - out_color_add = vec4(float3(depth), 0.0); + ShadowCoordinates coord = debug_coord_get(P, light); + float depth = shadow_read_depth(shadow_atlas_tx, shadow_tilemaps_tx, coord); + out_color_add = vec4((depth == -1) ? vec3(1.0, 0.0, 0.0) : float3(1.0 / depth), 0.0); out_color_mul = vec4(0.5); } @@ -170,18 +180,7 @@ void debug_random_tile_color(vec3 P, LightData light) void debug_random_tilemap_color(vec3 P, LightData light) { - ShadowCoordinates coord; - if (is_sun_light(light.type)) { - vec3 lP = light_world_to_local(light, P); - coord = shadow_directional_coordinates(light, lP); - } - else { - vec3 lP = light_world_to_local(light, P - light_position_get(light)); - int face_id = shadow_punctual_face_index_get(lP); - lP = shadow_punctual_local_position_to_face_local(face_id, lP); - coord = shadow_punctual_coordinates(light, lP, face_id); - } - + ShadowCoordinates coord = debug_coord_get(P, light); out_color_add = vec4(debug_random_color(ivec2(coord.tilemap_index)), 0) * 0.5; out_color_mul = vec4(0.5); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_lib.glsl index 2ccaea75bcd..e923c342d96 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_lib.glsl @@ -14,278 +14,74 @@ # define SHADOW_ATLAS_TYPE usampler2DArray #endif -struct ShadowSampleParams { - vec3 lP; - vec3 uv; - int tilemap_index; - float z_range; -}; - -ShadowSamplingTile shadow_tile_data_get(usampler2D tilemaps_tx, ShadowSampleParams params) -{ - /* Prevent out of bound access. Assumes the input is already non negative. */ - vec2 tilemap_uv = min(params.uv.xy, vec2(0.99999)); - - ivec2 texel_coord = ivec2(tilemap_uv * float(SHADOW_MAP_MAX_RES)); - /* Using bitwise ops is way faster than integer ops. */ - const int page_shift = SHADOW_PAGE_LOD; - - ivec2 tile_coord = texel_coord >> page_shift; - return shadow_tile_load(tilemaps_tx, tile_coord, params.tilemap_index); -} - float shadow_read_depth(SHADOW_ATLAS_TYPE atlas_tx, usampler2D tilemaps_tx, - ShadowSampleParams params) + ShadowCoordinates coord) { - /* Prevent out of bound access. Assumes the input is already non negative. */ - vec2 tilemap_uv = min(params.uv.xy, vec2(0.99999)); - - ivec2 texel_coord = ivec2(tilemap_uv * float(SHADOW_MAP_MAX_RES)); - /* Using bitwise ops is way faster than integer ops. */ - const int page_shift = SHADOW_PAGE_LOD; - - ivec2 tile_coord = texel_coord >> page_shift; - ShadowSamplingTile tile = shadow_tile_load(tilemaps_tx, tile_coord, params.tilemap_index); - + ShadowSamplingTile tile = shadow_tile_load(tilemaps_tx, coord.tilemap_tile, coord.tilemap_index); if (!tile.is_valid) { return -1.0; } + /* Using bitwise ops is way faster than integer ops. */ + const uint page_shift = uint(SHADOW_PAGE_LOD); + const uint page_mask = ~(0xFFFFFFFFu << uint(SHADOW_PAGE_LOD)); - int page_mask = ~(0xFFFFFFFF << (SHADOW_PAGE_LOD + int(tile.lod))); - ivec2 texel_page = (texel_coord & page_mask) >> int(tile.lod); - ivec3 texel = ivec3((ivec2(tile.page.xy) << page_shift) | texel_page, tile.page.z); + uvec2 texel = coord.tilemap_texel; + /* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */ + texel += uvec2(tile.lod_offset << SHADOW_PAGE_LOD); + /* Scale to LOD pixels (merge LOD0 pixels together) then mask to get pixel in page. */ + uvec2 texel_page = (texel >> tile.lod) & page_mask; + texel = (uvec2(tile.page.xy) << page_shift) | texel_page; - return uintBitsToFloat(texelFetch(atlas_tx, texel, 0).r); + return uintBitsToFloat(texelFetch(atlas_tx, ivec3(ivec2(texel), tile.page.z), 0).r); } -struct ShadowEvalResult { - /* Visibility of the light. */ - float light_visibilty; - /* Average occluder distance. In world space linear distance. */ - float occluder_distance; -}; - /* ---------------------------------------------------------------------- */ /** \name Shadow Sampling Functions * \{ */ -mat4x4 shadow_projection_perspective(float side, float near_clip, float far_clip) -{ - float z_delta = far_clip - near_clip; - - mat4x4 mat = mat4x4(1.0); - mat[0][0] = near_clip / side; - mat[1][1] = near_clip / side; - mat[2][0] = 0.0; - mat[2][1] = 0.0; - mat[2][2] = -(far_clip + near_clip) / z_delta; - mat[2][3] = -1.0; - mat[3][2] = (-2.0 * near_clip * far_clip) / z_delta; - mat[3][3] = 0.0; - return mat; -} - -mat4x4 shadow_projection_perspective_inverse(float side, float near_clip, float far_clip) -{ - float z_delta = far_clip - near_clip; - float d = 2.0 * near_clip * far_clip; - - mat4x4 mat = mat4x4(1.0); - mat[0][0] = side / near_clip; - mat[1][1] = side / near_clip; - mat[2][0] = 0.0; - mat[2][1] = 0.0; - mat[2][2] = 0.0; - mat[2][3] = (near_clip - far_clip) / d; - mat[3][2] = -1.0; - mat[3][3] = (near_clip + far_clip) / d; - return mat; -} - -/** - * Convert occluder distance in shadow space to world space distance. - * Assuming the occluder is above the shading point in direction to the shadow projection center. - */ -float shadow_linear_occluder_distance(LightData light, - const bool is_directional, - vec3 lP, - float occluder) -{ - float near = orderedIntBitsToFloat(light.clip_near); - float far = orderedIntBitsToFloat(light.clip_far); - - float occluder_z = (is_directional) ? (occluder * (far - near) + near) : - ((near * far) / (occluder * (near - far) + far)); - float receiver_z = (is_directional) ? -lP.z : reduce_max(abs(lP)); - if (!is_directional) { - float lP_len = length(lP); - return lP_len - lP_len * (occluder_z / receiver_z); - } - return receiver_z - occluder_z; -} - -mat4 shadow_punctual_projection_perspective(LightData light) -{ - /* Face Local (View) Space > Clip Space. */ - float clip_far = intBitsToFloat(light.clip_far); - float clip_near = intBitsToFloat(light.clip_near); - float clip_side = light_local_data_get(light).clip_side; - return shadow_projection_perspective(clip_side, clip_near, clip_far); -} - -mat4 shadow_punctual_projection_perspective_inverse(LightData light) -{ - /* Face Local (View) Space > Clip Space. */ - float clip_far = intBitsToFloat(light.clip_far); - float clip_near = intBitsToFloat(light.clip_near); - float clip_side = light_local_data_get(light).clip_side; - return shadow_projection_perspective_inverse(clip_side, clip_near, clip_far); -} - -vec3 shadow_punctual_reconstruct_position(ShadowSampleParams params, - mat4 wininv, - LightData light, - vec3 uvw) -{ - vec3 clip_P = uvw * 2.0 - 1.0; - vec3 lP = project_point(wininv, clip_P); - int face_id = params.tilemap_index - light.tilemap_index; - lP = shadow_punctual_face_local_to_local_position(face_id, lP); - return transform_point(light.object_to_world, lP); -} - -ShadowSampleParams shadow_punctual_sample_params_get(LightData light, vec3 P) +float shadow_punctual_sample_get(SHADOW_ATLAS_TYPE atlas_tx, + usampler2D tilemaps_tx, + LightData light, + vec3 P) { vec3 lP = transform_point_inversed(light.object_to_world, P); - int face_id = shadow_punctual_face_index_get(lP); - /* Local Light Space > Face Local (View) Space. */ lP = shadow_punctual_local_position_to_face_local(face_id, lP); - mat4 winmat = shadow_punctual_projection_perspective(light); - vec3 clip_P = project_point(winmat, lP); - /* Clip Space > UV Space. */ - vec3 uv_P = saturate(clip_P * 0.5 + 0.5); + ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id); - ShadowSampleParams result; - result.lP = lP; - result.uv = uv_P; - result.tilemap_index = light.tilemap_index + face_id; - result.z_range = 1.0; - return result; + float radial_dist = shadow_read_depth(atlas_tx, tilemaps_tx, coord); + if (radial_dist == -1.0) { + return 1e10; + } + float receiver_dist = length(lP); + float occluder_dist = radial_dist; + return receiver_dist - occluder_dist; } -ShadowEvalResult shadow_punctual_sample_get(SHADOW_ATLAS_TYPE atlas_tx, - usampler2D tilemaps_tx, - LightData light, - vec3 P) +float shadow_directional_sample_get(SHADOW_ATLAS_TYPE atlas_tx, + usampler2D tilemaps_tx, + LightData light, + vec3 P) { - ShadowSampleParams params = shadow_punctual_sample_params_get(light, P); - - float depth = shadow_read_depth(atlas_tx, tilemaps_tx, params); - - ShadowEvalResult result; - result.light_visibilty = float(params.uv.z < depth); - result.occluder_distance = shadow_linear_occluder_distance(light, false, params.lP, depth); - return result; -} - -struct ShadowDirectionalSampleInfo { - float clip_near; - float clip_far; - int level_relative; - int lod_relative; - ivec2 clipmap_offset; - vec2 clipmap_origin; -}; - -ShadowDirectionalSampleInfo shadow_directional_sample_info_get(LightData light, vec3 lP) -{ - ShadowDirectionalSampleInfo info; - info.clip_near = orderedIntBitsToFloat(light.clip_near); - info.clip_far = orderedIntBitsToFloat(light.clip_far); - - int level = shadow_directional_level(light, lP - light_position_get(light)); - /* This difference needs to be less than 32 for the later shift to be valid. - * This is ensured by ShadowDirectional::clipmap_level_range(). */ - info.level_relative = level - light_sun_data_get(light).clipmap_lod_min; - info.lod_relative = (light.type == LIGHT_SUN_ORTHO) ? light_sun_data_get(light).clipmap_lod_min : - level; - - info.clipmap_offset = shadow_decompress_grid_offset( - light.type, - light_sun_data_get(light).clipmap_base_offset_neg, - light_sun_data_get(light).clipmap_base_offset_pos, - info.level_relative); - info.clipmap_origin = light_sun_data_get(light).clipmap_origin; - - return info; -} - -vec3 shadow_directional_reconstruct_position(ShadowSampleParams params, LightData light, vec3 uvw) -{ - ShadowDirectionalSampleInfo info = shadow_directional_sample_info_get(light, params.lP); - - vec2 tilemap_uv = uvw.xy; - tilemap_uv += vec2(info.clipmap_offset) / float(SHADOW_TILEMAP_RES); - vec2 clipmap_pos = (tilemap_uv - 0.5) / exp2(-float(info.lod_relative)); - - vec3 lP; - lP.xy = clipmap_pos + info.clipmap_origin; - lP.z = (params.uv.z + info.clip_near) * -1.0; - - return transform_direction_transposed(light.object_to_world, lP); -} - -ShadowSampleParams shadow_directional_sample_params_get(usampler2D tilemaps_tx, - LightData light, - vec3 P) -{ - vec3 lP = transform_direction(light.object_to_world, P); - ShadowDirectionalSampleInfo info = shadow_directional_sample_info_get(light, lP); - + vec3 lP = transform_direction_transposed(light.object_to_world, P); ShadowCoordinates coord = shadow_directional_coordinates(light, lP); - /* Assumed to be non-null. */ - float z_range = info.clip_far - info.clip_near; - float dist_to_near_plane = -lP.z - info.clip_near; - - vec2 clipmap_pos = lP.xy - info.clipmap_origin; - vec2 tilemap_uv = clipmap_pos * exp2(-float(info.lod_relative)) + 0.5; - - /* Translate tilemap UVs to its origin. */ - tilemap_uv -= vec2(info.clipmap_offset) / float(SHADOW_TILEMAP_RES); - /* Clamp to avoid out of tilemap access. */ - tilemap_uv = saturate(tilemap_uv); - - ShadowSampleParams result; - result.lP = lP; - result.uv = vec3(tilemap_uv, dist_to_near_plane); - result.tilemap_index = light.tilemap_index + info.level_relative; - result.z_range = z_range; - return result; + float depth = shadow_read_depth(atlas_tx, tilemaps_tx, coord); + if (depth == -1.0) { + return 1e10; + } + /* Use increasing distance from the light. */ + float receiver_dist = -lP.z - orderedIntBitsToFloat(light.clip_near); + float occluder_dist = depth; + return receiver_dist - occluder_dist; } -ShadowEvalResult shadow_directional_sample_get(SHADOW_ATLAS_TYPE atlas_tx, - usampler2D tilemaps_tx, - LightData light, - vec3 P) -{ - ShadowSampleParams params = shadow_directional_sample_params_get(tilemaps_tx, light, P); - - float depth = shadow_read_depth(atlas_tx, tilemaps_tx, params); - - ShadowEvalResult result; - result.light_visibilty = float(params.uv.z < depth * params.z_range); - result.occluder_distance = shadow_linear_occluder_distance(light, true, params.lP, depth); - return result; -} - -ShadowEvalResult shadow_sample(const bool is_directional, - SHADOW_ATLAS_TYPE atlas_tx, - usampler2D tilemaps_tx, - LightData light, - vec3 P) +float shadow_sample(const bool is_directional, + SHADOW_ATLAS_TYPE atlas_tx, + usampler2D tilemaps_tx, + LightData light, + vec3 P) { if (is_directional) { return shadow_directional_sample_get(atlas_tx, tilemaps_tx, light, P); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_clear_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_clear_comp.glsl index bcb7a6f586c..631ffd96f19 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_clear_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_clear_comp.glsl @@ -17,6 +17,5 @@ void main() uvec3 page_co = shadow_page_unpack(page_packed); page_co.xy = page_co.xy * SHADOW_PAGE_RES + gl_GlobalInvocationID.xy; - /* Clear to FLT_MAX instead of 1 so the far plane doesn't cast shadows onto farther objects. */ imageStoreFast(shadow_atlas_img, ivec3(page_co), uvec4(floatBitsToUint(FLT_MAX))); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_mask_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_mask_comp.glsl index 628e53ca533..21dd19b93ea 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_mask_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_page_mask_comp.glsl @@ -22,7 +22,7 @@ shared uint levels_rendered; int shadow_tile_offset_lds(ivec2 tile, int lod) { - return shadow_tile_offset(tile, 0, lod); + return shadow_tile_offset(uvec2(tile), 0, lod); } /* Deactivate threads that are not part of this LOD. Will only let pass threads which tile @@ -46,7 +46,7 @@ void main() * main memory the usage bit. */ for (int lod = 0; lod <= SHADOW_TILEMAP_LOD; lod++) { if (thread_mask(tile_co, lod)) { - int tile_offset = shadow_tile_offset(tile_co, tilemap.tiles_index, lod); + int tile_offset = shadow_tile_offset(uvec2(tile_co), tilemap.tiles_index, lod); ShadowTileDataPacked tile_data = tiles_buf[tile_offset]; if ((tile_data & SHADOW_IS_USED) == 0) { @@ -158,7 +158,7 @@ void main() if (thread_mask(tile_co, lod)) { int tile_lds = shadow_tile_offset_lds(tile_co, lod); if ((tiles_local[tile_lds] & SHADOW_TILE_AMENDED) != 0) { - int tile_offset = shadow_tile_offset(tile_co, tilemap.tiles_index, lod); + int tile_offset = shadow_tile_offset(uvec2(tile_co), tilemap.tiles_index, lod); /* Note that we only flush the visibility so that cached pages can be reused. */ if ((tiles_local[tile_lds] & SHADOW_TILE_MASKED) != 0) { tiles_buf[tile_offset] &= ~SHADOW_IS_USED; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl index 183a96620cb..50a608231ab 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_update_comp.glsl @@ -95,7 +95,7 @@ void main() for (int lod = 0; lod <= SHADOW_TILEMAP_LOD; lod++, box_min >>= 1, box_max >>= 1) { for (int y = box_min.y; y <= box_max.y; y++) { for (int x = box_min.x; x <= box_max.x; x++) { - int tile_index = shadow_tile_offset(ivec2(x, y), tilemap.tiles_index, lod); + int tile_index = shadow_tile_offset(uvec2(x, y), tilemap.tiles_index, lod); atomicOr(tiles_buf[tile_index], uint(SHADOW_DO_UPDATE)); } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl index dc5072ede29..d06391793dd 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl @@ -15,13 +15,13 @@ #pragma BLENDER_REQUIRE(eevee_light_lib.glsl) #pragma BLENDER_REQUIRE(eevee_shadow_lib.glsl) -void shadow_tag_usage_tile(LightData light, ivec2 tile_co, int lod, int tilemap_index) +void shadow_tag_usage_tile(LightData light, uvec2 tile_co, int lod, int tilemap_index) { if (tilemap_index > light_tilemap_max_get(light)) { return; } - tile_co >>= lod; + tile_co >>= uint(lod); int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod); atomicOr(tiles_buf[tile_index], uint(SHADOW_IS_USED)); } @@ -40,7 +40,7 @@ void shadow_tag_usage_tilemap_directional_at_level(uint l_idx, vec3 P, int level level, light_sun_data_get(light).clipmap_lod_min, light_sun_data_get(light).clipmap_lod_max); ShadowCoordinates coord = shadow_directional_coordinates_at_level(light, lP, level); - shadow_tag_usage_tile(light, coord.tile_coord, 0, coord.tilemap_index); + shadow_tag_usage_tile(light, coord.tilemap_tile, 0, coord.tilemap_index); } void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radius, int lod_bias) @@ -57,7 +57,7 @@ void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radi if (radius == 0.0) { int level = shadow_directional_level(light, lP - light_position_get(light)); ShadowCoordinates coord = shadow_directional_coordinates_at_level(light, lP, level); - shadow_tag_usage_tile(light, coord.tile_coord, 0, coord.tilemap_index); + shadow_tag_usage_tile(light, coord.tilemap_tile, 0, coord.tilemap_index); } else { vec3 start_lP = light_world_to_local(light, P - V * radius); @@ -71,9 +71,9 @@ void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radi ShadowCoordinates coord_max = shadow_directional_coordinates_at_level( light, lP + vec3(radius, radius, 0.0), level); - for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) { - for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) { - shadow_tag_usage_tile(light, ivec2(x, y), 0, coord_min.tilemap_index); + for (uint x = coord_min.tilemap_tile.x; x <= coord_max.tilemap_tile.x; x++) { + for (uint y = coord_min.tilemap_tile.y; y <= coord_max.tilemap_tile.y; y++) { + shadow_tag_usage_tile(light, uvec2(x, y), 0, coord_min.tilemap_index); } } } @@ -121,7 +121,7 @@ void shadow_tag_usage_tilemap_punctual(uint l_idx, vec3 P, float radius, int lod int face_id = shadow_punctual_face_index_get(lP); lP = shadow_punctual_local_position_to_face_local(face_id, lP); ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id); - shadow_tag_usage_tile(light, coord.tile_coord, lod, coord.tilemap_index); + shadow_tag_usage_tile(light, coord.tilemap_tile, lod, coord.tilemap_index); } else { uint faces = 0u; @@ -146,9 +146,9 @@ void shadow_tag_usage_tilemap_punctual(uint l_idx, vec3 P, float radius, int lod ShadowCoordinates coord_min = shadow_punctual_coordinates(light, _lP - offset, face_id); ShadowCoordinates coord_max = shadow_punctual_coordinates(light, _lP + offset, face_id); - for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) { - for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) { - shadow_tag_usage_tile(light, ivec2(x, y), lod, tilemap_index); + for (uint x = coord_min.tilemap_tile.x; x <= coord_max.tilemap_tile.x; x++) { + for (uint y = coord_min.tilemap_tile.y; y <= coord_max.tilemap_tile.y; y++) { + shadow_tag_usage_tile(light, uvec2(x, y), lod, tilemap_index); } } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_test.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_test.glsl index 34a23cf3d9f..8adc6419a3b 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_test.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_test.glsl @@ -130,26 +130,26 @@ void main() lP = vec3(1e-5, 1e-5, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 0); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); lP = vec3(-1e-5, -1e-5, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 0); - EXPECT_EQ(coords.tile_coord, ivec2((SHADOW_TILEMAP_RES / 2) - 1)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2((SHADOW_TILEMAP_RES / 2) - 1)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); lP = vec3(-0.5, -0.5, 0.0); /* Min of first LOD. */ coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 0); - EXPECT_EQ(coords.tile_coord, ivec2(0)); - EXPECT_NEAR(coords.uv, vec2(0), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(0)); + // EXPECT_NEAR(coords.uv, vec2(0), 1e-3); lP = vec3(0.5, 0.5, 0.0); /* Max of first LOD. */ coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 0); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES - 1)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES - 1)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES), 1e-3); /* Test clip-map level selection. */ @@ -161,26 +161,26 @@ void main() lP = vec3(2.00001, 2.00001, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 0); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); lP = vec3(1.50001, 1.50001, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 1); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 4)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 4), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 4)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 4), 1e-3); lP = vec3(1.00001, 1.00001, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 2); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 4)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 4), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 4)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 4), 1e-3); lP = vec3(-0.0001, -0.0001, 0.0); /* Out of bounds. */ coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 2); - EXPECT_EQ(coords.tile_coord, ivec2(0)); - EXPECT_NEAR(coords.uv, vec2(0), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(0)); + // EXPECT_NEAR(coords.uv, vec2(0), 1e-3); /* Test clip-map offset. */ @@ -188,16 +188,16 @@ void main() lP = vec3(2.0001, 0.0001, 0.0); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, -1)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, -1)); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, 0)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, 0)); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, 0)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, 0)); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, 0)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, 0)); /* Test clip-map negative offsets. */ @@ -205,16 +205,16 @@ void main() lP = vec3(-2.0001, -0.0001, 0.0); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 1)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 1)); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 0)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 0)); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 0)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 0)); coords = shadow_directional_coordinates(light, lP); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 0)); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 0)); } TEST(eevee_shadow, DirectionalCascadeCoordinates) @@ -249,34 +249,31 @@ void main() lP = vec3(1e-8, 1e-8, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 1); - EXPECT_EQ(coords.lod_relative, 0); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); lP = vec3(lod_half_size * narrowing - 1e-5, 1e-8, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 1); - EXPECT_EQ(coords.lod_relative, 0); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES - 1, SHADOW_TILEMAP_RES / 2)); - EXPECT_NEAR(coords.uv, vec2(float(SHADOW_TILEMAP_RES) - 0.5, SHADOW_TILEMAP_RES / 2), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES - 1, SHADOW_TILEMAP_RES / 2)); + // EXPECT_NEAR(coords.uv, vec2(float(SHADOW_TILEMAP_RES) - 0.5, SHADOW_TILEMAP_RES / 2), 1e-3); lP = vec3(lod_half_size + 1e-5, 1e-5, 0.0); coords = shadow_directional_coordinates(light, lP); EXPECT_EQ(coords.tilemap_index, 2); - EXPECT_EQ(coords.lod_relative, 0); - EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES - 1, SHADOW_TILEMAP_RES / 2)); - EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES / 2), 1e-3); + EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES - 1, SHADOW_TILEMAP_RES / 2)); + // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES / 2), 1e-3); // lP = vec3(-0.5, -0.5, 0.0); /* Min of first LOD. */ // coords = shadow_directional_coordinates(light, lP); // EXPECT_EQ(coords.tilemap_index, 0); - // EXPECT_EQ(coords.tile_coord, ivec2(0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(0)); // EXPECT_NEAR(coords.uv, vec2(0), 1e-3); // lP = vec3(0.5, 0.5, 0.0); /* Max of first LOD. */ // coords = shadow_directional_coordinates(light, lP); // EXPECT_EQ(coords.tilemap_index, 0); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES - 1)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES - 1)); // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES), 1e-3); /* Test clip-map level selection. */ @@ -289,25 +286,25 @@ void main() // lP = vec3(2.00001, 2.00001, 0.0); // coords = shadow_directional_coordinates(light, lP); // EXPECT_EQ(coords.tilemap_index, 0); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2)); // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 2), 1e-3); // lP = vec3(1.50001, 1.50001, 0.0); // coords = shadow_directional_coordinates(light, lP); // EXPECT_EQ(coords.tilemap_index, 1); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 4)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 4)); // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 4), 1e-3); // lP = vec3(1.00001, 1.00001, 0.0); // coords = shadow_directional_coordinates(light, lP); // EXPECT_EQ(coords.tilemap_index, 2); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 4)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 4)); // EXPECT_NEAR(coords.uv, vec2(SHADOW_TILEMAP_RES / 4), 1e-3); // lP = vec3(-0.0001, -0.0001, 0.0); /* Out of bounds. */ // coords = shadow_directional_coordinates(light, lP); // EXPECT_EQ(coords.tilemap_index, 2); - // EXPECT_EQ(coords.tile_coord, ivec2(0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(0)); // EXPECT_NEAR(coords.uv, vec2(0), 1e-3); /* Test clip-map offset. */ @@ -316,16 +313,16 @@ void main() // lP = vec3(2.0001, 0.0001, 0.0); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, -1)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, -1)); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, 0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, 0)); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, 0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, 0)); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2) + ivec2(1, 0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2) + uvec2(1, 0)); /* Test clip-map negative offsets. */ @@ -333,15 +330,15 @@ void main() // lP = vec3(-2.0001, -0.0001, 0.0); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 1)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 1)); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 0)); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 0)); // coords = shadow_directional_coordinates(light, lP); - // EXPECT_EQ(coords.tile_coord, ivec2(SHADOW_TILEMAP_RES / 2 - 1) + ivec2(-1, 0)); + // EXPECT_EQ(coords.tilemap_tile, uvec2(SHADOW_TILEMAP_RES / 2 - 1) + uvec2(-1, 0)); } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_amend_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_amend_comp.glsl index 3409fbac163..93e0a0b4779 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_amend_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_amend_comp.glsl @@ -44,9 +44,9 @@ void main() /* Iterate in reverse. */ for (int lod = lod_max; lod >= 0; lod--) { int tilemap_index = light.tilemap_index + lod; - ivec2 atlas_texel = shadow_tile_coord_in_atlas(tile_co, tilemap_index); + uvec2 atlas_texel = shadow_tile_coord_in_atlas(uvec2(tile_co), tilemap_index); - ShadowSamplingTilePacked tile_packed = imageLoad(tilemaps_img, atlas_texel).x; + ShadowSamplingTilePacked tile_packed = imageLoad(tilemaps_img, ivec2(atlas_texel)).x; ShadowSamplingTile tile = shadow_sampling_tile_unpack(tile_packed); if (lod != lod_max && !tile.is_valid) { @@ -81,7 +81,7 @@ void main() tile_prev_packed = shadow_sampling_tile_pack(tile_prev); /* Replace the missing page with the one from the lower LOD. */ - imageStore(tilemaps_img, atlas_texel, uvec4(tile_prev_packed)); + imageStore(tilemaps_img, ivec2(atlas_texel), uvec4(tile_prev_packed)); /* Push this amended tile to the local tiles. */ tile_packed = tile_prev_packed; tile.is_valid = true; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_finalize_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_finalize_comp.glsl index 73fac997313..0fec3b91454 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_finalize_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_finalize_comp.glsl @@ -51,7 +51,7 @@ void main() int tilemap_index = int(gl_GlobalInvocationID.z); ivec2 tile_co = ivec2(gl_GlobalInvocationID.xy); - ivec2 atlas_texel = shadow_tile_coord_in_atlas(tile_co, tilemap_index); + uvec2 atlas_texel = shadow_tile_coord_in_atlas(uvec2(tile_co), tilemap_index); ShadowTileMapData tilemap_data = tilemaps_buf[tilemap_index]; bool is_cubemap = (tilemap_data.projection_type == SHADOW_PROJECTION_CUBEFACE); @@ -64,7 +64,7 @@ void main() * Add one render view per LOD that has tiles to be rendered. */ for (int lod = lod_max; lod >= 0; lod--) { ivec2 tile_co_lod = tile_co >> lod; - int tile_index = shadow_tile_offset(tile_co_lod, tilemap_data.tiles_index, lod); + int tile_index = shadow_tile_offset(uvec2(tile_co_lod), tilemap_data.tiles_index, lod); ShadowTileData tile = shadow_tile_unpack(tiles_buf[tile_index]); @@ -103,26 +103,6 @@ void main() view_index = atomicAdd(statistics_buf.view_needed_count, 1); if (view_index < SHADOW_VIEW_MAX) { /* Setup the view. */ - - render_view_buf[view_index].viewport_index = viewport_index; - /* Scale by actual radius size (overestimate since scaled by bounding circle). */ - float filter_radius = tilemap_data.filter_radius * M_SQRT2; - /* We need a minimum slope bias even if filter is 0 to avoid some invalid shadowing. */ - render_view_buf[view_index].filter_radius = max(1.0, filter_radius); - /* Clipping setup. */ - if (tilemap_data.is_area_side) { - /* Negative for tagging this case. See shadow_clip_vector_get for explanation. */ - render_view_buf[view_index].clip_distance_inv = -M_SQRT1_3 / tilemap_data.area_shift; - } - else if (is_point_light(tilemap_data.light_type)) { - /* Clip as a sphere around the clip_near cube. */ - render_view_buf[view_index].clip_distance_inv = M_SQRT1_3 / tilemap_data.clip_near; - } - else { - /* Disable local clipping. */ - render_view_buf[view_index].clip_distance_inv = 0.0; - } - view_infos_buf[view_index].viewmat = tilemap_data.viewmat; view_infos_buf[view_index].viewinv = inverse(tilemap_data.viewmat); @@ -153,6 +133,23 @@ void main() view_infos_buf[view_index].winmat = winmat; view_infos_buf[view_index].wininv = inverse(winmat); + + render_view_buf[view_index].viewport_index = viewport_index; + render_view_buf[view_index].is_directionnal = !is_cubemap; + render_view_buf[view_index].clip_near = clip_near; + /* Clipping setup. */ + if (tilemap_data.is_area_side) { + /* Negative for tagging this case. See shadow_clip_vector_get for explanation. */ + render_view_buf[view_index].clip_distance_inv = -M_SQRT1_3 / tilemap_data.area_shift; + } + else if (is_point_light(tilemap_data.light_type)) { + /* Clip as a sphere around the clip_near cube. */ + render_view_buf[view_index].clip_distance_inv = M_SQRT1_3 / tilemap_data.clip_near; + } + else { + /* Disable local clipping. */ + render_view_buf[view_index].clip_distance_inv = 0.0; + } } } } @@ -205,7 +202,7 @@ void main() ShadowTileData tile_data = shadow_tile_unpack(tile_packed); ShadowSamplingTile tile_sampling = shadow_sampling_tile_create(tile_data, valid_lod); ShadowSamplingTilePacked tile_sampling_packed = shadow_sampling_tile_pack(tile_sampling); - imageStore(tilemaps_img, atlas_texel, uvec4(tile_sampling_packed)); + imageStore(tilemaps_img, ivec2(atlas_texel), uvec4(tile_sampling_packed)); if (all(equal(gl_GlobalInvocationID, uvec3(0)))) { /* Clamp it as it can underflow if there is too much tile present on screen. */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl index 5d01144fafe..648c5c27156 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_init_comp.glsl @@ -87,7 +87,7 @@ void main() for (int lod = 0; lod <= lod_max; lod++, lod_size >>= 1u) { bool thread_active = all(lessThan(tile_co, ivec2(lod_size))); ShadowTileDataPacked tile = 0; - int tile_load = shadow_tile_offset(tile_wrapped, tilemap.tiles_index, lod); + int tile_load = shadow_tile_offset(uvec2(tile_wrapped), tilemap.tiles_index, lod); if (thread_active) { tile = init_tile_data(tiles_buf[tile_load], do_update); } @@ -96,7 +96,7 @@ void main() barrier(); if (thread_active) { - int tile_store = shadow_tile_offset(tile_co, tilemap.tiles_index, lod); + int tile_store = shadow_tile_offset(uvec2(tile_co), tilemap.tiles_index, lod); if ((tile_load != tile_store) && flag_test(tile, SHADOW_IS_CACHED)) { /* Inlining of shadow_page_cache_update_tile_ref to avoid buffer dependencies. */ pages_cached_buf[shadow_tile_unpack(tile).cache_index].y = tile_store; diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl index 7795897c81b..0197ffd74e6 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl @@ -15,19 +15,19 @@ int shadow_tile_index(ivec2 tile) return tile.x + tile.y * SHADOW_TILEMAP_RES; } -ivec2 shadow_tile_coord(int tile_index) +uvec2 shadow_tile_coord(int tile_index) { - return ivec2(tile_index % SHADOW_TILEMAP_RES, tile_index / SHADOW_TILEMAP_RES); + return uvec2(tile_index % SHADOW_TILEMAP_RES, tile_index / SHADOW_TILEMAP_RES); } /* Return bottom left pixel position of the tile-map inside the tile-map atlas. */ -ivec2 shadow_tilemap_start(int tilemap_index) +uvec2 shadow_tilemap_start(int tilemap_index) { return SHADOW_TILEMAP_RES * - ivec2(tilemap_index % SHADOW_TILEMAP_PER_ROW, tilemap_index / SHADOW_TILEMAP_PER_ROW); + uvec2(tilemap_index % SHADOW_TILEMAP_PER_ROW, tilemap_index / SHADOW_TILEMAP_PER_ROW); } -ivec2 shadow_tile_coord_in_atlas(ivec2 tile, int tilemap_index) +uvec2 shadow_tile_coord_in_atlas(uvec2 tile, int tilemap_index) { return shadow_tilemap_start(tilemap_index) + tile; } @@ -36,7 +36,7 @@ ivec2 shadow_tile_coord_in_atlas(ivec2 tile, int tilemap_index) * Return tile index inside `tiles_buf` for a given tile coordinate inside a specific LOD. * `tiles_index` should be `ShadowTileMapData.tiles_index`. */ -int shadow_tile_offset(ivec2 tile, int tiles_index, int lod) +int shadow_tile_offset(uvec2 tile, int tiles_index, int lod) { #if SHADOW_TILEMAP_LOD > 5 # error This needs to be adjusted @@ -54,34 +54,35 @@ int shadow_tile_offset(ivec2 tile, int tiles_index, int lod) const int lod4_size = lod4_width * lod4_width; const int lod5_size = lod5_width * lod5_width; + /* TODO(fclem): Convert everything to uint. */ int offset = tiles_index; switch (lod) { case 5: offset += lod0_size + lod1_size + lod2_size + lod3_size + lod4_size; - offset += tile.y * lod5_width; + offset += int(tile.y) * lod5_width; break; case 4: offset += lod0_size + lod1_size + lod2_size + lod3_size; - offset += tile.y * lod4_width; + offset += int(tile.y) * lod4_width; break; case 3: offset += lod0_size + lod1_size + lod2_size; - offset += tile.y * lod3_width; + offset += int(tile.y) * lod3_width; break; case 2: offset += lod0_size + lod1_size; - offset += tile.y * lod2_width; + offset += int(tile.y) * lod2_width; break; case 1: offset += lod0_size; - offset += tile.y * lod1_width; + offset += int(tile.y) * lod1_width; break; case 0: default: - offset += tile.y * lod0_width; + offset += int(tile.y) * lod0_width; break; } - offset += tile.x; + offset += int(tile.x); return offset; } @@ -92,13 +93,13 @@ int shadow_tile_offset(ivec2 tile, int tiles_index, int lod) * \{ */ /** \note Will clamp if out of bounds. */ -ShadowSamplingTile shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilemap_index) +ShadowSamplingTile shadow_tile_load(usampler2D tilemaps_tx, uvec2 tile_co, int tilemap_index) { /* NOTE(@fclem): This clamp can hide some small imprecision at clip-map transition. * Can be disabled to check if the clip-map is well centered. */ - tile_co = clamp(tile_co, ivec2(0), ivec2(SHADOW_TILEMAP_RES - 1)); - ivec2 texel = shadow_tile_coord_in_atlas(tile_co, tilemap_index); - uint tile_data = texelFetch(tilemaps_tx, texel, 0).x; + tile_co = clamp(tile_co, uvec2(0), uvec2(SHADOW_TILEMAP_RES - 1)); + uvec2 texel = shadow_tile_coord_in_atlas(tile_co, tilemap_index); + uint tile_data = texelFetch(tilemaps_tx, ivec2(texel), 0).x; return shadow_sampling_tile_unpack(tile_data); } @@ -202,14 +203,22 @@ int shadow_punctual_level(LightData light, struct ShadowCoordinates { /* Index of the tile-map to containing the tile. */ int tilemap_index; - /* LOD of the tile to load relative to the min level. Always positive. */ - int lod_relative; - /* Tile coordinate inside the tile-map. */ - ivec2 tile_coord; - /* UV coordinates in [0..SHADOW_TILEMAP_RES) range. */ - vec2 uv; + /* Texel coordinates in [0..SHADOW_MAP_MAX_RES) range. */ + uvec2 tilemap_texel; + /* Tile coordinate in [0..SHADOW_TILEMAP_RES) range. */ + uvec2 tilemap_tile; }; +/* Assumes tilemap_uv is already saturated. */ +ShadowCoordinates shadow_coordinate_from_uvs(int tilemap_index, vec2 tilemap_uv) +{ + ShadowCoordinates ret; + ret.tilemap_index = tilemap_index; + ret.tilemap_texel = uvec2(tilemap_uv * (float(SHADOW_MAP_MAX_RES) - 1e-2)); + ret.tilemap_tile = ret.tilemap_texel >> uint(SHADOW_PAGE_LOD); + return ret; +} + /* Retain sign bit and avoid costly int division. */ ivec2 shadow_decompress_grid_offset(eLightType light_type, ivec2 offset_neg, @@ -229,30 +238,24 @@ ivec2 shadow_decompress_grid_offset(eLightType light_type, */ ShadowCoordinates shadow_directional_coordinates_at_level(LightData light, vec3 lP, int level) { - ShadowCoordinates ret; /* This difference needs to be less than 32 for the later shift to be valid. * This is ensured by `ShadowDirectional::clipmap_level_range()`. */ int level_relative = level - light_sun_data_get(light).clipmap_lod_min; - - ret.tilemap_index = light.tilemap_index + level_relative; - - ret.lod_relative = (light.type == LIGHT_SUN_ORTHO) ? light_sun_data_get(light).clipmap_lod_min : + int lod_relative = (light.type == LIGHT_SUN_ORTHO) ? light_sun_data_get(light).clipmap_lod_min : level; - /* Compute offset in tile. */ ivec2 clipmap_offset = shadow_decompress_grid_offset( light.type, light_sun_data_get(light).clipmap_base_offset_neg, light_sun_data_get(light).clipmap_base_offset_pos, level_relative); + /* UV in [0..1] range over the tilemap. */ + vec2 tilemap_uv = lP.xy - light_sun_data_get(light).clipmap_origin; + tilemap_uv *= exp2(float(-lod_relative)); + tilemap_uv -= vec2(clipmap_offset) * (1.0 / float(SHADOW_TILEMAP_RES)); + tilemap_uv = saturate(tilemap_uv + 0.5); - ret.uv = lP.xy - light_sun_data_get(light).clipmap_origin; - ret.uv /= exp2(float(ret.lod_relative)); - ret.uv = ret.uv * float(SHADOW_TILEMAP_RES) + float(SHADOW_TILEMAP_RES / 2); - ret.uv -= vec2(clipmap_offset); - /* Clamp to avoid out of tile-map access. */ - ret.tile_coord = clamp(ivec2(ret.uv), ivec2(0.0), ivec2(SHADOW_TILEMAP_RES - 1)); - return ret; + return shadow_coordinate_from_uvs(light.tilemap_index + level_relative, tilemap_uv); } /** @@ -325,16 +328,12 @@ ShadowCoordinates shadow_punctual_coordinates(LightData light, vec3 lP, int face { float clip_near = intBitsToFloat(light.clip_near); float clip_side = light_local_data_get(light).clip_side; - - ShadowCoordinates ret; - ret.tilemap_index = light.tilemap_index + face_id; /* UVs in [-1..+1] range. */ - ret.uv = (lP.xy * clip_near) / abs(lP.z * clip_side); - /* UVs in [0..SHADOW_TILEMAP_RES] range. */ - ret.uv = ret.uv * float(SHADOW_TILEMAP_RES / 2) + float(SHADOW_TILEMAP_RES / 2); - /* Clamp to avoid out of tile-map access. */ - ret.tile_coord = clamp(ivec2(ret.uv), ivec2(0), ivec2(SHADOW_TILEMAP_RES - 1)); - return ret; + vec2 tilemap_uv = (lP.xy * clip_near) / abs(lP.z * clip_side); + /* UVs in [0..1] range. */ + tilemap_uv = saturate(tilemap_uv * 0.5 + 0.5); + + return shadow_coordinate_from_uvs(light.tilemap_index + face_id, tilemap_uv); } /** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl index acfa914ca9f..e3132ea8bfb 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tracing_lib.glsl @@ -15,47 +15,17 @@ #pragma BLENDER_REQUIRE(draw_view_lib.glsl) #pragma BLENDER_REQUIRE(draw_math_geom_lib.glsl) -float shadow_read_depth_at_tilemap_uv(int tilemap_index, vec2 tilemap_uv) -{ - /* Prevent out of bound access. Assumes the input is already non negative. */ - tilemap_uv = min(tilemap_uv, vec2(0.99999)); - - ivec2 texel_coord = ivec2(tilemap_uv * float(SHADOW_MAP_MAX_RES)); - /* Using bitwise ops is way faster than integer ops. */ - const int page_shift = SHADOW_PAGE_LOD; - const int page_mask = ~(0xFFFFFFFF << SHADOW_PAGE_LOD); - - ivec2 tile_coord = texel_coord >> page_shift; - ShadowSamplingTile tile = shadow_tile_load(shadow_tilemaps_tx, tile_coord, tilemap_index); - - if (!tile.is_valid) { - return -1.0; - } - /* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */ - /* TODO convert everything to uint to avoid signed int operations. */ - texel_coord += ivec2(tile.lod_offset << SHADOW_PAGE_LOD); - /* Scale to LOD pixels (merge LOD0 pixels together) then mask to get pixel in page. */ - ivec2 texel_page = (texel_coord >> int(tile.lod)) & page_mask; - ivec3 texel = ivec3((ivec2(tile.page.xy) << page_shift) | texel_page, tile.page.z); - - return uintBitsToFloat(texelFetch(shadow_atlas_tx, texel, 0).r); -} - /* ---------------------------------------------------------------------- */ /** \name Shadow Map Tracing loop * \{ */ -#define SHADOW_TRACING_INVALID_HISTORY -999.0 +#define SHADOW_TRACING_INVALID_HISTORY FLT_MAX struct ShadowMapTracingState { - /* Receiver Z value at previous valid depth sample. */ - float receiver_depth_history; - /* Occluder Z value at previous valid depth sample. */ - float occluder_depth_history; - /* Ray time at previous valid depth sample. */ - float ray_time_history; - /* Z slope (delta/time) between previous valid sample (N-1) and the one before that (N-2). */ - float occluder_depth_slope; + /* Occluder ray coordinate at previous valid depth sample. */ + vec2 occluder_history; + /* Time slope between previous valid sample (N-1) and the one before that (N-2). */ + float occluder_slope; /* Multiplier and bias to the ray step quickly compute ray time. */ float ray_step_mul; float ray_step_bias; @@ -67,10 +37,8 @@ struct ShadowMapTracingState { ShadowMapTracingState shadow_map_trace_init(int sample_count, float step_offset) { ShadowMapTracingState state; - state.receiver_depth_history = -1.0; - state.occluder_depth_history = SHADOW_TRACING_INVALID_HISTORY; - state.ray_time_history = -1.0; - state.occluder_depth_slope = 0.0; + state.occluder_history = vec2(SHADOW_TRACING_INVALID_HISTORY); + state.occluder_slope = SHADOW_TRACING_INVALID_HISTORY; /* We trace the ray in reverse. From 1.0 (light) to 0.0 (shading point). */ state.ray_step_mul = -1.0 / float(sample_count); state.ray_step_bias = 1.0 + step_offset * state.ray_step_mul; @@ -79,8 +47,12 @@ ShadowMapTracingState shadow_map_trace_init(int sample_count, float step_offset) } struct ShadowTracingSample { - float receiver_depth; - float occluder_depth; + /** + * Occluder position in ray space. + * `x` component is just the normalized distance from the ray start to the ray end. + * `y` component is signed distance to the ray, positive if on the light side of the ray. + */ + vec2 occluder; bool skip_sample; }; @@ -91,7 +63,7 @@ struct ShadowTracingSample { * Most of the code is wrapped into functions to avoid to debug issues inside macro code. */ #define SHADOW_MAP_TRACE_FN(ShadowRayType) \ - ShadowMapTraceResult shadow_map_trace(ShadowRayType ray, int sample_count, float step_offset) \ + bool shadow_map_trace(ShadowRayType ray, int sample_count, float step_offset) \ { \ ShadowMapTracingState state = shadow_map_trace_init(sample_count, step_offset); \ for (int i = 0; (i <= sample_count) && (i <= SHADOW_MAX_STEP) && (state.hit == false); i++) { \ @@ -102,7 +74,7 @@ struct ShadowTracingSample { \ shadow_map_trace_hit_check(state, samp); \ } \ - return shadow_map_trace_finish(state); \ + return state.hit; \ } /** @@ -119,68 +91,38 @@ void shadow_map_trace_hit_check(inout ShadowMapTracingState state, ShadowTracing return; } /* For the first sample, regular depth compare since we do not have history values. */ - if (state.occluder_depth_history == SHADOW_TRACING_INVALID_HISTORY) { - if (samp.occluder_depth < samp.receiver_depth) { + if (state.occluder_history.x == SHADOW_TRACING_INVALID_HISTORY) { + if (samp.occluder.x > state.ray_time) { state.hit = true; return; } - state.occluder_depth_history = samp.occluder_depth; - state.receiver_depth_history = samp.receiver_depth; - state.ray_time_history = state.ray_time; + state.occluder_history = samp.occluder; return; } - /* Delta between previous valid sample. */ - float ray_depth_delta = samp.receiver_depth - state.receiver_depth_history; - /* Delta between previous valid sample not occluding the ray. */ - float time_delta = state.ray_time - state.ray_time_history; - /* Arbitrary increase the threshold to avoid missing occluders because of precision issues. - * Increasing the threshold inflates the occluders. */ - float compare_threshold = abs(ray_depth_delta) * 1.05; - /* Find out if the ray step is behind an occluder. - * To be consider behind (and ignore the occluder), the occluder must not be cross the ray. - * Use the full delta ray depth as threshold to make sure to not miss any occluder. */ - bool is_behind = samp.occluder_depth < (samp.receiver_depth - compare_threshold); - if (is_behind) { - /* Use last known valid occluder Z value and extrapolate to the sample position. */ - samp.occluder_depth = state.occluder_depth_history + state.occluder_depth_slope * time_delta; - /* Intersection test will be against the extrapolated last known occluder. */ + bool is_behind_occluder = samp.occluder.y > 0.0; + if (is_behind_occluder && (state.occluder_slope != SHADOW_TRACING_INVALID_HISTORY)) { + /* Extrapolate last known valid occluder and check if it crossed the ray. + * Note that we only want to check if the extrapolated occluder is above the ray at a certain + * time value, we don't actually care about the correct value. So we replace the complex + * problem of trying to get the extrapolation in shadow map space into the extrapolation at + * ray_time in ray space. This is equivalent as both functions have the same roots. */ + float delta_time = state.ray_time - state.occluder_history.x; + float extrapolated_occluder_y = abs(state.occluder_history.y) + + state.occluder_slope * delta_time; + state.hit = extrapolated_occluder_y < 0.0; } else { /* Compute current occluder slope and record history for when the ray goes behind a surface. */ - state.occluder_depth_slope = (samp.occluder_depth - state.occluder_depth_history) / time_delta; - state.occluder_depth_slope = clamp(state.occluder_depth_slope, -100.0, 100.0); - state.occluder_depth_history = samp.occluder_depth; - state.ray_time_history = state.ray_time; - /* Intersection test will be against the current sample's occluder. */ + vec2 delta = samp.occluder - state.occluder_history; + /* Clamping the slope to a mininim avoid light leaking. */ + /* TODO(fclem): Expose as parameter? */ + const float min_slope = tan(M_PI * 0.25); + state.occluder_slope = max(min_slope, abs(delta.y / delta.x)); + state.occluder_history = samp.occluder; + /* Intersection test. Intersect if above the ray time. */ + state.hit = samp.occluder.x > state.ray_time; } - - if (samp.occluder_depth < samp.receiver_depth) { - state.occluder_depth_history = samp.occluder_depth; - state.hit = true; - return; - } - /* No intersection. */ - state.receiver_depth_history = samp.receiver_depth; -} - -struct ShadowMapTraceResult { - bool has_hit; - float occluder_depth; -}; - -ShadowMapTraceResult shadow_map_trace_finish(ShadowMapTracingState state) -{ - ShadowMapTraceResult result; - if (state.hit) { - result.occluder_depth = state.occluder_depth_history; - result.has_hit = true; - } - else { - result.occluder_depth = 0.0; - result.has_hit = false; - } - return result; } /** \} */ @@ -202,12 +144,15 @@ vec3 shadow_ray_above_horizon_ensure(vec3 L, vec3 N) * \{ */ struct ShadowRayDirectional { - /* Ray in local translated coordinate, with depth in [0..1] range in W component. */ - vec4 origin; - vec4 direction; + /* Ray in light rotated space. But not translated. */ + vec3 origin; + vec3 direction; + /* Convert form local light position to ray oriented position where X axis is the ray. */ + vec3 local_ray_up; LightData light; }; +/* `lP` is supposed to be in light rotated space. But not translated. */ ShadowRayDirectional shadow_ray_generate_directional(LightData light, vec2 random_2d, vec3 lP, @@ -216,28 +161,25 @@ ShadowRayDirectional shadow_ray_generate_directional(LightData light, float clip_near = orderedIntBitsToFloat(light.clip_near); float clip_far = orderedIntBitsToFloat(light.clip_far); /* Assumed to be non-null. */ - float z_range = clip_far - clip_near; float dist_to_near_plane = -lP.z - clip_near; - /* `lP` is supposed to be in light rotated space. But not translated. */ - vec4 origin = vec4(lP, dist_to_near_plane / z_range); - - vec3 disk_direction = sample_uniform_cone(sample_cylinder(random_2d), - light_sun_data_get(light).shadow_angle); - - disk_direction = shadow_ray_above_horizon_ensure(disk_direction, lNg); - /* Light shape is 1 unit away from the shading point. */ - vec4 direction = vec4(disk_direction, -1.0 / z_range); + vec3 direction = sample_uniform_cone(sample_cylinder(random_2d), + light_sun_data_get(light).shadow_angle); + + direction = shadow_ray_above_horizon_ensure(direction, lNg); /* It only make sense to trace where there can be occluder. Clamp by distance to near plane. */ direction *= min(light_sun_data_get(light).shadow_trace_distance, - dist_to_near_plane / disk_direction.z); + dist_to_near_plane / direction.z); ShadowRayDirectional ray; - ray.origin = origin; + ray.origin = lP; ray.direction = direction; ray.light = light; + /* TODO(fclem): We can simplify this using the ray direction construction. */ + ray.local_ray_up = safe_normalize( + cross(cross(vec3(0.0, 0.0, -1.0), ray.direction), ray.direction)); return ray; } @@ -245,37 +187,21 @@ ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state, inout ShadowRayDirectional ray) { /* Ray position is ray local position with origin at light origin. */ - vec4 ray_pos = ray.origin + ray.direction * state.ray_time; + vec3 ray_pos = ray.origin + ray.direction * state.ray_time; - int level = shadow_directional_level(ray.light, ray_pos.xyz - light_position_get(ray.light)); - /* This difference needs to be less than 32 for the later shift to be valid. - * This is ensured by ShadowDirectional::clipmap_level_range(). */ - int level_relative = level - light_sun_data_get(ray.light).clipmap_lod_min; + ShadowCoordinates coord = shadow_directional_coordinates(ray.light, ray_pos); - int lod_relative = (ray.light.type == LIGHT_SUN_ORTHO) ? - light_sun_data_get(ray.light).clipmap_lod_min : - level; - - vec2 clipmap_origin = light_sun_data_get(ray.light).clipmap_origin; - vec2 clipmap_pos = ray_pos.xy - clipmap_origin; - vec2 tilemap_uv = clipmap_pos * exp2(-float(lod_relative)) + 0.5; - - /* Compute offset in tile. */ - ivec2 clipmap_offset = shadow_decompress_grid_offset( - ray.light.type, - light_sun_data_get(ray.light).clipmap_base_offset_neg, - light_sun_data_get(ray.light).clipmap_base_offset_pos, - level_relative); - /* Translate tilemap UVs to its origin. */ - tilemap_uv -= vec2(clipmap_offset) / float(SHADOW_TILEMAP_RES); - /* Clamp to avoid out of tilemap access. */ - tilemap_uv = saturate(tilemap_uv); + float depth = shadow_read_depth(shadow_atlas_tx, shadow_tilemaps_tx, coord); + /* Distance from near plane. */ + float clip_near = orderedIntBitsToFloat(ray.light.clip_near); + vec3 occluder_pos = vec3(ray_pos.xy, -depth - clip_near); + /* Transform to ray local space. */ + vec3 ray_local_occluder = occluder_pos - ray.origin; ShadowTracingSample samp; - samp.receiver_depth = ray_pos.w; - samp.occluder_depth = shadow_read_depth_at_tilemap_uv(ray.light.tilemap_index + level_relative, - tilemap_uv); - samp.skip_sample = (samp.occluder_depth == -1.0); + samp.occluder.x = dot(ray_local_occluder, ray.direction) / length_squared(ray.direction); + samp.occluder.y = dot(ray_local_occluder, ray.local_ray_up); + samp.skip_sample = (depth == -1.0); return samp; } @@ -288,11 +214,14 @@ SHADOW_MAP_TRACE_FN(ShadowRayDirectional) * \{ */ struct ShadowRayPunctual { - /* Ray in tile-map normalized coordinates [0..1]. */ + /* Light space shadow ray origin and direction. */ vec3 origin; vec3 direction; + /* Convert form local light position to ray oriented position where X axis is the ray. */ + vec3 local_ray_up; /* Tile-map to sample. */ - int tilemap_index; + int light_tilemap_index; + LightData light; }; /* Return ray in UV clip space [0..1]. */ @@ -354,44 +283,34 @@ ShadowRayPunctual shadow_ray_generate_punctual(LightData light, vec2 random_2d, direction *= saturate((dist - clip_distance) / dist); } - /* Apply shadow origin shift. */ - vec3 local_ray_start = lP + projection_origin; - vec3 local_ray_end = local_ray_start + direction; - - /* Use an offset in the ray direction to jitter which face is traced. - * This helps hiding some harsh discontinuity. */ - int face_id = shadow_punctual_face_index_get(local_ray_start + direction * 0.5); - /* Local Light Space > Face Local (View) Space. */ - vec3 view_ray_start = shadow_punctual_local_position_to_face_local(face_id, local_ray_start); - vec3 view_ray_end = shadow_punctual_local_position_to_face_local(face_id, local_ray_end); - - /* Face Local (View) Space > Clip Space. */ - /* TODO: Could be simplified since frustum is completely symmetrical. */ - mat4 winmat = projection_perspective( - -clip_side, clip_side, -clip_side, clip_side, clip_near, clip_far); - vec3 clip_ray_start = project_point(winmat, view_ray_start); - vec3 clip_ray_end = project_point(winmat, view_ray_end); - /* Clip Space > UV Space. */ - vec3 uv_ray_start = clip_ray_start * 0.5 + 0.5; - vec3 uv_ray_end = clip_ray_end * 0.5 + 0.5; /* Compute the ray again. */ ShadowRayPunctual ray; - ray.origin = uv_ray_start; - ray.direction = uv_ray_end - uv_ray_start; - ray.tilemap_index = light.tilemap_index + face_id; + ray.origin = lP; + ray.direction = direction; + ray.light_tilemap_index = light.tilemap_index; + ray.local_ray_up = safe_normalize(cross(cross(ray.origin, ray.direction), ray.direction)); + ray.light = light; return ray; } ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state, inout ShadowRayPunctual ray) { - vec3 ray_pos = ray.origin + ray.direction * state.ray_time; - vec2 tilemap_uv = saturate(ray_pos.xy); + vec3 receiver_pos = ray.origin + ray.direction * state.ray_time; + int face_id = shadow_punctual_face_index_get(receiver_pos); + vec3 face_pos = shadow_punctual_local_position_to_face_local(face_id, receiver_pos); + ShadowCoordinates coord = shadow_punctual_coordinates(ray.light, face_pos, face_id); + + float radial_occluder_depth = shadow_read_depth(shadow_atlas_tx, shadow_tilemaps_tx, coord); + vec3 occluder_pos = receiver_pos * (radial_occluder_depth / length(receiver_pos)); + + /* Transform to ray local space. */ + vec3 ray_local_occluder = occluder_pos - ray.origin; ShadowTracingSample samp; - samp.receiver_depth = ray_pos.z; - samp.occluder_depth = shadow_read_depth_at_tilemap_uv(ray.tilemap_index, tilemap_uv); - samp.skip_sample = (samp.occluder_depth == -1.0); + samp.occluder.x = dot(ray_local_occluder, ray.direction) / length_squared(ray.direction); + samp.occluder.y = dot(ray_local_occluder, ray.local_ray_up); + samp.skip_sample = (radial_occluder_depth == -1.0); return samp; } @@ -487,17 +406,18 @@ float shadow_normal_offset(vec3 Ng, vec3 L) /** * Evaluate shadowing by casting rays toward the light direction. + * Returns light visibility. */ -ShadowEvalResult shadow_eval(LightData light, - const bool is_directional, - const bool is_transmission, - bool is_translucent_with_thickness, - float thickness, /* Only used if is_transmission is true. */ - vec3 P, - vec3 Ng, - vec3 L, - int ray_count, - int ray_step_count) +float shadow_eval(LightData light, + const bool is_directional, + const bool is_transmission, + bool is_translucent_with_thickness, + float thickness, /* Only used if is_transmission is true. */ + vec3 P, + vec3 Ng, + vec3 L, + int ray_count, + int ray_step_count) { #if defined(EEVEE_SAMPLING_DATA) && defined(EEVEE_UTILITY_TX) # ifdef GPU_FRAGMENT_SHADER @@ -506,7 +426,7 @@ ShadowEvalResult shadow_eval(LightData light, vec2 pixel = vec2(gl_GlobalInvocationID.xy); # endif vec3 blue_noise_3d = utility_tx_fetch(utility_tx, pixel, UTIL_BLUE_NOISE_LAYER).rgb; - vec3 random_shadow_3d = blue_noise_3d + sampling_rng_3D_get(SAMPLING_SHADOW_U); + vec3 random_shadow_3d = fract(blue_noise_3d + sampling_rng_3D_get(SAMPLING_SHADOW_U)); vec2 random_pcf_2d = fract(blue_noise_3d.xy + sampling_rng_2D_get(SAMPLING_SHADOW_X)); #else /* Case of surfel light eval. */ @@ -546,24 +466,21 @@ ShadowEvalResult shadow_eval(LightData light, for (int ray_index = 0; ray_index < ray_count && ray_index < SHADOW_MAX_RAY; ray_index++) { vec2 random_ray_2d = fract(hammersley_2d(ray_index, ray_count) + random_shadow_3d.xy); - ShadowMapTraceResult trace; + bool has_hit; if (is_directional) { ShadowRayDirectional clip_ray = shadow_ray_generate_directional( light, random_ray_2d, lP, lNg); - trace = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z); + has_hit = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z); } else { ShadowRayPunctual clip_ray = shadow_ray_generate_punctual(light, random_ray_2d, lP, lNg); - trace = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z); + has_hit = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z); } - surface_hit += float(trace.has_hit); + surface_hit += float(has_hit); } /* Average samples. */ - ShadowEvalResult result; - result.light_visibilty = saturate(1.0 - surface_hit / float(ray_count)); - result.occluder_distance = 0.0; /* Unused. Could reintroduced if needed. */ - return result; + return saturate(1.0 - surface_hit / float(ray_count)); } /** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl index 9880fc30cb6..27d83755154 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_lib.glsl @@ -162,6 +162,14 @@ void shadow_viewport_layer_set(int view_id, int lod) gpu_ViewportIndex = lod; } +vec3 shadow_position_vector_get(vec3 view_position, ShadowRenderView view) +{ + if (view.is_directionnal) { + return vec3(0.0, 0.0, -view_position.z - view.clip_near); + } + return view_position; +} + /* In order to support physical clipping, we pass a vector to the fragment shader that then clips * each fragment using a unit sphere test. This allows to support both point light and area light * clipping at the same time. */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_shadow_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_shadow_frag.glsl index 754c1244282..5c0c875e579 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surf_shadow_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surf_shadow_frag.glsl @@ -24,21 +24,19 @@ vec4 closure_to_rgba(Closure cl) void main() { - float f_depth = gl_FragCoord.z; - /* Slope bias. - * Note that we always need a minimum slope bias of 1 pixel to avoid slanted surfaces aliasing - * onto facing surfaces. - * IMPORTANT: `fwidth` needs to be inside uniform control flow. */ + float ndc_depth = gl_FragCoord.z; + float linear_depth = length(shadow_clip.position); + #ifdef SHADOW_UPDATE_TBDR /* We need to write to `gl_FragDepth` un-conditionally. So we cannot early exit or use discard. */ -# define discard_result f_depth = 1.0; +# define discard_result \ + linear_depth = FLT_MAX; \ + ndc_depth = 1.0; #else # define discard_result \ discard; \ return; #endif - /* Avoid values greater than 1. */ - f_depth = saturate(f_depth); /* Clip to light shape. */ if (length_squared(shadow_clip.vector) < 1.0) { @@ -83,12 +81,12 @@ void main() ivec3 out_texel = ivec3((page.xy << page_shift) | texel_page, page.z); - uint u_depth = floatBitsToUint(f_depth); + uint u_depth = floatBitsToUint(linear_depth); imageAtomicMin(shadow_atlas_img, out_texel, u_depth); #endif #ifdef SHADOW_UPDATE_TBDR - gl_FragDepth = f_depth; - out_depth = f_depth; + gl_FragDepth = ndc_depth; + out_depth = linear_depth; #endif } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_volume_scatter_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_volume_scatter_comp.glsl index 9c4de2537a5..360e9aff141 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_volume_scatter_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_volume_scatter_comp.glsl @@ -39,8 +39,10 @@ vec3 volume_light_eval(const bool is_directional, vec3 P, vec3 V, uint l_idx, fl float visibility = attenuation; if (light.tilemap_index != LIGHT_NO_SHADOW) { - visibility *= shadow_sample(is_directional, shadow_atlas_tx, shadow_tilemaps_tx, light, P) - .light_visibilty; + float delta = shadow_sample(is_directional, shadow_atlas_tx, shadow_tilemaps_tx, light, P); + if (delta > 0.0) { + return vec3(0); + } } visibility *= volume_phase_function(-V, lv.L, s_anisotropy); if (visibility < LIGHT_ATTENUATION_THRESHOLD) { diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh index 2cfd7c996d5..b2387f6836c 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_material_info.hh @@ -232,17 +232,14 @@ GPU_SHADER_INTERFACE_INFO(eevee_surf_shadow_atomic_iface, "shadow_iface") .flat(Type::INT, "shadow_view_id"); GPU_SHADER_INTERFACE_INFO(eevee_surf_shadow_clipping_iface, "shadow_clip") + .smooth(Type::VEC3, "position") .smooth(Type::VEC3, "vector"); -GPU_SHADER_INTERFACE_INFO(eevee_surf_shadow_flat_iface, "shadow_flat") - .flat(Type::FLOAT, "filter_radius"); - GPU_SHADER_CREATE_INFO(eevee_surf_shadow) .define("DRW_VIEW_LEN", STRINGIFY(SHADOW_VIEW_MAX)) .define("MAT_SHADOW") .builtins(BuiltinBits::VIEWPORT_INDEX) .vertex_out(eevee_surf_shadow_clipping_iface) - .vertex_out(eevee_surf_shadow_flat_iface) .storage_buf(SHADOW_RENDER_VIEW_BUF_SLOT, Qualifier::READ, "ShadowRenderView", diff --git a/source/blender/draw/tests/eevee_test.cc b/source/blender/draw/tests/eevee_test.cc index 11698eb3517..4582dea46de 100644 --- a/source/blender/draw/tests/eevee_test.cc +++ b/source/blender/draw/tests/eevee_test.cc @@ -234,13 +234,12 @@ static void test_eevee_shadow_tag_update() { ShadowTileMap tilemap(0 * SHADOW_TILEDATA_PER_TILEMAP); tilemap.sync_cubeface( - LIGHT_OMNI_SPHERE, float4x4::identity(), 0.01f, 1.0f, 0.01f, 0.0f, Z_NEG, 0.0f, 0.0f); + LIGHT_OMNI_SPHERE, float4x4::identity(), 0.01f, 1.0f, 0.01f, 0.0f, Z_NEG, 0.0f); tilemaps_data.append(tilemap); } { ShadowTileMap tilemap(1 * SHADOW_TILEDATA_PER_TILEMAP); - tilemap.sync_orthographic( - float4x4::identity(), int2(0), 1, 0.0f, 0.0f, SHADOW_PROJECTION_CLIPMAP); + tilemap.sync_orthographic(float4x4::identity(), int2(0), 1, 0.0f, SHADOW_PROJECTION_CLIPMAP); tilemaps_data.append(tilemap); } @@ -1544,7 +1543,7 @@ static void test_eevee_shadow_page_mask_ex(int max_view_per_tilemap) { ShadowTileMap tilemap(0); tilemap.sync_cubeface( - LIGHT_OMNI_SPHERE, float4x4::identity(), 0.01f, 1.0f, 0.01f, 0.0f, Z_NEG, 0.0f, 0.0f); + LIGHT_OMNI_SPHERE, float4x4::identity(), 0.01f, 1.0f, 0.01f, 0.0f, Z_NEG, 0.0f); tilemaps_data.append(tilemap); }