mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
EEVEE: Port Light Eval Loop to BSL
Rel #151442 This rewrites the light loop macro to Iterator templated classes. While this is aguably more boiler plate code, it allows for better static analysis and removes most of the macros and defines. The templating also allows to make specific path variation (for transmission for instance). Pull Request: https://projects.blender.org/blender/blender/pulls/158553
This commit is contained in:
parent
80b3fc1080
commit
d0c8ae7db3
46 changed files with 1261 additions and 1152 deletions
|
|
@ -330,7 +330,6 @@ set(GLSL_SRC
|
|||
engines/eevee/shaders/infos/eevee_fullscreen_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_geom_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_hiz_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_light_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_lightprobe_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_lightprobe_sphere_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_lightprobe_volume_infos.hh
|
||||
|
|
@ -339,7 +338,6 @@ set(GLSL_SRC
|
|||
engines/eevee/shaders/infos/eevee_nodetree_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_raycast_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_sampling_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_shadow_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_surf_depth_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_surf_shadow_infos.hh
|
||||
engines/eevee/shaders/infos/eevee_surf_volume_infos.hh
|
||||
|
|
@ -448,8 +446,9 @@ set(GLSL_SRC
|
|||
engines/eevee/shaders/eevee_fast_gi.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_culling.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_shadow_setup.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_eval_lib.glsl
|
||||
engines/eevee/shaders/eevee_light_iter_lib.glsl
|
||||
engines/eevee/shaders/eevee_light_data.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_eval.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_iter.bsl.hh
|
||||
engines/eevee/shaders/eevee_light_lib.glsl
|
||||
engines/eevee/shaders/eevee_lightprobe_display.bsl.hh
|
||||
engines/eevee/shaders/eevee_lightprobe_eval_lib.glsl
|
||||
|
|
@ -494,8 +493,8 @@ set(GLSL_SRC
|
|||
engines/eevee/shaders/eevee_renderpass_clear.bsl.hh
|
||||
engines/eevee/shaders/eevee_renderpass_lib.glsl
|
||||
engines/eevee/shaders/eevee_sampling_lib.glsl
|
||||
engines/eevee/shaders/eevee_shadow_lib.glsl
|
||||
engines/eevee/shaders/eevee_shadow_tracing_lib.glsl
|
||||
engines/eevee/shaders/eevee_shadow.bsl.hh
|
||||
engines/eevee/shaders/eevee_shadow_tracing.bsl.hh
|
||||
engines/eevee/shaders/eevee_shadow_page_allocate.bsl.hh
|
||||
engines/eevee/shaders/eevee_shadow_page_clear.bsl.hh
|
||||
engines/eevee/shaders/eevee_shadow_page_defrag.bsl.hh
|
||||
|
|
|
|||
|
|
@ -1009,24 +1009,15 @@ void ShaderModule::material_create_info_amend(GPUMaterial *gpumat, GPUCodegenOut
|
|||
if ((pipeline_type == MAT_PIPE_FORWARD) ||
|
||||
GPU_material_flag_get(gpumat, GPU_MATFLAG_SHADER_TO_RGBA))
|
||||
{
|
||||
switch (closure_bin_count) {
|
||||
case 0:
|
||||
/* Define nothing. This will in turn define SKIP_LIGHT_EVAL. */
|
||||
break;
|
||||
/* These need to be separated since the strings need to be static. */
|
||||
case 1:
|
||||
info.define("LIGHT_CLOSURE_EVAL_COUNT", "1");
|
||||
break;
|
||||
case 2:
|
||||
info.define("LIGHT_CLOSURE_EVAL_COUNT", "2");
|
||||
break;
|
||||
case 3:
|
||||
info.define("LIGHT_CLOSURE_EVAL_COUNT", "3");
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
break;
|
||||
}
|
||||
const int transmit_eval_count = (closure_bits &
|
||||
(CLOSURE_REFRACTION | CLOSURE_TRANSLUCENT | CLOSURE_SSS)) ?
|
||||
1 :
|
||||
0;
|
||||
|
||||
info.compilation_constant(
|
||||
gpu::shader::Type::int_t, "light_closure_eval_count_reflect", closure_bin_count);
|
||||
info.compilation_constant(
|
||||
gpu::shader::Type::int_t, "light_closure_eval_count_transmit", transmit_eval_count);
|
||||
}
|
||||
|
||||
if (GPU_material_flag_get(gpumat, GPU_MATFLAG_BARYCENTRIC)) {
|
||||
|
|
|
|||
|
|
@ -893,6 +893,8 @@ void ShadowModule::end_sync()
|
|||
sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip);
|
||||
sub.bind_ssbo("casters_id_buf", curr_casters_);
|
||||
sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current());
|
||||
/* Bind again using a writable binding. */
|
||||
sub.bind_ssbo("light_buf_write", inst_.lights.culling_light_buf_);
|
||||
sub.push_constant("resource_len", int(curr_casters_.size()));
|
||||
sub.bind_resources(inst_.lights);
|
||||
sub.dispatch(int3(
|
||||
|
|
@ -1090,6 +1092,8 @@ void ShadowModule::end_sync()
|
|||
sub.bind_image("tilemaps_img", tilemap_pool.tilemap_tx);
|
||||
sub.bind_ssbo("tilemaps_buf", tilemap_pool.tilemaps_data);
|
||||
sub.bind_resources(inst_.lights);
|
||||
/* Bind again using a writable binding. */
|
||||
sub.bind_ssbo("light_buf_write", inst_.lights.culling_light_buf_);
|
||||
sub.dispatch(int3(1));
|
||||
sub.barrier(GPU_BARRIER_TEXTURE_FETCH);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,8 +109,6 @@ set(SRC_GLSL_LIB
|
|||
eevee_filter_lib.glsl
|
||||
# eevee_forward_lib.glsl
|
||||
eevee_gbuffer_lib.glsl
|
||||
eevee_light_eval_lib.glsl
|
||||
eevee_light_iter_lib.glsl
|
||||
eevee_light_lib.glsl
|
||||
eevee_lightprobe_eval_lib.glsl
|
||||
eevee_lightprobe_lib.glsl
|
||||
|
|
@ -122,8 +120,6 @@ set(SRC_GLSL_LIB
|
|||
eevee_ray_generate_lib.glsl
|
||||
eevee_renderpass_lib.glsl
|
||||
eevee_sampling_lib.glsl
|
||||
eevee_shadow_lib.glsl
|
||||
eevee_shadow_tracing_lib.glsl
|
||||
eevee_subsurface_lib.glsl
|
||||
eevee_surf_lib.glsl
|
||||
# eevee_transparency_lib.glsl # Require Fragment shader include
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include "eevee_deferred_thickness_amend.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_fast_gi.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_light_culling.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_light_eval.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_light_iter.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_light_shadow_setup.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_lightprobe_display.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_ltc_lib.bsl.hh" /* IWYU pragma: export */
|
||||
|
|
@ -25,6 +27,7 @@
|
|||
#include "eevee_ray_trace.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_ray_types_lib.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_reverse_z_lib.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow_page_allocate.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow_page_clear.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow_page_defrag.bsl.hh" /* IWYU pragma: export */
|
||||
|
|
@ -39,6 +42,7 @@
|
|||
#include "eevee_shadow_tilemap_finalize.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow_tilemap_init.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow_tilemap_lib.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow_tracing.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_shadow_visibility.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_subsurface.bsl.hh" /* IWYU pragma: export */
|
||||
#include "eevee_surf_capture.bsl.hh" /* IWYU pragma: export */
|
||||
|
|
|
|||
|
|
@ -9,21 +9,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "infos/eevee_common_infos.hh"
|
||||
#include "infos/eevee_light_infos.hh"
|
||||
#include "infos/eevee_shadow_infos.hh"
|
||||
|
||||
FRAGMENT_SHADER_CREATE_INFO(draw_view)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_hiz_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_light_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_shadow_data)
|
||||
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_debug_shared.hh"
|
||||
#include "eevee_defines.hh"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_iter.bsl.hh"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_sampling_lib.glsl"
|
||||
#include "eevee_shadow_lib.glsl"
|
||||
#include "eevee_shadow.bsl.hh"
|
||||
#include "eevee_shadow_shared.hh"
|
||||
#include "eevee_shadow_tilemap_lib.bsl.hh"
|
||||
#include "gpu_shader_debug_gradients_lib.glsl"
|
||||
|
|
@ -44,11 +40,34 @@ struct DebugVertOut {
|
|||
|
||||
#define default_depth -1.0f
|
||||
|
||||
struct SearchDebugLightCtx {
|
||||
int debug_tilemap_index;
|
||||
uint light_index;
|
||||
|
||||
void eval_directional([[resource_table]] LightRenderData & /*res*/, uint l_idx, LightData light)
|
||||
{
|
||||
if (light.tilemap_index == debug_tilemap_index) {
|
||||
light_index = l_idx;
|
||||
}
|
||||
}
|
||||
void eval_local([[resource_table]] LightRenderData & /*res*/, uint l_idx, LightData light)
|
||||
{
|
||||
if (light.tilemap_index == debug_tilemap_index) {
|
||||
light_index = l_idx;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template void light::foreach<SearchDebugLightCtx, LightRenderData>(const LightRenderData &,
|
||||
SearchDebugLightCtx &,
|
||||
LightRenderData &);
|
||||
|
||||
struct ShadowDebug {
|
||||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
|
||||
[[resource_table]] srt_t<LightRenderData> light_data;
|
||||
[[resource_table]] srt_t<ShadowRenderData> shadow_data;
|
||||
|
||||
[[storage(5, read)]] ShadowTileMapData (&tilemaps_buf)[];
|
||||
[[storage(6, read)]] uint (&tiles_buf)[];
|
||||
|
|
@ -128,32 +147,23 @@ struct ShadowDebug {
|
|||
|
||||
ShadowSamplingTile debug_tile_get(float3 P, LightData light) const
|
||||
{
|
||||
[[resource_table]] const ShadowRenderData &srd = shadow_data;
|
||||
ShadowCoordinates coord = debug_coord_get(P, light);
|
||||
return shadow_tile_data_get(shadow_tilemaps_tx, coord);
|
||||
return shadow_tile_data_get(srd.shadow_tilemaps_tx, coord);
|
||||
}
|
||||
|
||||
LightData debug_light_get() const
|
||||
LightData debug_light_get()
|
||||
{
|
||||
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(light_cull_buf, l_idx)
|
||||
{
|
||||
LightData light = light_buf[l_idx];
|
||||
if (light.tilemap_index == debug_tilemap_index) {
|
||||
return light;
|
||||
}
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
[[resource_table]] LightRenderData &lrd = light_data;
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
LightData light = light_buf[l_idx];
|
||||
if (light.tilemap_index == debug_tilemap_index) {
|
||||
return light;
|
||||
}
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
SearchDebugLightCtx ctx = {
|
||||
.debug_tilemap_index = this->debug_tilemap_index,
|
||||
.light_index = 0,
|
||||
};
|
||||
|
||||
/* TODO Assert. */
|
||||
/* Silence compiler warning. */
|
||||
return light_buf[0];
|
||||
light::foreach(lrd, ctx, lrd);
|
||||
|
||||
return lrd.light_buf[ctx.light_index];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -175,6 +185,8 @@ ShadowDebugOutput debug_tilemaps([[resource_table]] const ShadowDebug &srt,
|
|||
int2 texel,
|
||||
bool do_debug_sample_tile)
|
||||
{
|
||||
[[resource_table]] const ShadowRenderData &srd = srt.shadow_data;
|
||||
|
||||
/** Control the scaling of the tile-map splat. */
|
||||
constexpr int debug_tile_size_px = 4;
|
||||
|
||||
|
|
@ -186,7 +198,7 @@ ShadowDebugOutput debug_tilemaps([[resource_table]] const ShadowDebug &srt,
|
|||
/* Debug values in the tilemap_tx. */
|
||||
uint2 tilemap_texel = shadow_tile_coord_in_atlas(uint2(px), tilemap_index);
|
||||
ShadowSamplingTile tile = shadow_sampling_tile_unpack(
|
||||
texelFetch(shadow_tilemaps_tx, int2(tilemap_texel), 0).x);
|
||||
texelFetch(srd.shadow_tilemaps_tx, int2(tilemap_texel), 0).x);
|
||||
/* Leave 1 px border between tile-maps. */
|
||||
if (!any(equal(texel % (SHADOW_TILEMAP_RES * debug_tile_size_px), int2(0)))) {
|
||||
return {.valid = true,
|
||||
|
|
@ -233,8 +245,10 @@ ShadowDebugOutput debug_atlas_values([[resource_table]] const ShadowDebug &srt,
|
|||
float3 P,
|
||||
LightData light)
|
||||
{
|
||||
[[resource_table]] const ShadowRenderData &srd = srt.shadow_data;
|
||||
|
||||
ShadowCoordinates coord = srt.debug_coord_get(P, light);
|
||||
float depth = shadow_read_depth(shadow_atlas_tx, shadow_tilemaps_tx, coord);
|
||||
float depth = srd.read_depth(coord);
|
||||
return {
|
||||
.valid = true,
|
||||
.color_add = float4((depth == -1) ? float3(1.0f, 0.0f, 0.0f) : float3(1.0f / depth), 0.0f) *
|
||||
|
|
@ -243,33 +257,45 @@ ShadowDebugOutput debug_atlas_values([[resource_table]] const ShadowDebug &srt,
|
|||
.depth = default_depth};
|
||||
}
|
||||
|
||||
float debug_atomic_cost([[resource_table]] const ShadowDebug &srt, uint l_idx, float3 P)
|
||||
{
|
||||
LightData light = light_buf[l_idx];
|
||||
ShadowCoordinates coord = srt.debug_coord_get(P, light);
|
||||
uint cost = floatBitsToUint(shadow_read_depth(shadow_atlas_tx, shadow_tilemaps_tx, coord));
|
||||
return float(cost - floatBitsToUint(FLT_MAX));
|
||||
}
|
||||
struct AtomicCostCtx {
|
||||
float3 P;
|
||||
float cost;
|
||||
|
||||
ShadowDebugOutput debug_atomic_cost([[resource_table]] const ShadowDebug &srt,
|
||||
float atomic_cost([[resource_table]] const ShadowDebug &srt, LightData light)
|
||||
{
|
||||
[[resource_table]] const ShadowRenderData &srd = srt.shadow_data;
|
||||
|
||||
ShadowCoordinates coord = srt.debug_coord_get(P, light);
|
||||
uint u_cost = floatBitsToUint(srd.read_depth(coord));
|
||||
return float(u_cost - floatBitsToUint(FLT_MAX));
|
||||
}
|
||||
|
||||
void eval_directional([[resource_table]] ShadowDebug &srt, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
cost += atomic_cost(srt, light);
|
||||
}
|
||||
|
||||
void eval_local([[resource_table]] ShadowDebug &srt, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
cost += atomic_cost(srt, light);
|
||||
}
|
||||
};
|
||||
|
||||
template void light::foreach<AtomicCostCtx, ShadowDebug>(const LightRenderData &,
|
||||
AtomicCostCtx &,
|
||||
ShadowDebug &);
|
||||
|
||||
ShadowDebugOutput debug_atomic_cost([[resource_table]] ShadowDebug &srt,
|
||||
float3 P,
|
||||
LightData /*light*/)
|
||||
{
|
||||
float cost = 0.0f;
|
||||
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(light_cull_buf, l_idx)
|
||||
{
|
||||
cost += debug_atomic_cost(srt, l_idx, P);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
AtomicCostCtx ctx = {.P = P, .cost = 0.0f};
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
cost += debug_atomic_cost(srt, l_idx, P);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
light::foreach(srt.light_data, ctx, srt);
|
||||
|
||||
cost /= 60.0f;
|
||||
ctx.cost /= 60.0f;
|
||||
return {.valid = true,
|
||||
.color_add = float4(heatmap_gradient(cost), 0.0f),
|
||||
.color_add = float4(heatmap_gradient(ctx.cost), 0.0f),
|
||||
.color_mul = float4(0.0f),
|
||||
.depth = default_depth};
|
||||
}
|
||||
|
|
@ -297,7 +323,7 @@ ShadowDebugOutput debug_random_tilemap_color([[resource_table]] const ShadowDebu
|
|||
}
|
||||
|
||||
[[fragment]]
|
||||
void debug_shadow_frag([[resource_table]] const ShadowDebug &srt,
|
||||
void debug_shadow_frag([[resource_table]] ShadowDebug &srt,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[frag_depth(greater)]] float &frag_depth,
|
||||
[[in]] const DebugVertOut v_out,
|
||||
|
|
|
|||
|
|
@ -15,15 +15,13 @@ FRAGMENT_SHADER_CREATE_INFO(draw_object_infos)
|
|||
FRAGMENT_SHADER_CREATE_INFO(eevee_gbuffer_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_utility_texture)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_sampling_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_light_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_shadow_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_hiz_data)
|
||||
FRAGMENT_SHADER_CREATE_INFO(eevee_volume_probe_data)
|
||||
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_closure_lib.glsl"
|
||||
#include "eevee_gbuffer_read_lib.glsl"
|
||||
#include "eevee_light_eval_lib.glsl"
|
||||
#include "eevee_light_eval.bsl.hh"
|
||||
#include "eevee_lightprobe_eval_lib.glsl"
|
||||
#include "eevee_lightprobe_volume_eval_lib.glsl"
|
||||
#include "eevee_renderpass_lib.glsl"
|
||||
|
|
@ -57,8 +55,6 @@ struct LightEval {
|
|||
[[legacy_info]] ShaderCreateInfo eevee_gbuffer_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_utility_texture;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_sampling_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_lightprobe_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_render_pass_out;
|
||||
|
|
@ -72,8 +68,6 @@ struct LightEval {
|
|||
[[specialization_constant(1)]] int shadow_ray_count;
|
||||
[[specialization_constant(6)]] int shadow_ray_step_count;
|
||||
|
||||
[[compilation_constant]] int light_closure_eval_count;
|
||||
|
||||
/* Chaining to next pass. */
|
||||
[[image(2, write, DEFERRED_RADIANCE_FORMAT)]] uimage2D direct_radiance_1_img;
|
||||
[[image(3, write, DEFERRED_RADIANCE_FORMAT)]] uimage2D direct_radiance_2_img;
|
||||
|
|
@ -117,9 +111,12 @@ struct LightEval {
|
|||
* Load all BSDFs closures and evaluate LTC for each selected lights. */
|
||||
[[fragment, early_fragment_tests]]
|
||||
void light_eval_frag([[resource_table]] LightEval &srt,
|
||||
[[resource_table]] LightEvalIterator &lights,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[in]] const VertOut v_out)
|
||||
{
|
||||
[[resource_table]] LightEvalData &lrt = lights.inner;
|
||||
|
||||
const int2 texel = int2(frag_co.xy);
|
||||
|
||||
/* Bias the shading point position because of depth buffer precision.
|
||||
|
|
@ -136,66 +133,65 @@ void light_eval_frag([[resource_table]] LightEval &srt,
|
|||
const float3 V = drw_world_incident_vector(P);
|
||||
const float vPz = dot(drw_view_forward(), P) - dot(drw_view_forward(), drw_view_position());
|
||||
|
||||
ClosureLightStack stack;
|
||||
light::EvalCtx<false> ctx;
|
||||
/* Unroll light stack array assignments to avoid non-constant indexing. */
|
||||
closure_light_set(stack, 0, closure_light_new(gbuf.layer[0], V));
|
||||
if (srt.light_closure_eval_count > 1) [[static_branch]] {
|
||||
closure_light_set(stack, 1, closure_light_new(gbuf.layer[1], V));
|
||||
}
|
||||
if (srt.light_closure_eval_count > 2) [[static_branch]] {
|
||||
closure_light_set(stack, 2, closure_light_new(gbuf.layer[2], V));
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (lrt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
ctx.stack.cl[i] = closure_light_new(gbuf.layer[i], V);
|
||||
}
|
||||
}
|
||||
|
||||
uchar receiver_light_set = 0;
|
||||
float normal_offset = 0.0f;
|
||||
float geometry_offset = 0.0f;
|
||||
ctx.P = P;
|
||||
ctx.Ng = Ng;
|
||||
ctx.V = V;
|
||||
ctx.thickness = thickness;
|
||||
ctx.receiver_light_set = 0;
|
||||
ctx.terminator_normal_offset = 0.0f;
|
||||
ctx.terminator_geometry_offset = 0.0f;
|
||||
if (gbuf.header.use_object_id()) {
|
||||
uint object_id = gbuffer::read_object_id(texel);
|
||||
ObjectInfos object_infos = drw_infos[object_id];
|
||||
receiver_light_set = receiver_light_set_get(object_infos);
|
||||
normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
ctx.receiver_light_set = receiver_light_set_get(object_infos);
|
||||
ctx.terminator_normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
ctx.terminator_geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
}
|
||||
|
||||
/* TODO(fclem): If transmission (no SSS) is present, we could reduce LIGHT_CLOSURE_EVAL_COUNT
|
||||
* by 1 for this evaluation and skip evaluating the transmission closure twice. */
|
||||
light_eval_reflection(stack, P, Ng, V, vPz, receiver_light_set, normal_offset, geometry_offset);
|
||||
lights.eval_reflection(ctx, frag_co.xy, vPz);
|
||||
|
||||
if (srt.use_transmission) {
|
||||
ClosureUndetermined cl_transmit = gbuf.layer[0];
|
||||
#if 1 /* TODO Limit to SSS. */
|
||||
float3 sss_reflect_shadowed, sss_reflect_unshadowed;
|
||||
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {
|
||||
sss_reflect_shadowed = stack.cl[0].light_shadowed;
|
||||
sss_reflect_unshadowed = stack.cl[0].light_unshadowed;
|
||||
}
|
||||
#endif
|
||||
light::EvalCtx<true> ctx_tr = light::init_from_reflect_ctx(ctx);
|
||||
|
||||
stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
ClosureUndetermined cl_transmit = gbuf.layer[0];
|
||||
ctx_tr.stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
|
||||
/* NOTE: Only evaluates `stack.cl[0]`. */
|
||||
light_eval_transmission(
|
||||
stack, P, Ng, V, vPz, thickness, receiver_light_set, normal_offset, geometry_offset);
|
||||
lights.eval_transmission(ctx_tr, frag_co.xy, vPz);
|
||||
|
||||
#if 1 /* TODO Limit to SSS. */
|
||||
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {
|
||||
/* Apply transmission profile onto transmitted light and sum with reflected light. */
|
||||
float3 sss_profile = subsurface_transmission(to_closure_subsurface(cl_transmit).sss_radius,
|
||||
thickness.value());
|
||||
stack.cl[0].light_shadowed *= sss_profile;
|
||||
stack.cl[0].light_unshadowed *= sss_profile;
|
||||
stack.cl[0].light_shadowed += sss_reflect_shadowed;
|
||||
stack.cl[0].light_unshadowed += sss_reflect_unshadowed;
|
||||
ctx.stack.cl[0].light_shadowed += ctx_tr.stack.cl[0].light_shadowed * sss_profile;
|
||||
ctx.stack.cl[0].light_unshadowed += ctx_tr.stack.cl[0].light_unshadowed * sss_profile;
|
||||
}
|
||||
else {
|
||||
ctx.stack.cl[0].light_shadowed = ctx_tr.stack.cl[0].light_shadowed;
|
||||
ctx.stack.cl[0].light_unshadowed = ctx_tr.stack.cl[0].light_unshadowed;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (srt.render_pass_shadow_id != -1) {
|
||||
float3 radiance_shadowed = float3(0);
|
||||
float3 radiance_unshadowed = float3(0);
|
||||
for (uchar i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < closure_count; i++) {
|
||||
radiance_shadowed += closure_light_get(stack, i).light_shadowed;
|
||||
radiance_unshadowed += closure_light_get(stack, i).light_unshadowed;
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (lrt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
if (i < closure_count) {
|
||||
radiance_shadowed += ctx.stack.cl[i].light_shadowed;
|
||||
radiance_unshadowed += ctx.stack.cl[i].light_unshadowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
float3 shadows = radiance_shadowed * safe_rcp(radiance_unshadowed);
|
||||
output_renderpass_value(srt.render_pass_shadow_id, average(shadows));
|
||||
|
|
@ -209,23 +205,33 @@ void light_eval_frag([[resource_table]] LightEval &srt,
|
|||
clamp_indirect);
|
||||
|
||||
uint3 bin_indices = gbuf.header.bin_index_per_layer();
|
||||
for (uchar i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < closure_count; i++) {
|
||||
float3 indirect_light = lightprobe_eval(samp, gbuf.layer[i], P, V, thickness);
|
||||
float3 direct_light = closure_light_get(stack, i).light_shadowed;
|
||||
if (srt.use_split_indirect) {
|
||||
srt.write_radiance_indirect(bin_indices[i], texel, indirect_light);
|
||||
srt.write_radiance_direct(bin_indices[i], texel, direct_light);
|
||||
}
|
||||
else {
|
||||
srt.write_radiance_direct(bin_indices[i], texel, direct_light + indirect_light);
|
||||
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (lrt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
if (i < closure_count) {
|
||||
float3 indirect_light = lightprobe_eval(samp, gbuf.layer[i], P, V, thickness);
|
||||
float3 direct_light = ctx.stack.cl[i].light_shadowed;
|
||||
if (srt.use_split_indirect) {
|
||||
srt.write_radiance_indirect(bin_indices[i], texel, indirect_light);
|
||||
srt.write_radiance_direct(bin_indices[i], texel, direct_light);
|
||||
}
|
||||
else {
|
||||
srt.write_radiance_direct(bin_indices[i], texel, direct_light + indirect_light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
uint3 bin_indices = gbuf.header.bin_index_per_layer();
|
||||
for (uchar i = 0; i < LIGHT_CLOSURE_EVAL_COUNT && i < closure_count; i++) {
|
||||
float3 direct_light = closure_light_get(stack, i).light_shadowed;
|
||||
srt.write_radiance_direct(bin_indices[i], texel, direct_light);
|
||||
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (lrt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
if (i < closure_count) {
|
||||
float3 direct_light = ctx.stack.cl[i].light_shadowed;
|
||||
srt.write_radiance_direct(bin_indices[i], texel, direct_light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -237,15 +243,11 @@ void light_eval_frag([[resource_table]] LightEval &srt,
|
|||
* \{ */
|
||||
|
||||
struct SphereProbeEval {
|
||||
[[compilation_constant]] int light_closure_eval_count;
|
||||
|
||||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo draw_object_infos;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_gbuffer_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_utility_texture;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_sampling_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_volume_probe_data;
|
||||
};
|
||||
|
|
@ -254,6 +256,7 @@ struct SphereProbeEval {
|
|||
* being available. */
|
||||
[[fragment, early_fragment_tests]]
|
||||
void sphere_eval_frag([[resource_table]] SphereProbeEval & /*srt*/,
|
||||
[[resource_table]] LightEvalIterator &lights,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[in]] const VertOut v_out,
|
||||
[[out]] FragOut &frag_out)
|
||||
|
|
@ -306,29 +309,34 @@ void sphere_eval_frag([[resource_table]] SphereProbeEval & /*srt*/,
|
|||
cl_transmit.N = gbuf.surface_N();
|
||||
cl_transmit.type = CLOSURE_BSDF_TRANSLUCENT_ID;
|
||||
|
||||
uchar receiver_light_set = 0;
|
||||
float normal_offset = 0.0f;
|
||||
float geometry_offset = 0.0f;
|
||||
light::EvalCtx<false> ctx;
|
||||
ctx.P = P;
|
||||
ctx.Ng = Ng;
|
||||
ctx.V = V;
|
||||
ctx.thickness = thickness;
|
||||
ctx.receiver_light_set = 0;
|
||||
ctx.terminator_normal_offset = 0.0f;
|
||||
ctx.terminator_geometry_offset = 0.0f;
|
||||
if (gbuf.header.use_object_id()) {
|
||||
uint object_id = gbuffer::read_object_id(texel);
|
||||
ObjectInfos object_infos = drw_infos[object_id];
|
||||
receiver_light_set = receiver_light_set_get(object_infos);
|
||||
normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
ctx.receiver_light_set = receiver_light_set_get(object_infos);
|
||||
ctx.terminator_normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
ctx.terminator_geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
}
|
||||
|
||||
/* Direct light. */
|
||||
ClosureLightStack stack;
|
||||
stack.cl[0] = closure_light_new(cl, V);
|
||||
light_eval_reflection(stack, P, Ng, V, vPz, receiver_light_set, normal_offset, geometry_offset);
|
||||
ctx.stack.cl[0] = closure_light_new(cl, V);
|
||||
lights.eval_reflection(ctx, frag_co.xy, vPz);
|
||||
|
||||
float3 radiance_front = stack.cl[0].light_shadowed;
|
||||
float3 radiance_front = ctx.stack.cl[0].light_shadowed;
|
||||
|
||||
stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
light_eval_transmission(
|
||||
stack, P, Ng, V, vPz, thickness, receiver_light_set, normal_offset, geometry_offset);
|
||||
light::EvalCtx<true> ctx_tr = light::init_from_reflect_ctx(ctx);
|
||||
|
||||
float3 radiance_back = stack.cl[0].light_shadowed;
|
||||
ctx_tr.stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
lights.eval_transmission(ctx_tr, frag_co.xy, vPz);
|
||||
|
||||
float3 radiance_back = ctx_tr.stack.cl[0].light_shadowed;
|
||||
|
||||
/* Indirect light. */
|
||||
/* Can only load irradiance to avoid dependency loop with the reflection probe. */
|
||||
|
|
@ -344,21 +352,19 @@ void sphere_eval_frag([[resource_table]] SphereProbeEval & /*srt*/,
|
|||
struct PlanarProbeEval {
|
||||
/* TODO(fclem): Workaround waiting for this lib to be ported to BSL. */
|
||||
[[compilation_constant]] bool legacy_sphere_probe_enable;
|
||||
[[compilation_constant]] int light_closure_eval_count;
|
||||
|
||||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo draw_object_infos;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_gbuffer_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_utility_texture;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_sampling_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_lightprobe_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
};
|
||||
|
||||
[[fragment, early_fragment_tests]]
|
||||
void planar_eval_frag([[resource_table]] PlanarProbeEval & /*srt*/,
|
||||
[[resource_table]] LightEvalIterator &lights,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[in]] const VertOut v_out,
|
||||
[[out]] FragOut &frag_out)
|
||||
|
|
@ -446,33 +452,39 @@ void planar_eval_frag([[resource_table]] PlanarProbeEval & /*srt*/,
|
|||
cl_transmit.N = gbuf.surface_N();
|
||||
cl_transmit.type = CLOSURE_BSDF_TRANSLUCENT_ID;
|
||||
|
||||
uchar receiver_light_set = 0;
|
||||
float normal_offset = 0.0f;
|
||||
float geometry_offset = 0.0f;
|
||||
light::EvalCtx<false> ctx;
|
||||
ctx.P = P;
|
||||
ctx.Ng = Ng;
|
||||
ctx.V = V;
|
||||
ctx.thickness = thickness;
|
||||
ctx.receiver_light_set = 0;
|
||||
ctx.terminator_normal_offset = 0.0f;
|
||||
ctx.terminator_geometry_offset = 0.0f;
|
||||
if (gbuf.header.use_object_id()) {
|
||||
uint object_id = gbuffer::read_object_id(texel);
|
||||
ObjectInfos object_infos = drw_infos[object_id];
|
||||
receiver_light_set = receiver_light_set_get(object_infos);
|
||||
normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
ctx.receiver_light_set = receiver_light_set_get(object_infos);
|
||||
ctx.terminator_normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
ctx.terminator_geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
}
|
||||
|
||||
/* Direct light. */
|
||||
ClosureLightStack stack;
|
||||
stack.cl[0] = closure_light_new(cl, V);
|
||||
stack.cl[1] = closure_light_new(cl_reflect, V);
|
||||
light_eval_reflection(stack, P, Ng, V, vPz, receiver_light_set, normal_offset, geometry_offset);
|
||||
ctx.stack.cl[0] = closure_light_new(cl, V);
|
||||
ctx.stack.cl[1] = closure_light_new(cl_reflect, V);
|
||||
lights.eval_reflection(ctx, frag_co.xy, vPz);
|
||||
|
||||
float3 radiance_front = stack.cl[0].light_shadowed;
|
||||
float3 radiance_reflect = stack.cl[1].light_shadowed;
|
||||
float3 radiance_front = ctx.stack.cl[0].light_shadowed;
|
||||
float3 radiance_reflect = ctx.stack.cl[1].light_shadowed;
|
||||
|
||||
stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
stack.cl[1] = closure_light_new(cl_refract, V, thickness);
|
||||
light_eval_transmission(
|
||||
stack, P, Ng, V, vPz, thickness, receiver_light_set, normal_offset, geometry_offset);
|
||||
light::EvalCtx<true> ctx_tr = light::init_from_reflect_ctx(ctx);
|
||||
ctx_tr.stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
/* TODO Replicate the 5.1 bug for now. */
|
||||
// ctx_tr.stack.cl[1] = closure_light_new(cl_refract, V, thickness);
|
||||
lights.eval_transmission(ctx_tr, frag_co.xy, vPz);
|
||||
|
||||
float3 radiance_back = stack.cl[0].light_shadowed;
|
||||
float3 radiance_refract = stack.cl[1].light_shadowed;
|
||||
float3 radiance_back = ctx_tr.stack.cl[0].light_shadowed;
|
||||
/* TODO Replicate the 5.1 bug for now. */
|
||||
float3 radiance_refract = float3(0.0f); // ctx_tr.stack.cl[1].light_shadowed;
|
||||
|
||||
/* Indirect light. */
|
||||
SphericalHarmonicL1<float4> sh = lightprobe_volume_sample(P, V, Ng);
|
||||
|
|
@ -495,29 +507,36 @@ void planar_eval_frag([[resource_table]] PlanarProbeEval & /*srt*/,
|
|||
|
||||
PipelineGraphic light_single(fullscreen_vert,
|
||||
light_eval_frag,
|
||||
LightEval{
|
||||
.light_closure_eval_count = 1,
|
||||
LightEvalData{
|
||||
.light_closure_eval_count_reflect = 1,
|
||||
.light_closure_eval_count_transmit = 1,
|
||||
});
|
||||
PipelineGraphic light_double(fullscreen_vert,
|
||||
light_eval_frag,
|
||||
LightEval{
|
||||
.light_closure_eval_count = 2,
|
||||
LightEvalData{
|
||||
.light_closure_eval_count_reflect = 2,
|
||||
.light_closure_eval_count_transmit = 1,
|
||||
});
|
||||
PipelineGraphic light_triple(fullscreen_vert,
|
||||
light_eval_frag,
|
||||
LightEval{
|
||||
.light_closure_eval_count = 3,
|
||||
LightEvalData{
|
||||
.light_closure_eval_count_reflect = 3,
|
||||
.light_closure_eval_count_transmit = 1,
|
||||
});
|
||||
PipelineGraphic sphere_eval(fullscreen_vert,
|
||||
sphere_eval_frag,
|
||||
SphereProbeEval{
|
||||
.light_closure_eval_count = 1,
|
||||
LightEvalData{
|
||||
.light_closure_eval_count_reflect = 1,
|
||||
.light_closure_eval_count_transmit = 1,
|
||||
});
|
||||
PipelineGraphic planar_eval(fullscreen_vert,
|
||||
planar_eval_frag,
|
||||
PlanarProbeEval{
|
||||
.legacy_sphere_probe_enable = true,
|
||||
.light_closure_eval_count = 2,
|
||||
},
|
||||
LightEvalData{
|
||||
.light_closure_eval_count_reflect = 2,
|
||||
.light_closure_eval_count_transmit = 1, /* TODO should be 2. */
|
||||
});
|
||||
|
||||
} // namespace eevee::deferred
|
||||
|
|
|
|||
|
|
@ -9,20 +9,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "infos/eevee_common_infos.hh"
|
||||
#include "infos/eevee_light_infos.hh"
|
||||
#include "infos/eevee_shadow_infos.hh"
|
||||
|
||||
SHADER_LIBRARY_CREATE_INFO(draw_view)
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_hiz_data)
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_shadow_data)
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_light_data)
|
||||
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_gbuffer_lib.glsl"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_data.bsl.hh"
|
||||
#include "eevee_light_iter.bsl.hh"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_sampling_lib.glsl"
|
||||
#include "eevee_shadow_tracing_lib.glsl"
|
||||
#include "eevee_shadow_tracing.bsl.hh"
|
||||
#include "gpu_shader_fullscreen_lib.glsl"
|
||||
|
||||
namespace eevee::thickness {
|
||||
|
|
@ -35,7 +32,7 @@ struct FromShadowEvalCtx {
|
|||
float weight_accum;
|
||||
float2 pcf_random;
|
||||
|
||||
void eval(LightData light, const bool is_directional)
|
||||
void eval([[resource_table]] ShadowRenderData &srd, LightData light, const bool is_directional)
|
||||
{
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||
return;
|
||||
|
|
@ -60,8 +57,7 @@ struct FromShadowEvalCtx {
|
|||
*/
|
||||
P_offset -= texel_radius * shadow_pcf_offset(lv.L, Ng, pcf_random);
|
||||
|
||||
float occluder_delta = shadow_sample(
|
||||
is_directional, shadow_atlas_tx, shadow_tilemaps_tx, light, P_offset);
|
||||
float occluder_delta = srd.shadow_sample(is_directional, light, P_offset);
|
||||
if (occluder_delta > 0.0f) {
|
||||
float hit_distance = abs(occluder_delta);
|
||||
/* Add back the amount of offset we added to the original position.
|
||||
|
|
@ -79,26 +75,29 @@ struct FromShadowEvalCtx {
|
|||
}
|
||||
}
|
||||
|
||||
void eval_directional(uint /*l_idx*/, LightData light)
|
||||
void eval_directional([[resource_table]] ShadowRenderData &srd, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
eval(light, true);
|
||||
eval(srd, light, true);
|
||||
}
|
||||
void eval_local(uint /*l_idx*/, LightData light)
|
||||
void eval_local([[resource_table]] ShadowRenderData &srd, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
eval(light, false);
|
||||
eval(srd, light, false);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace eevee::thickness
|
||||
|
||||
namespace eevee {
|
||||
template void light::foreach_visible<thickness::FromShadowEvalCtx, ShadowRenderData>(
|
||||
const LightRenderData &, float2, float, thickness::FromShadowEvalCtx &, ShadowRenderData &);
|
||||
} // namespace eevee
|
||||
|
||||
namespace eevee {
|
||||
|
||||
struct ThicknessAmend {
|
||||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_sampling_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
|
||||
[[sampler(0)]] usampler2DArray gbuf_header_tx;
|
||||
[[image(0, read_write, UNORM_16_16)]] image2DArray gbuf_normal_img;
|
||||
|
|
@ -119,6 +118,8 @@ void amend_vert([[vertex_id]] const int vert_id,
|
|||
/* Early fragment test is needed to discard fragment that do not need this processing. */
|
||||
[[fragment]] [[early_fragment_tests]]
|
||||
void amend_frag([[resource_table]] ThicknessAmend &srt,
|
||||
[[resource_table]] ShadowRenderData &srd,
|
||||
[[resource_table]] const LightRenderData &lrd,
|
||||
[[in]] const VertOut &v_out,
|
||||
[[frag_coord]] const float4 frag_co)
|
||||
{
|
||||
|
|
@ -150,18 +151,7 @@ void amend_frag([[resource_table]] ThicknessAmend &srt,
|
|||
.pcf_random = pcg4d(float4(frag_co.xyz, sampling_rng_1D_get(SAMPLING_SHADOW_X))).xy,
|
||||
};
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
LightData light = light_buf[l_idx];
|
||||
ctx.eval_directional(l_idx, light);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
float2 pixel = frag_co.xy;
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vPz, l_idx) {
|
||||
LightData light = light_buf[l_idx];
|
||||
ctx.eval_local(l_idx, light);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
light::foreach_visible(lrd, frag_co.xy, vPz, ctx, srd);
|
||||
|
||||
/* The apparent thickness of an object behind its surface considering all shadow maps
|
||||
* available. If no shadow-map has a record of the other side of the surface, do not amend
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#include "draw_model_lib.glsl"
|
||||
#include "eevee_colorspace_lib.bsl.hh"
|
||||
#include "eevee_light_eval_lib.glsl"
|
||||
#include "eevee_light_eval.bsl.hh"
|
||||
#include "eevee_lightprobe_eval_lib.glsl"
|
||||
#include "eevee_nodetree_closures_lib.glsl"
|
||||
#include "eevee_reverse_z_lib.bsl.hh"
|
||||
|
|
@ -25,80 +25,81 @@
|
|||
|
||||
/* Allow static compilation of forward materials. */
|
||||
#ifndef CLOSURE_BIN_COUNT
|
||||
# define CLOSURE_BIN_COUNT LIGHT_CLOSURE_EVAL_COUNT
|
||||
# define CLOSURE_BIN_COUNT SRT_CONSTANT_light_closure_eval_count
|
||||
#endif
|
||||
|
||||
#if CLOSURE_BIN_COUNT != LIGHT_CLOSURE_EVAL_COUNT
|
||||
# error Closure data count and eval count must match
|
||||
#ifndef GLSL_CPP_STUBS
|
||||
# if CLOSURE_BIN_COUNT != SRT_CONSTANT_light_closure_eval_count && \
|
||||
SRT_CONSTANT_light_closure_eval_count != 0
|
||||
# error Closure data count and eval count must match
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace eevee {
|
||||
|
||||
void forward_lighting_eval(Thickness thickness,
|
||||
float2 frag_co,
|
||||
float3 &radiance,
|
||||
float3 &transmittance)
|
||||
{
|
||||
[[resource_table]] auto &lights = resource_table_get(eevee::LightEvalIterator);
|
||||
[[resource_table]] LightEvalData &srt = lights.inner;
|
||||
|
||||
float vPz = dot(drw_view_forward(), g_data.P) - dot(drw_view_forward(), drw_view_position());
|
||||
float3 V = drw_world_incident_vector(g_data.P);
|
||||
|
||||
ClosureLightStack stack;
|
||||
for (int i = 0; i < LIGHT_CLOSURE_EVAL_COUNT; i++) {
|
||||
ClosureUndetermined cl = g_closure_get(uchar(i));
|
||||
closure_light_set(stack, uchar(i), closure_light_new(cl, V));
|
||||
light::EvalCtx<false> ctx;
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (srt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
ClosureUndetermined cl = g_closure_get(uchar(i));
|
||||
ctx.stack.cl[i] = closure_light_new(cl, V);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.P = g_data.P;
|
||||
ctx.Ng = g_data.Ng;
|
||||
ctx.V = V;
|
||||
ctx.thickness = thickness;
|
||||
|
||||
/* TODO(fclem): If transmission (no SSS) is present, we could reduce light_closure_eval_count
|
||||
* by 1 for this evaluation and skip evaluating the transmission closure twice. */
|
||||
const auto &infos_buf = buffer_get(draw_object_infos, drw_infos);
|
||||
/* TODO(fclem): If transmission (no SSS) is present, we could reduce LIGHT_CLOSURE_EVAL_COUNT
|
||||
* by 1 for this evaluation and skip evaluating the transmission closure twice. */
|
||||
ObjectInfos object_infos = infos_buf[drw_resource_id()];
|
||||
uchar receiver_light_set = receiver_light_set_get(object_infos);
|
||||
float normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
float geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
light_eval_reflection(
|
||||
stack, g_data.P, g_data.Ng, V, vPz, receiver_light_set, normal_offset, geometry_offset);
|
||||
ctx.receiver_light_set = receiver_light_set_get(object_infos);
|
||||
ctx.terminator_normal_offset = object_infos.shadow_terminator_normal_offset;
|
||||
ctx.terminator_geometry_offset = object_infos.shadow_terminator_geometry_offset;
|
||||
|
||||
#if defined(MAT_SUBSURFACE) || defined(MAT_REFRACTION) || defined(MAT_TRANSLUCENT)
|
||||
|
||||
ClosureUndetermined cl_transmit = g_closure_get(0);
|
||||
if (cl_transmit.type != CLOSURE_NONE_ID) {
|
||||
# if defined(MAT_SUBSURFACE)
|
||||
float3 sss_reflect_shadowed, sss_reflect_unshadowed;
|
||||
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {
|
||||
sss_reflect_shadowed = stack.cl[0].light_shadowed;
|
||||
sss_reflect_unshadowed = stack.cl[0].light_unshadowed;
|
||||
}
|
||||
# endif
|
||||
lights.eval_reflection(ctx, frag_co, vPz);
|
||||
|
||||
if (srt.light_closure_eval_count_transmit > 0) [[static_branch]] {
|
||||
ClosureUndetermined cl_transmit = g_closure_get(0);
|
||||
if (cl_transmit.type == CLOSURE_BSDF_TRANSLUCENT_ID ||
|
||||
cl_transmit.type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID ||
|
||||
cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID)
|
||||
{
|
||||
stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
light::EvalCtx<true> ctx_tr = light::init_from_reflect_ctx(ctx);
|
||||
ctx_tr.stack.cl[0] = closure_light_new(cl_transmit, V, thickness);
|
||||
|
||||
/* NOTE: Only evaluates `stack.cl[0]`. */
|
||||
light_eval_transmission(stack,
|
||||
g_data.P,
|
||||
g_data.Ng,
|
||||
V,
|
||||
vPz,
|
||||
thickness,
|
||||
receiver_light_set,
|
||||
normal_offset,
|
||||
geometry_offset);
|
||||
}
|
||||
lights.eval_transmission(ctx_tr, frag_co, vPz);
|
||||
|
||||
# if defined(MAT_SUBSURFACE)
|
||||
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {
|
||||
/* Apply transmission profile onto transmitted light and sum with reflected light. */
|
||||
float3 sss_profile = subsurface_transmission(to_closure_subsurface(cl_transmit).sss_radius,
|
||||
thickness.value());
|
||||
stack.cl[0].light_shadowed *= sss_profile;
|
||||
stack.cl[0].light_unshadowed *= sss_profile;
|
||||
stack.cl[0].light_shadowed += sss_reflect_shadowed;
|
||||
stack.cl[0].light_unshadowed += sss_reflect_unshadowed;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
if (cl_transmit.type == CLOSURE_BSSRDF_BURLEY_ID) {
|
||||
#if defined(GLSL_CPP_STUBS) || defined(MAT_SUBSURFACE)
|
||||
/* Apply transmission profile onto transmitted light and sum with reflected light. */
|
||||
float3 sss_profile = subsurface_transmission(to_closure_subsurface(cl_transmit).sss_radius,
|
||||
thickness.value());
|
||||
ctx.stack.cl[0].light_shadowed += ctx_tr.stack.cl[0].light_shadowed * sss_profile;
|
||||
ctx.stack.cl[0].light_unshadowed += ctx_tr.stack.cl[0].light_unshadowed * sss_profile;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
ctx.stack.cl[0].light_shadowed = ctx_tr.stack.cl[0].light_shadowed;
|
||||
ctx.stack.cl[0].light_unshadowed = ctx_tr.stack.cl[0].light_unshadowed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LightProbeSample samp = lightprobe_load(frag_co, g_data.P, g_data.Ng, V);
|
||||
|
||||
|
|
@ -106,15 +107,17 @@ void forward_lighting_eval(Thickness thickness,
|
|||
samp.volume_irradiance = spherical_harmonics::clamp_energy(samp.volume_irradiance,
|
||||
clamp_indirect_sh);
|
||||
|
||||
#ifdef MAT_REFLECTION
|
||||
#ifdef MAT_REFLECTION /* Disable if only rough surfaces. */
|
||||
/* Planar reflection. */
|
||||
float3 planar_probe_radiance = float3(0.0f);
|
||||
float3 average_N = g_data.Ng * 0.001f;
|
||||
{
|
||||
/* Get average normal. */
|
||||
for (uchar i = 0; i < LIGHT_CLOSURE_EVAL_COUNT; i++) {
|
||||
ClosureUndetermined cl = g_closure_get(i);
|
||||
average_N += cl.N * cl.weight;
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (srt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
ClosureUndetermined cl = g_closure_get(uchar(i));
|
||||
average_N += cl.N * cl.weight;
|
||||
}
|
||||
}
|
||||
average_N = safe_normalize(average_N);
|
||||
|
||||
|
|
@ -145,30 +148,33 @@ void forward_lighting_eval(Thickness thickness,
|
|||
/* Combine all radiance. */
|
||||
float3 radiance_direct = float3(0.0f);
|
||||
float3 radiance_indirect = float3(0.0f);
|
||||
for (uchar i = 0; i < LIGHT_CLOSURE_EVAL_COUNT; i++) {
|
||||
ClosureUndetermined cl = g_closure_get_resolved(i, 1.0f);
|
||||
if (cl.weight > CLOSURE_WEIGHT_CUTOFF) {
|
||||
float3 direct_light = closure_light_get(stack, i).light_shadowed;
|
||||
float3 indirect_light = lightprobe_eval(samp, cl, g_data.P, V, thickness);
|
||||
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (srt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
ClosureUndetermined cl = g_closure_get_resolved(uchar(i), 1.0f);
|
||||
if (cl.weight > CLOSURE_WEIGHT_CUTOFF) {
|
||||
float3 direct_light = ctx.stack.cl[i].light_shadowed;
|
||||
float3 indirect_light = lightprobe_eval(samp, cl, g_data.P, V, thickness);
|
||||
|
||||
#ifdef MAT_REFLECTION
|
||||
if (cl.type == CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID) {
|
||||
const float blend = saturate(to_closure_reflection(cl).roughness * -10.0f + 1.0f) *
|
||||
saturate(dot(average_N, cl.N) * 100.0f - 99.0f);
|
||||
indirect_light = mix(indirect_light, planar_probe_radiance, blend);
|
||||
}
|
||||
if (cl.type == CLOSURE_BSDF_MICROFACET_GGX_REFLECTION_ID) {
|
||||
const float blend = saturate(to_closure_reflection(cl).roughness * -10.0f + 1.0f) *
|
||||
saturate(dot(average_N, cl.N) * 100.0f - 99.0f);
|
||||
indirect_light = mix(indirect_light, planar_probe_radiance, blend);
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((cl.type == CLOSURE_BSDF_TRANSLUCENT_ID ||
|
||||
cl.type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) &&
|
||||
(thickness.value() != 0.0f))
|
||||
{
|
||||
/* We model two transmission event, so the surface color need to be applied twice. */
|
||||
cl.color *= cl.color;
|
||||
}
|
||||
if ((cl.type == CLOSURE_BSDF_TRANSLUCENT_ID ||
|
||||
cl.type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID) &&
|
||||
(thickness.value() != 0.0f))
|
||||
{
|
||||
/* We model two transmission event, so the surface color need to be applied twice. */
|
||||
cl.color *= cl.color;
|
||||
}
|
||||
|
||||
radiance_direct += direct_light * cl.color;
|
||||
radiance_indirect += indirect_light * cl.color;
|
||||
radiance_direct += direct_light * cl.color;
|
||||
radiance_indirect += indirect_light * cl.color;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Light clamping. */
|
||||
|
|
@ -185,3 +191,5 @@ void forward_lighting_eval(Thickness thickness,
|
|||
|
||||
transmittance = g_transmittance;
|
||||
}
|
||||
|
||||
} // namespace eevee
|
||||
|
|
|
|||
|
|
@ -5,15 +5,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "infos/eevee_common_infos.hh"
|
||||
#include "infos/eevee_light_infos.hh"
|
||||
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_hiz_data)
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_light_data)
|
||||
|
||||
#include "draw_intersect_lib.glsl"
|
||||
#include "draw_shape_lib.glsl"
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_iter.bsl.hh"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_light_shared.hh"
|
||||
#include "gpu_shader_debug_gradients_lib.glsl"
|
||||
|
|
@ -469,7 +467,6 @@ struct DebugFragOut {
|
|||
|
||||
struct Debug {
|
||||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
};
|
||||
|
||||
|
|
@ -481,8 +478,59 @@ void debug_vert([[vertex_id]] const int vert_id,
|
|||
fullscreen_vertex(vert_id, out_position, v_out.screen_uv);
|
||||
}
|
||||
|
||||
struct NoCullCtx {
|
||||
float light_count;
|
||||
uint light_bits;
|
||||
|
||||
void eval_directional([[resource_table]] LightRenderData & /*lrd*/,
|
||||
uint /*l_idx*/,
|
||||
LightData /*light*/)
|
||||
{
|
||||
}
|
||||
|
||||
void eval_local([[resource_table]] LightRenderData &lrd, uint l_idx, LightData /*light*/)
|
||||
{
|
||||
light_bits |= 1u << l_idx;
|
||||
light_count += 1.0f;
|
||||
}
|
||||
};
|
||||
|
||||
struct WithCullCtx {
|
||||
uint light_bits;
|
||||
float3 P;
|
||||
|
||||
void eval_directional([[resource_table]] LightRenderData & /*lrd*/,
|
||||
uint /*l_idx*/,
|
||||
LightData /*light*/)
|
||||
{
|
||||
}
|
||||
|
||||
void eval_local([[resource_table]] LightRenderData &lrd, uint l_idx, LightData light)
|
||||
{
|
||||
LightVector lv = light_vector_get(light, false, P);
|
||||
if (light_attenuation_surface(light, false, lv) > LIGHT_ATTENUATION_THRESHOLD) {
|
||||
light_bits |= 1u << l_idx;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace eevee::light::culling
|
||||
|
||||
namespace eevee::light {
|
||||
|
||||
template void light::foreach<culling::NoCullCtx, LightRenderData>(const LightRenderData &,
|
||||
culling::NoCullCtx &,
|
||||
LightRenderData &);
|
||||
|
||||
template void light::foreach_visible<culling::WithCullCtx, LightRenderData>(
|
||||
const LightRenderData &, float2, float, culling::WithCullCtx &, LightRenderData &);
|
||||
|
||||
} // namespace eevee::light
|
||||
|
||||
namespace eevee::light::culling {
|
||||
[[fragment]]
|
||||
void debug_frag([[resource_table]] Debug & /*srt*/,
|
||||
[[resource_table]] LightRenderData &lrd,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[in]] const DebugVertOut &v_out,
|
||||
[[out]] DebugFragOut &frag_out)
|
||||
|
|
@ -493,29 +541,15 @@ void debug_frag([[resource_table]] Debug & /*srt*/,
|
|||
float vP_z = drw_depth_screen_to_view(depth);
|
||||
float3 P = drw_point_screen_to_world(float3(v_out.screen_uv, depth));
|
||||
|
||||
float light_count = 0.0f;
|
||||
uint light_cull = 0u;
|
||||
float2 px = frag_co.xy;
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, px, vP_z, l_idx) {
|
||||
light_cull |= 1u << l_idx;
|
||||
light_count += 1.0f;
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
NoCullCtx no_cull = {};
|
||||
light::foreach(lrd, no_cull, lrd);
|
||||
|
||||
uint light_nocull = 0u;
|
||||
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(light_cull_buf, l_idx)
|
||||
{
|
||||
LightData light = light_buf[l_idx];
|
||||
LightVector lv = light_vector_get(light, false, P);
|
||||
if (light_attenuation_surface(light, false, lv) > LIGHT_ATTENUATION_THRESHOLD) {
|
||||
light_nocull |= 1u << l_idx;
|
||||
}
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
WithCullCtx with_cull = {.P = P};
|
||||
light::foreach_visible(lrd, frag_co.xy, vP_z, with_cull, lrd);
|
||||
|
||||
float4 color = float4(heatmap_gradient(light_count / 4.0f), 1.0f);
|
||||
float4 color = float4(heatmap_gradient(no_cull.light_count / 4.0f), 1.0f);
|
||||
|
||||
if ((light_cull & light_nocull) != light_nocull) {
|
||||
if ((with_cull.light_bits & no_cull.light_bits) != no_cull.light_bits) {
|
||||
/* ERROR. Some lights were culled incorrectly. */
|
||||
color = float4(0.0f, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_shader_compat.hh"
|
||||
|
||||
#include "eevee_light_shared.hh"
|
||||
#include "eevee_shadow_shared.hh"
|
||||
|
||||
namespace eevee {
|
||||
|
||||
struct LightRenderData {
|
||||
[[storage(LIGHT_CULL_BUF_SLOT, read)]] const LightCullingData &light_cull_buf;
|
||||
[[storage(LIGHT_BUF_SLOT, read)]] const LightData (&light_buf)[];
|
||||
[[storage(LIGHT_ZBIN_BUF_SLOT, read)]] const uint (&light_zbin_buf)[];
|
||||
[[storage(LIGHT_TILE_BUF_SLOT, read)]] const uint (&light_tile_buf)[];
|
||||
};
|
||||
|
||||
} // namespace eevee
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "eevee_bxdf_lib.glsl"
|
||||
#include "eevee_closure_lib.glsl"
|
||||
#include "eevee_light_iter.bsl.hh"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_shadow.bsl.hh"
|
||||
#include "eevee_shadow_tracing.bsl.hh"
|
||||
#include "eevee_thickness_lib.bsl.hh"
|
||||
#include "gpu_shader_codegen_lib.glsl"
|
||||
#include "gpu_shader_utildefines_lib.glsl"
|
||||
|
||||
#if !defined(SRT_CONSTANT_light_closure_eval_count_reflect)
|
||||
# define SRT_CONSTANT_light_closure_eval_count_reflect 0
|
||||
#endif
|
||||
#if !defined(SRT_CONSTANT_light_closure_eval_count_transmit)
|
||||
# define SRT_CONSTANT_light_closure_eval_count_transmit 0
|
||||
#endif
|
||||
|
||||
#ifdef GLSL_CPP_STUBS
|
||||
# define LIGHT_STACK_SIZE_REFLECT 3
|
||||
#elif SRT_CONSTANT_light_closure_eval_count_reflect == 0
|
||||
# define LIGHT_STACK_SIZE_REFLECT 1 /* Avoid compilation error. */
|
||||
#else
|
||||
# define LIGHT_STACK_SIZE_REFLECT SRT_CONSTANT_light_closure_eval_count_reflect
|
||||
#endif
|
||||
|
||||
#ifdef GLSL_CPP_STUBS
|
||||
# define LIGHT_STACK_SIZE_TRANSMIT 3
|
||||
#elif SRT_CONSTANT_light_closure_eval_count_transmit == 0
|
||||
# define LIGHT_STACK_SIZE_TRANSMIT 1 /* Avoid compilation error. */
|
||||
#else
|
||||
# define LIGHT_STACK_SIZE_TRANSMIT SRT_CONSTANT_light_closure_eval_count_transmit
|
||||
#endif
|
||||
|
||||
namespace eevee {
|
||||
|
||||
struct LightEvalData {
|
||||
[[resource_table]] srt_t<ShadowRenderData> shadow_data;
|
||||
|
||||
[[compilation_constant]] int light_closure_eval_count_reflect;
|
||||
[[compilation_constant]] int light_closure_eval_count_transmit;
|
||||
};
|
||||
|
||||
namespace light {
|
||||
|
||||
template<bool is_transmission> struct ClosureStack {};
|
||||
|
||||
template<> struct ClosureStack<false> {
|
||||
ClosureLight cl[LIGHT_STACK_SIZE_REFLECT];
|
||||
};
|
||||
|
||||
template<> struct ClosureStack<true> {
|
||||
ClosureLight cl[LIGHT_STACK_SIZE_TRANSMIT];
|
||||
};
|
||||
|
||||
float power_get(LightData light, LightingType type)
|
||||
{
|
||||
/* Mask anything above 3. See LIGHT_TRANSLUCENT_WITH_THICKNESS. */
|
||||
return light.power[type & 3u];
|
||||
}
|
||||
|
||||
bool light_linking_affects_receiver(uint2 light_set_membership, uchar receiver_light_set)
|
||||
{
|
||||
return bitmask64_test(light_set_membership, receiver_light_set);
|
||||
}
|
||||
|
||||
void eval_single_closure(
|
||||
LightData light, LightVector lv, ClosureLight &cl, float3 V, float attenuation, float shadow)
|
||||
{
|
||||
attenuation *= power_get(light, cl.type);
|
||||
if (attenuation < 1e-30f) {
|
||||
return;
|
||||
}
|
||||
auto &util_tx = sampler_get(eevee_utility_texture, utility_tx);
|
||||
float ltc_result = light_ltc(util_tx, light, cl.N, V, lv, cl.ltc_mat);
|
||||
float3 out_radiance = light.color * ltc_result;
|
||||
float visibility = shadow * attenuation;
|
||||
cl.light_shadowed += visibility * out_radiance;
|
||||
cl.light_unshadowed += attenuation * out_radiance;
|
||||
}
|
||||
|
||||
template<bool is_transmission> struct EvalCtx {
|
||||
ClosureStack<is_transmission> stack;
|
||||
|
||||
float3 P;
|
||||
float3 Ng;
|
||||
float3 V;
|
||||
Thickness thickness;
|
||||
uchar receiver_light_set;
|
||||
float terminator_normal_offset;
|
||||
float terminator_geometry_offset;
|
||||
|
||||
void light_eval_single([[resource_table]] LightEvalData &srt,
|
||||
LightData light,
|
||||
const bool is_directional)
|
||||
{
|
||||
[[resource_table]] ShadowRenderData &srd = srt.shadow_data;
|
||||
|
||||
if (!light_linking_affects_receiver(light.light_set_membership, receiver_light_set)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(SPECIALIZED_SHADOW_PARAMS) || defined(SRT_CONSTANT_shadow_ray_count)
|
||||
int ray_count = shadow_ray_count;
|
||||
int ray_step_count = shadow_ray_step_count;
|
||||
#else
|
||||
int ray_count = uniform_buf.shadow.ray_count;
|
||||
int ray_step_count = uniform_buf.shadow.step_count;
|
||||
#endif
|
||||
|
||||
LightVector lv = light_vector_get(light, is_directional, P);
|
||||
|
||||
/* TODO(fclem): Get rid of this special case. */
|
||||
bool is_translucent_with_thickness = is_transmission &&
|
||||
(stack.cl[0].type == LIGHT_TRANSLUCENT_WITH_THICKNESS);
|
||||
|
||||
float attenuation = light_attenuation_surface(light, is_directional, lv);
|
||||
float facing = light_attenuation_facing(light, lv.L, lv.dist, stack.cl[0].N, is_transmission);
|
||||
|
||||
if (!is_translucent_with_thickness) {
|
||||
/* Only do attenuation for this case, since we integrate the whole sphere for translucency.
|
||||
* Moreover, stack.cl[0].N is overwritten for is_translucent_with_thickness. */
|
||||
attenuation *= facing;
|
||||
}
|
||||
|
||||
if (attenuation < LIGHT_ATTENUATION_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
float shadow = 1.0f;
|
||||
if (light.tilemap_index != LIGHT_NO_SHADOW) {
|
||||
shadow = shadow_eval(srd,
|
||||
light,
|
||||
is_directional,
|
||||
is_transmission,
|
||||
is_translucent_with_thickness,
|
||||
thickness,
|
||||
P,
|
||||
Ng,
|
||||
stack.cl[0].N,
|
||||
terminator_normal_offset,
|
||||
terminator_geometry_offset,
|
||||
ray_count,
|
||||
ray_step_count);
|
||||
}
|
||||
|
||||
if (is_translucent_with_thickness) {
|
||||
/* This makes the LTC compute the solid angle of the light (still with the cosine term
|
||||
* applied but that still works great enough in practice). */
|
||||
stack.cl[0].N = lv.L;
|
||||
/* Adjust power because of the second lambertian distribution. */
|
||||
attenuation *= M_1_PI;
|
||||
}
|
||||
|
||||
for (uint i = 0u; i < 3; i++) [[unroll]] {
|
||||
if (is_transmission) [[static_branch]] {
|
||||
if (srt.light_closure_eval_count_transmit > i) [[static_branch]] {
|
||||
eval_single_closure(light, lv, stack.cl[i], V, attenuation, shadow);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (srt.light_closure_eval_count_reflect > i) [[static_branch]] {
|
||||
eval_single_closure(light, lv, stack.cl[i], V, attenuation, shadow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eval_directional([[resource_table]] LightEvalData &srt, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
light_eval_single(srt, light, true);
|
||||
}
|
||||
|
||||
void eval_local([[resource_table]] LightEvalData &srt, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
light_eval_single(srt, light, false);
|
||||
}
|
||||
};
|
||||
|
||||
template struct EvalCtx<true>;
|
||||
template struct EvalCtx<false>;
|
||||
|
||||
template void foreach_visible<EvalCtx<true>, LightEvalData>(
|
||||
const LightRenderData &, float2, float, EvalCtx<true> &, LightEvalData &);
|
||||
template void foreach_visible<EvalCtx<false>, LightEvalData>(
|
||||
const LightRenderData &, float2, float, EvalCtx<false> &, LightEvalData &);
|
||||
|
||||
/* NOTE: Doesn't init the closure stack. */
|
||||
EvalCtx<true> init_from_reflect_ctx(EvalCtx<false> ctx)
|
||||
{
|
||||
EvalCtx<true> ctx_tr;
|
||||
ctx_tr.P = ctx.P;
|
||||
ctx_tr.Ng = ctx.Ng;
|
||||
ctx_tr.V = ctx.V;
|
||||
ctx_tr.thickness = ctx.thickness;
|
||||
ctx_tr.receiver_light_set = ctx.receiver_light_set;
|
||||
ctx_tr.terminator_normal_offset = ctx.terminator_normal_offset;
|
||||
ctx_tr.terminator_geometry_offset = ctx.terminator_geometry_offset;
|
||||
return ctx_tr;
|
||||
}
|
||||
|
||||
} // namespace light
|
||||
|
||||
struct LightEvalIterator {
|
||||
[[resource_table]] srt_t<LightEvalData> inner;
|
||||
[[resource_table]] srt_t<LightRenderData> light_data;
|
||||
|
||||
void eval_reflection(light::EvalCtx<false> &ctx, float2 pixel, float vPz)
|
||||
{
|
||||
[[resource_table]] LightEvalData &srt = inner;
|
||||
if (srt.light_closure_eval_count_reflect > 0) [[static_branch]] {
|
||||
light::foreach_visible(light_data, pixel, vPz, ctx, srt);
|
||||
}
|
||||
}
|
||||
|
||||
void eval_transmission(light::EvalCtx<true> &ctx, float2 pixel, float vPz)
|
||||
{
|
||||
[[resource_table]] LightEvalData &srt = inner;
|
||||
if (srt.light_closure_eval_count_transmit > 0) [[static_branch]] {
|
||||
light::foreach_visible(light_data, pixel, vPz, ctx, srt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace eevee
|
||||
|
|
@ -1,295 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* The resources expected to be defined are:
|
||||
* - light_buf
|
||||
* - light_zbin_buf
|
||||
* - light_cull_buf
|
||||
* - light_tile_buf
|
||||
* - shadow_atlas_tx
|
||||
* - shadow_tilemaps_tx
|
||||
* - utility_tx
|
||||
*/
|
||||
|
||||
#include "infos/eevee_common_infos.hh"
|
||||
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_light_data)
|
||||
|
||||
#include "eevee_bxdf_lib.glsl"
|
||||
#include "eevee_closure_lib.glsl"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_shadow_lib.glsl"
|
||||
#include "eevee_shadow_tracing_lib.glsl"
|
||||
#include "eevee_thickness_lib.bsl.hh"
|
||||
#include "gpu_shader_codegen_lib.glsl"
|
||||
#include "gpu_shader_utildefines_lib.glsl"
|
||||
|
||||
/* If using compute, the shader should define its own pixel. */
|
||||
#if !defined(PIXEL) && defined(GPU_FRAGMENT_SHADER)
|
||||
# define PIXEL gl_FragCoord.xy
|
||||
#elif !defined(GPU_COMPUTE_SHADER)
|
||||
# define PIXEL float2(0)
|
||||
#endif
|
||||
|
||||
#ifdef GLSL_CPP_STUBS
|
||||
# define LIGHT_CLOSURE_EVAL_COUNT 3
|
||||
#endif
|
||||
|
||||
/* For forward compatibility until everything is ported to BSL. */
|
||||
#ifdef SRT_CONSTANT_light_closure_eval_count
|
||||
# define LIGHT_CLOSURE_EVAL_COUNT SRT_CONSTANT_light_closure_eval_count
|
||||
#endif
|
||||
|
||||
#if !defined(LIGHT_CLOSURE_EVAL_COUNT)
|
||||
# define LIGHT_CLOSURE_EVAL_COUNT 1
|
||||
# define SKIP_LIGHT_EVAL
|
||||
#endif
|
||||
|
||||
struct ClosureLightStack {
|
||||
/* NOTE: This is wrapped into a struct to avoid array shenanigans on MSL. */
|
||||
ClosureLight cl[LIGHT_CLOSURE_EVAL_COUNT];
|
||||
};
|
||||
|
||||
ClosureLight closure_light_get(ClosureLightStack stack, uchar index)
|
||||
{
|
||||
switch (index) {
|
||||
case 0:
|
||||
return stack.cl[0];
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 1
|
||||
case 1:
|
||||
return stack.cl[1];
|
||||
#endif
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 2
|
||||
case 2:
|
||||
return stack.cl[2];
|
||||
#endif
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 3
|
||||
# error
|
||||
#endif
|
||||
}
|
||||
ClosureLight closure_null;
|
||||
return closure_null;
|
||||
}
|
||||
|
||||
void closure_light_set(ClosureLightStack &stack, uchar index, ClosureLight cl_light)
|
||||
{
|
||||
switch (index) {
|
||||
case 0:
|
||||
stack.cl[0] = cl_light;
|
||||
break;
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 1
|
||||
case 1:
|
||||
stack.cl[1] = cl_light;
|
||||
break;
|
||||
#endif
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 2
|
||||
case 2:
|
||||
stack.cl[2] = cl_light;
|
||||
break;
|
||||
#endif
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 3
|
||||
# error
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
float light_power_get(LightData light, LightingType type)
|
||||
{
|
||||
/* Mask anything above 3. See LIGHT_TRANSLUCENT_WITH_THICKNESS. */
|
||||
return light.power[type & 3u];
|
||||
}
|
||||
|
||||
bool light_linking_affects_receiver(uint2 light_set_membership, uchar receiver_light_set)
|
||||
{
|
||||
return bitmask64_test(light_set_membership, receiver_light_set);
|
||||
}
|
||||
|
||||
void light_eval_single_closure(
|
||||
LightData light, LightVector lv, ClosureLight &cl, float3 V, float attenuation, float shadow)
|
||||
{
|
||||
attenuation *= light_power_get(light, cl.type);
|
||||
if (attenuation < 1e-30f) {
|
||||
return;
|
||||
}
|
||||
float ltc_result = light_ltc(utility_tx, light, cl.N, V, lv, cl.ltc_mat);
|
||||
float3 out_radiance = light.color * ltc_result;
|
||||
float visibility = shadow * attenuation;
|
||||
cl.light_shadowed += visibility * out_radiance;
|
||||
cl.light_unshadowed += attenuation * out_radiance;
|
||||
}
|
||||
|
||||
void light_eval_single(uint l_idx,
|
||||
const bool is_directional,
|
||||
const bool is_transmission,
|
||||
ClosureLightStack &stack,
|
||||
float3 P,
|
||||
float3 Ng,
|
||||
float3 V,
|
||||
Thickness thickness,
|
||||
uchar receiver_light_set,
|
||||
float terminator_normal_offset,
|
||||
float terminator_geometry_offset)
|
||||
{
|
||||
LightData light = light_buf[l_idx];
|
||||
|
||||
if (!light_linking_affects_receiver(light.light_set_membership, receiver_light_set)) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(SPECIALIZED_SHADOW_PARAMS) || defined(SRT_CONSTANT_shadow_ray_count)
|
||||
int ray_count = shadow_ray_count;
|
||||
int ray_step_count = shadow_ray_step_count;
|
||||
#else
|
||||
int ray_count = uniform_buf.shadow.ray_count;
|
||||
int ray_step_count = uniform_buf.shadow.step_count;
|
||||
#endif
|
||||
|
||||
LightVector lv = light_vector_get(light, is_directional, P);
|
||||
|
||||
/* TODO(fclem): Get rid of this special case. */
|
||||
bool is_translucent_with_thickness = is_transmission &&
|
||||
(stack.cl[0].type == LIGHT_TRANSLUCENT_WITH_THICKNESS);
|
||||
|
||||
float attenuation = light_attenuation_surface(light, is_directional, lv);
|
||||
|
||||
if (!is_translucent_with_thickness) {
|
||||
/* Only do attenuation for this case, since we integrate the whole sphere for translucency.
|
||||
* Moreover, stack.cl[0].N is overwritten for is_translucent_with_thickness. */
|
||||
attenuation *= light_attenuation_facing(light, lv.L, lv.dist, stack.cl[0].N, is_transmission);
|
||||
}
|
||||
|
||||
if (attenuation < LIGHT_ATTENUATION_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
float shadow = 1.0f;
|
||||
if (light.tilemap_index != LIGHT_NO_SHADOW) {
|
||||
shadow = shadow_eval(light,
|
||||
is_directional,
|
||||
is_transmission,
|
||||
is_translucent_with_thickness,
|
||||
thickness,
|
||||
P,
|
||||
Ng,
|
||||
stack.cl[0].N,
|
||||
terminator_normal_offset,
|
||||
terminator_geometry_offset,
|
||||
ray_count,
|
||||
ray_step_count);
|
||||
}
|
||||
|
||||
if (is_translucent_with_thickness) {
|
||||
/* This makes the LTC compute the solid angle of the light (still with the cosine term applied
|
||||
* but that still works great enough in practice). */
|
||||
stack.cl[0].N = lv.L;
|
||||
/* Adjust power because of the second lambertian distribution. */
|
||||
attenuation *= M_1_PI;
|
||||
}
|
||||
|
||||
light_eval_single_closure(light, lv, stack.cl[0], V, attenuation, shadow);
|
||||
if (!is_transmission) {
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 1
|
||||
light_eval_single_closure(light, lv, stack.cl[1], V, attenuation, shadow);
|
||||
#endif
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 2
|
||||
light_eval_single_closure(light, lv, stack.cl[2], V, attenuation, shadow);
|
||||
#endif
|
||||
#if LIGHT_CLOSURE_EVAL_COUNT > 3
|
||||
# error
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void light_eval_transmission(ClosureLightStack &stack,
|
||||
float3 P,
|
||||
float3 Ng,
|
||||
float3 V,
|
||||
[[maybe_unused]] float vPz,
|
||||
Thickness thickness,
|
||||
uchar receiver_light_set,
|
||||
float terminator_normal_offset,
|
||||
float terminator_geometry_offset)
|
||||
{
|
||||
#ifdef SKIP_LIGHT_EVAL
|
||||
return;
|
||||
#endif
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
light_eval_single(l_idx,
|
||||
true,
|
||||
true,
|
||||
stack,
|
||||
P,
|
||||
Ng,
|
||||
V,
|
||||
thickness,
|
||||
receiver_light_set,
|
||||
terminator_normal_offset,
|
||||
terminator_geometry_offset);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, PIXEL, vPz, l_idx) {
|
||||
light_eval_single(l_idx,
|
||||
false,
|
||||
true,
|
||||
stack,
|
||||
P,
|
||||
Ng,
|
||||
V,
|
||||
thickness,
|
||||
receiver_light_set,
|
||||
terminator_normal_offset,
|
||||
terminator_geometry_offset);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
}
|
||||
|
||||
void light_eval_reflection(ClosureLightStack &stack,
|
||||
float3 P,
|
||||
float3 Ng,
|
||||
float3 V,
|
||||
[[maybe_unused]] float vPz,
|
||||
uchar receiver_light_set,
|
||||
float terminator_normal_offset,
|
||||
float terminator_geometry_offset)
|
||||
{
|
||||
#ifdef SKIP_LIGHT_EVAL
|
||||
return;
|
||||
#endif
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
light_eval_single(l_idx,
|
||||
true,
|
||||
false,
|
||||
stack,
|
||||
P,
|
||||
Ng,
|
||||
V,
|
||||
Thickness::zero(),
|
||||
receiver_light_set,
|
||||
terminator_normal_offset,
|
||||
terminator_geometry_offset);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, PIXEL, vPz, l_idx) {
|
||||
light_eval_single(l_idx,
|
||||
false,
|
||||
false,
|
||||
stack,
|
||||
P,
|
||||
Ng,
|
||||
V,
|
||||
Thickness::zero(),
|
||||
receiver_light_set,
|
||||
terminator_normal_offset,
|
||||
terminator_geometry_offset);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_shader_compat.hh"
|
||||
|
||||
#include "eevee_light_data.bsl.hh"
|
||||
|
||||
namespace eevee::light {
|
||||
|
||||
uint bitfield_mask(uint bit_width, uint bit_min)
|
||||
{
|
||||
/* Cannot bit shift more than 31 positions. */
|
||||
uint mask = (bit_width > 31u) ? 0x0u : (0xFFFFFFFFu << bit_width);
|
||||
return ~mask << bit_min;
|
||||
}
|
||||
|
||||
uint zbin_mask(uint word_index, uint zbin_min, uint zbin_max)
|
||||
{
|
||||
uint word_start = word_index * 32u;
|
||||
uint word_end = word_start + 31u;
|
||||
uint local_min = max(zbin_min, word_start);
|
||||
uint local_max = min(zbin_max, word_end);
|
||||
uint mask_width = local_max - local_min + 1;
|
||||
return bitfield_mask(mask_width, local_min);
|
||||
}
|
||||
|
||||
int culling_z_to_zbin(float scale, float bias, float z)
|
||||
{
|
||||
return int(z * scale + bias);
|
||||
}
|
||||
|
||||
/* To be instantiated with a callback class that implement eval_directional and eval_local.
|
||||
* If ResourceT is not needed, just pass LightRenderData again. */
|
||||
template<typename CallbackT, typename ResourceT>
|
||||
void foreach([[resource_table]] const LightRenderData &srt,
|
||||
CallbackT &cb,
|
||||
[[resource_table]] ResourceT &res)
|
||||
{
|
||||
const LightCullingData &culling = srt.light_cull_buf;
|
||||
|
||||
for (uint index = culling.local_lights_len; index < culling.items_count; index++) {
|
||||
LightData light = srt.light_buf[index];
|
||||
cb.eval_directional(res, index, light);
|
||||
}
|
||||
|
||||
for (uint index = 0; index < culling.visible_count; index++) {
|
||||
LightData light = srt.light_buf[index];
|
||||
cb.eval_local(res, index, light);
|
||||
}
|
||||
}
|
||||
|
||||
/* To be instantiated with a callback class that implement eval_directional and eval_local.
|
||||
* If ResourceT is not needed, just pass LightRenderData again. */
|
||||
template<typename CallbackT, typename ResourceT>
|
||||
void foreach_visible([[resource_table]] const LightRenderData &srt,
|
||||
float2 pixel,
|
||||
float linear_view_z,
|
||||
CallbackT &cb,
|
||||
[[resource_table]] ResourceT &res)
|
||||
{
|
||||
const LightCullingData &culling = srt.light_cull_buf;
|
||||
const auto &zbins = srt.light_zbin_buf;
|
||||
const auto &words = srt.light_tile_buf;
|
||||
|
||||
for (uint index = culling.local_lights_len; index < culling.items_count; index++) {
|
||||
LightData light = srt.light_buf[index];
|
||||
cb.eval_directional(res, index, light);
|
||||
}
|
||||
|
||||
/* WORKAROUND: For Surfels to use the same lighting path. Could be improved. */
|
||||
#ifdef SRT_CONSTANT_light_iter_force_no_culling
|
||||
/* Same as light::foreach. */
|
||||
for (uint index = 0; index < culling.visible_count; index++) {
|
||||
LightData light = srt.light_buf[index];
|
||||
cb.eval_local(res, index, light);
|
||||
}
|
||||
return;
|
||||
#endif
|
||||
|
||||
{
|
||||
uint2 tile_co = uint2(pixel / culling.tile_size);
|
||||
uint tile_word_offset = (tile_co.x + tile_co.y * culling.tile_x_len) * culling.tile_word_len;
|
||||
int zbin_index = culling_z_to_zbin(culling.zbin_scale, culling.zbin_bias, linear_view_z);
|
||||
zbin_index = clamp(zbin_index, 0, CULLING_ZBIN_COUNT - 1);
|
||||
uint zbin_data = zbins[zbin_index];
|
||||
uint min_index = zbin_data & 0xFFFFu;
|
||||
uint max_index = zbin_data >> 16u;
|
||||
/* Ensure all threads inside a subgroup get the same value to reduce VGPR usage. */
|
||||
#ifdef GPU_METAL
|
||||
/* Waiting to implement extensions support. We need:
|
||||
* - GL_KHR_shader_subgroup_ballot
|
||||
* - GL_KHR_shader_subgroup_arithmetic
|
||||
* or
|
||||
* - Vulkan 1.1
|
||||
*/
|
||||
min_index = simd_broadcast_first(simd_min(min_index));
|
||||
max_index = simd_broadcast_first(simd_max(max_index));
|
||||
#endif
|
||||
/* Same as divide by 32 but avoid integer division. */
|
||||
uint word_min = min_index >> 5u;
|
||||
uint word_max = max_index >> 5u;
|
||||
for (uint word_idx = word_min; word_idx <= word_max; word_idx++) {
|
||||
uint word = words[tile_word_offset + word_idx];
|
||||
word &= zbin_mask(word_idx, min_index, max_index);
|
||||
/* Ensure all threads inside a subgroup get the same value to reduce VGPR usage. */
|
||||
#ifdef GPU_METAL
|
||||
/* Waiting to implement extensions support. We need:
|
||||
* - GL_KHR_shader_subgroup_ballot
|
||||
* - GL_KHR_shader_subgroup_arithmetic
|
||||
* or
|
||||
* - Vulkan 1.1
|
||||
*/
|
||||
word = simd_broadcast_first(simd_or(word));
|
||||
#endif
|
||||
int bit_index;
|
||||
while ((bit_index = findLSB(word)) != -1) {
|
||||
word &= ~1u << uint(bit_index);
|
||||
uint index = word_idx * 32u + uint(bit_index);
|
||||
LightData light = srt.light_buf[index];
|
||||
cb.eval_local(res, index, light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace eevee::light
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpu_shader_compat.hh"
|
||||
|
||||
/* For forward compatibility until everything is ported to BSL. */
|
||||
#ifdef SRT_CONSTANT_light_iter_force_no_culling
|
||||
# define LIGHT_ITER_FORCE_NO_CULLING SRT_CONSTANT_light_iter_force_no_culling
|
||||
#endif
|
||||
|
||||
uint bitfield_mask(uint bit_width, uint bit_min)
|
||||
{
|
||||
/* Cannot bit shift more than 31 positions. */
|
||||
uint mask = (bit_width > 31u) ? 0x0u : (0xFFFFFFFFu << bit_width);
|
||||
return ~mask << bit_min;
|
||||
}
|
||||
|
||||
uint zbin_mask(uint word_index, uint zbin_min, uint zbin_max)
|
||||
{
|
||||
uint word_start = word_index * 32u;
|
||||
uint word_end = word_start + 31u;
|
||||
uint local_min = max(zbin_min, word_start);
|
||||
uint local_max = min(zbin_max, word_end);
|
||||
uint mask_width = local_max - local_min + 1;
|
||||
return bitfield_mask(mask_width, local_min);
|
||||
}
|
||||
|
||||
int culling_z_to_zbin(float scale, float bias, float z)
|
||||
{
|
||||
return int(z * scale + bias);
|
||||
}
|
||||
|
||||
/* Waiting to implement extensions support. We need:
|
||||
* - GL_KHR_shader_subgroup_ballot
|
||||
* - GL_KHR_shader_subgroup_arithmetic
|
||||
* or
|
||||
* - Vulkan 1.1
|
||||
*/
|
||||
#ifdef GPU_METAL
|
||||
# define subgroupMin(a) simd_min(a)
|
||||
# define subgroupMax(a) simd_max(a)
|
||||
# define subgroupOr(a) simd_or(a)
|
||||
# define subgroupBroadcastFirst(a) simd_broadcast_first(a)
|
||||
#else
|
||||
# define subgroupMin(a) a
|
||||
# define subgroupMax(a) a
|
||||
# define subgroupOr(a) a
|
||||
# define subgroupBroadcastFirst(a) a
|
||||
#endif
|
||||
|
||||
#define LIGHT_FOREACH_BEGIN_DIRECTIONAL(_culling, _index) \
|
||||
{ \
|
||||
{ \
|
||||
for (uint _index = _culling.local_lights_len; _index < _culling.items_count; _index++) {
|
||||
|
||||
/* No culling. Iterate over all items. */
|
||||
#define LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(_culling, _item_index) \
|
||||
{ \
|
||||
{ \
|
||||
for (uint _item_index = 0; _item_index < _culling.visible_count; _item_index++) {
|
||||
|
||||
#ifdef LIGHT_ITER_FORCE_NO_CULLING
|
||||
|
||||
/* Skip the optimization structure traversal for cases where the acceleration structure
|
||||
* doesn't match. */
|
||||
# define LIGHT_FOREACH_BEGIN_LOCAL(_culling, _zbins, _words, _pixel, _linearz, _item_index) \
|
||||
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(_culling, _item_index)
|
||||
|
||||
#else
|
||||
|
||||
# define LIGHT_FOREACH_BEGIN_LOCAL(_culling, _zbins, _words, _pixel, _linearz, _item_index) \
|
||||
{ \
|
||||
uint2 tile_co = uint2(_pixel / _culling.tile_size); \
|
||||
uint tile_word_offset = (tile_co.x + tile_co.y * _culling.tile_x_len) * \
|
||||
_culling.tile_word_len; \
|
||||
int zbin_index = culling_z_to_zbin(_culling.zbin_scale, _culling.zbin_bias, _linearz); \
|
||||
zbin_index = clamp(zbin_index, 0, CULLING_ZBIN_COUNT - 1); \
|
||||
uint zbin_data = _zbins[zbin_index]; \
|
||||
uint min_index = zbin_data & 0xFFFFu; \
|
||||
uint max_index = zbin_data >> 16u; \
|
||||
/* Ensure all threads inside a subgroup get the same value to reduce VGPR usage. */ \
|
||||
min_index = subgroupBroadcastFirst(subgroupMin(min_index)); \
|
||||
max_index = subgroupBroadcastFirst(subgroupMax(max_index)); \
|
||||
/* Same as divide by 32 but avoid integer division. */ \
|
||||
uint word_min = min_index >> 5u; \
|
||||
uint word_max = max_index >> 5u; \
|
||||
for (uint word_idx = word_min; word_idx <= word_max; word_idx++) { \
|
||||
uint word = _words[tile_word_offset + word_idx]; \
|
||||
word &= zbin_mask(word_idx, min_index, max_index); \
|
||||
/* Ensure all threads inside a subgroup get the same value to reduce VGPR usage. */ \
|
||||
word = subgroupBroadcastFirst(subgroupOr(word)); \
|
||||
int bit_index; \
|
||||
while ((bit_index = findLSB(word)) != -1) { \
|
||||
word &= ~1u << uint(bit_index); \
|
||||
uint _item_index = word_idx * 32u + uint(bit_index);
|
||||
|
||||
#endif
|
||||
|
||||
#define LIGHT_FOREACH_END \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "eevee_shadow_tilemap_lib.bsl.hh"
|
||||
#include "gpu_shader_utildefines_lib.glsl"
|
||||
|
||||
namespace eevee {
|
||||
|
||||
/* Any entry point function using this should also use `[[texture_atomic]]`. */
|
||||
struct ShadowRenderData {
|
||||
[[sampler(SHADOW_ATLAS_TEX_SLOT)]] usampler2DArrayAtomic shadow_atlas_tx;
|
||||
[[sampler(SHADOW_TILEMAPS_TEX_SLOT)]] usampler2D shadow_tilemaps_tx;
|
||||
|
||||
float read_depth(ShadowCoordinates coord) const
|
||||
{
|
||||
ShadowSamplingTile tile = shadow_tile_load(
|
||||
shadow_tilemaps_tx, coord.tilemap_tile, coord.tilemap_index);
|
||||
if (!tile.is_valid) {
|
||||
return -1.0f;
|
||||
}
|
||||
/* Using bitwise ops is way faster than integer ops. */
|
||||
constexpr uint page_shift = uint(SHADOW_PAGE_LOD);
|
||||
constexpr uint page_mask = ~(0xFFFFFFFFu << uint(SHADOW_PAGE_LOD));
|
||||
|
||||
uint2 texel = coord.tilemap_texel;
|
||||
/* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */
|
||||
texel += uint2(tile.lod_offset << SHADOW_PAGE_LOD);
|
||||
/* Scale to LOD pixels (merge LOD0 pixels together) then mask to get pixel in page. */
|
||||
uint2 texel_page = (texel >> tile.lod) & page_mask;
|
||||
texel = (uint2(tile.page.xy) << page_shift) | texel_page;
|
||||
|
||||
return uintBitsToFloat(texelFetch(shadow_atlas_tx, int3(int2(texel), int(tile.page.z)), 0).r);
|
||||
}
|
||||
|
||||
float punctual_sample_get(LightData light, float3 P) const
|
||||
{
|
||||
float3 shadow_position = light.local().local.shadow_position;
|
||||
float3 lP = transform_point_inversed(light.object_to_world, P);
|
||||
lP -= shadow_position;
|
||||
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);
|
||||
|
||||
float radial_dist = read_depth(coord);
|
||||
if (radial_dist == -1.0f) {
|
||||
return 1e10f;
|
||||
}
|
||||
float receiver_dist = length(lP);
|
||||
float occluder_dist = radial_dist;
|
||||
return receiver_dist - occluder_dist;
|
||||
}
|
||||
|
||||
float directional_sample_get(LightData light, float3 P) const
|
||||
{
|
||||
float3 lP = transform_direction_transposed(light.object_to_world, P);
|
||||
ShadowCoordinates coord = shadow_directional_coordinates(light, lP);
|
||||
|
||||
float depth = read_depth(coord);
|
||||
if (depth == -1.0f) {
|
||||
return 1e10f;
|
||||
}
|
||||
/* Use increasing distance from the light. */
|
||||
float receiver_dist = -lP.z - orderedIntBitsToFloat(light.clip_near);
|
||||
float occluder_dist = depth;
|
||||
return receiver_dist - occluder_dist;
|
||||
}
|
||||
|
||||
float shadow_sample(const bool is_directional, LightData light, float3 P) const
|
||||
{
|
||||
if (is_directional) {
|
||||
return directional_sample_get(light, P);
|
||||
}
|
||||
return punctual_sample_get(light, P);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace eevee
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "eevee_shadow_tilemap_lib.bsl.hh"
|
||||
#include "gpu_shader_utildefines_lib.glsl"
|
||||
|
||||
#define EEVEE_SHADOW_LIB
|
||||
|
||||
#ifdef SHADOW_READ_ATOMIC
|
||||
# define SHADOW_ATLAS_TYPE usampler2DArrayAtomic
|
||||
#else
|
||||
# define SHADOW_ATLAS_TYPE usampler2DArray
|
||||
#endif
|
||||
|
||||
float shadow_read_depth(SHADOW_ATLAS_TYPE atlas_tx,
|
||||
usampler2D tilemaps_tx,
|
||||
ShadowCoordinates coord)
|
||||
{
|
||||
ShadowSamplingTile tile = shadow_tile_load(tilemaps_tx, coord.tilemap_tile, coord.tilemap_index);
|
||||
if (!tile.is_valid) {
|
||||
return -1.0f;
|
||||
}
|
||||
/* Using bitwise ops is way faster than integer ops. */
|
||||
constexpr uint page_shift = uint(SHADOW_PAGE_LOD);
|
||||
constexpr uint page_mask = ~(0xFFFFFFFFu << uint(SHADOW_PAGE_LOD));
|
||||
|
||||
uint2 texel = coord.tilemap_texel;
|
||||
/* Shift LOD0 pixels so that they get wrapped at the right position for the given LOD. */
|
||||
texel += uint2(tile.lod_offset << SHADOW_PAGE_LOD);
|
||||
/* Scale to LOD pixels (merge LOD0 pixels together) then mask to get pixel in page. */
|
||||
uint2 texel_page = (texel >> tile.lod) & page_mask;
|
||||
texel = (uint2(tile.page.xy) << page_shift) | texel_page;
|
||||
|
||||
return uintBitsToFloat(texelFetch(atlas_tx, int3(int2(texel), int(tile.page.z)), 0).r);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Shadow Sampling Functions
|
||||
* \{ */
|
||||
|
||||
float shadow_punctual_sample_get(SHADOW_ATLAS_TYPE atlas_tx,
|
||||
usampler2D tilemaps_tx,
|
||||
LightData light,
|
||||
float3 P)
|
||||
{
|
||||
float3 shadow_position = light.local().local.shadow_position;
|
||||
float3 lP = transform_point_inversed(light.object_to_world, P);
|
||||
lP -= shadow_position;
|
||||
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);
|
||||
|
||||
float radial_dist = shadow_read_depth(atlas_tx, tilemaps_tx, coord);
|
||||
if (radial_dist == -1.0f) {
|
||||
return 1e10f;
|
||||
}
|
||||
float receiver_dist = length(lP);
|
||||
float occluder_dist = radial_dist;
|
||||
return receiver_dist - occluder_dist;
|
||||
}
|
||||
|
||||
float shadow_directional_sample_get(SHADOW_ATLAS_TYPE atlas_tx,
|
||||
usampler2D tilemaps_tx,
|
||||
LightData light,
|
||||
float3 P)
|
||||
{
|
||||
float3 lP = transform_direction_transposed(light.object_to_world, P);
|
||||
ShadowCoordinates coord = shadow_directional_coordinates(light, lP);
|
||||
|
||||
float depth = shadow_read_depth(atlas_tx, tilemaps_tx, coord);
|
||||
if (depth == -1.0f) {
|
||||
return 1e10f;
|
||||
}
|
||||
/* Use increasing distance from the light. */
|
||||
float receiver_dist = -lP.z - orderedIntBitsToFloat(light.clip_near);
|
||||
float occluder_dist = depth;
|
||||
return receiver_dist - occluder_dist;
|
||||
}
|
||||
|
||||
float shadow_sample(const bool is_directional,
|
||||
SHADOW_ATLAS_TYPE atlas_tx,
|
||||
usampler2D tilemaps_tx,
|
||||
LightData light,
|
||||
float3 P)
|
||||
{
|
||||
if (is_directional) {
|
||||
return shadow_directional_sample_get(atlas_tx, tilemaps_tx, light, P);
|
||||
}
|
||||
else {
|
||||
return shadow_punctual_sample_get(atlas_tx, tilemaps_tx, light, P);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "infos/eevee_shadow_infos.hh"
|
||||
|
||||
#include "eevee_shadow_page_ops.bsl.hh"
|
||||
#include "eevee_shadow_tilemap_lib.bsl.hh"
|
||||
|
||||
|
|
|
|||
|
|
@ -11,17 +11,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "infos/eevee_common_infos.hh"
|
||||
#include "infos/eevee_light_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(draw_view)
|
||||
COMPUTE_SHADER_CREATE_INFO(draw_view_culling)
|
||||
COMPUTE_SHADER_CREATE_INFO(eevee_hiz_data)
|
||||
COMPUTE_SHADER_CREATE_INFO(eevee_light_data)
|
||||
COMPUTE_SHADER_CREATE_INFO(draw_resource_id_varying)
|
||||
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_defines.hh"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_iter.bsl.hh"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_lightprobe_shared.hh"
|
||||
#include "eevee_sampling_lib.glsl"
|
||||
|
|
@ -37,53 +35,12 @@ struct TagUsage {
|
|||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo draw_view_culling;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_global_ubo;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
|
||||
[[resource_table]] srt_t<LightRenderData> light_data;
|
||||
[[resource_table]] srt_t<TileMaps> tilemaps;
|
||||
[[resource_table]] srt_t<Tiles> tiles;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \a radius Radius of the tagging area in world space.
|
||||
* Used for downsampled/ray-marched tagging, so all the shadow-map texels covered get correctly
|
||||
* tagged.
|
||||
*/
|
||||
void tag_pixel(float3 vP,
|
||||
float3 P,
|
||||
float2 pixel,
|
||||
float3 V = float3(0),
|
||||
float radius = 0.0f,
|
||||
int lod_bias = 0)
|
||||
{
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
shadow_tag_usage_tilemap_directional(l_idx, P, V, radius, lod_bias);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx)
|
||||
{
|
||||
tag_usage_tilemap_punctual(l_idx, P, radius, lod_bias);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
}
|
||||
|
||||
void tag_surfel(Surfel surfel, int directional_lvl)
|
||||
{
|
||||
float3 P = surfel.position;
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
tag_usage_tilemap_directional_at_level(l_idx, P, directional_lvl);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(light_cull_buf, l_idx)
|
||||
{
|
||||
tag_usage_tilemap_punctual(l_idx, P, 0, 0);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
}
|
||||
|
||||
private:
|
||||
void tag_usage_tile(LightData light, uint2 tile_co, int lod, int tilemap_index)
|
||||
{
|
||||
if (tilemap_index > light_tilemap_max_get(light)) {
|
||||
|
|
@ -99,7 +56,8 @@ struct TagUsage {
|
|||
|
||||
void tag_usage_tilemap_directional_at_level(uint l_idx, float3 P, int level)
|
||||
{
|
||||
LightData light = light_buf[l_idx];
|
||||
[[resource_table]] LightRenderData &lrd = light_data;
|
||||
LightData light = lrd.light_buf[l_idx];
|
||||
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||
return;
|
||||
|
|
@ -116,7 +74,8 @@ struct TagUsage {
|
|||
void shadow_tag_usage_tilemap_directional(
|
||||
uint l_idx, float3 P, float3 V, float radius, int lod_bias)
|
||||
{
|
||||
LightData light = light_buf[l_idx];
|
||||
[[resource_table]] LightRenderData &lrd = light_data;
|
||||
LightData light = lrd.light_buf[l_idx];
|
||||
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||
return;
|
||||
|
|
@ -157,7 +116,9 @@ struct TagUsage {
|
|||
|
||||
void tag_usage_tilemap_punctual(uint l_idx, float3 P, float radius, int lod_bias)
|
||||
{
|
||||
LightData light = light_buf[l_idx];
|
||||
[[resource_table]] LightRenderData &lrd = light_data;
|
||||
|
||||
LightData light = lrd.light_buf[l_idx];
|
||||
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||
return;
|
||||
|
|
@ -231,6 +192,61 @@ struct TagUsage {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \a radius Radius of the tagging area in world space.
|
||||
* Used for downsampled/ray-marched tagging, so all the shadow-map texels covered get correctly
|
||||
* tagged.
|
||||
*/
|
||||
struct TagPixelCtx {
|
||||
float3 P;
|
||||
float3 V;
|
||||
float radius;
|
||||
int lod_bias;
|
||||
|
||||
void eval_directional([[resource_table]] TagUsage &srt, uint index, LightData /*light*/)
|
||||
{
|
||||
srt.shadow_tag_usage_tilemap_directional(index, P, V, radius, lod_bias);
|
||||
}
|
||||
|
||||
void eval_local([[resource_table]] TagUsage &srt, uint index, LightData /*light*/)
|
||||
{
|
||||
srt.tag_usage_tilemap_punctual(index, P, radius, lod_bias);
|
||||
}
|
||||
};
|
||||
|
||||
struct TagSurfelCtx {
|
||||
float3 P;
|
||||
int directional_lvl;
|
||||
|
||||
void eval_directional([[resource_table]] TagUsage &srt, uint index, LightData /*light*/)
|
||||
{
|
||||
srt.tag_usage_tilemap_directional_at_level(index, P, directional_lvl);
|
||||
}
|
||||
|
||||
void eval_local([[resource_table]] TagUsage &srt, uint index, LightData /*light*/)
|
||||
{
|
||||
srt.tag_usage_tilemap_punctual(index, P, 0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace eevee::shadow::usage
|
||||
|
||||
namespace eevee::light {
|
||||
|
||||
template void light::foreach_visible<shadow::usage::TagPixelCtx, shadow::usage::TagUsage>(
|
||||
const LightRenderData &,
|
||||
float2,
|
||||
float,
|
||||
shadow::usage::TagPixelCtx &,
|
||||
shadow::usage::TagUsage &);
|
||||
|
||||
template void light::foreach<shadow::usage::TagSurfelCtx, shadow::usage::TagUsage>(
|
||||
const LightRenderData &, shadow::usage::TagSurfelCtx &, shadow::usage::TagUsage &);
|
||||
|
||||
} // namespace eevee::light
|
||||
|
||||
namespace eevee::shadow::usage {
|
||||
|
||||
struct TagUsageOpaque {
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
|
||||
|
|
@ -246,6 +262,8 @@ void tag_usage_opaque([[resource_table]] TagUsageOpaque &srt,
|
|||
[[resource_table]] TagUsage &tag,
|
||||
[[global_invocation_id]] const uint3 global_id)
|
||||
{
|
||||
[[resource_table]] LightRenderData &lrd = tag.light_data;
|
||||
|
||||
int2 texel = int2(global_id.xy);
|
||||
int2 tex_size = srt.input_depth_extent;
|
||||
|
||||
|
|
@ -260,10 +278,15 @@ void tag_usage_opaque([[resource_table]] TagUsageOpaque &srt,
|
|||
|
||||
float2 uv = (float2(texel) + 0.5f) / float2(tex_size);
|
||||
float3 vP = drw_point_screen_to_view(float3(uv, depth));
|
||||
float3 P = drw_point_view_to_world(vP);
|
||||
float2 pixel = float2(global_id.xy);
|
||||
|
||||
tag.tag_pixel(vP, P, pixel);
|
||||
TagPixelCtx ctx = {
|
||||
.P = drw_point_view_to_world(vP),
|
||||
.V = float3(0.0f),
|
||||
.radius = 0.0f,
|
||||
.lod_bias = 0,
|
||||
};
|
||||
|
||||
light::foreach_visible(lrd, float2(global_id.xy), vP.z, ctx, tag);
|
||||
}
|
||||
|
||||
struct TagUsageSurfel {
|
||||
|
|
@ -285,6 +308,8 @@ void tag_usage_surfel([[resource_table]] TagUsageSurfel &srt,
|
|||
[[resource_table]] SurfelCapture &capture,
|
||||
[[global_invocation_id]] const uint3 global_id)
|
||||
{
|
||||
[[resource_table]] LightRenderData &lrd = tag.light_data;
|
||||
|
||||
uint index = global_id.x;
|
||||
if (index >= capture.capture_info_buf.surfel_len) {
|
||||
return;
|
||||
|
|
@ -292,7 +317,12 @@ void tag_usage_surfel([[resource_table]] TagUsageSurfel &srt,
|
|||
|
||||
Surfel surfel = capture.surfel_buf[index];
|
||||
|
||||
tag.tag_surfel(surfel, srt.directional_level);
|
||||
TagSurfelCtx ctx = {
|
||||
.P = surfel.position,
|
||||
.directional_lvl = srt.directional_level,
|
||||
};
|
||||
|
||||
light::foreach(lrd, ctx, tag);
|
||||
}
|
||||
|
||||
struct TagUsageVolume {
|
||||
|
|
@ -310,6 +340,8 @@ void tag_usage_volume([[resource_table]] TagUsageVolume & /*srt*/,
|
|||
[[resource_table]] SurfelCapture & /*capture*/,
|
||||
[[global_invocation_id]] const uint3 global_id)
|
||||
{
|
||||
[[resource_table]] LightRenderData &lrd = tag.light_data;
|
||||
|
||||
int3 froxel = int3(global_id);
|
||||
|
||||
if (any(greaterThanEqual(froxel, uniform_buf.volumes.tex_size))) {
|
||||
|
|
@ -340,7 +372,15 @@ void tag_usage_volume([[resource_table]] TagUsageVolume & /*srt*/,
|
|||
uniform_buf.volumes.main_view_extent;
|
||||
|
||||
int bias = uniform_buf.volumes.tile_size_lod;
|
||||
tag.tag_pixel(vP, P, pixel, drw_world_incident_vector(P), 0.01f, bias);
|
||||
|
||||
TagPixelCtx ctx = {
|
||||
.P = P,
|
||||
.V = drw_world_incident_vector(P),
|
||||
.radius = 0.01f,
|
||||
.lod_bias = bias,
|
||||
};
|
||||
|
||||
light::foreach_visible(lrd, pixel, vP.z, ctx, tag);
|
||||
}
|
||||
|
||||
} // namespace eevee::shadow::usage
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "infos/eevee_shadow_infos.hh"
|
||||
#include "draw_view_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(draw_modelmat)
|
||||
|
||||
|
|
@ -252,7 +252,18 @@ void tag_usage_frag([[resource_table]] TagUsageTransparent &srt,
|
|||
srt.step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius);
|
||||
float3 vP = drw_point_world_to_view(P);
|
||||
|
||||
tag.tag_pixel(vP, P, frag_co.xy * exp2(float(srt.fb_lod)), ws_view_direction, step_radius, 0);
|
||||
float2 pixel = frag_co.xy * exp2(float(srt.fb_lod));
|
||||
|
||||
[[resource_table]] LightRenderData &lrd = tag.light_data;
|
||||
|
||||
TagPixelCtx ctx = {
|
||||
.P = P,
|
||||
.V = drw_world_incident_vector(P),
|
||||
.radius = step_radius,
|
||||
.lod_bias = 0,
|
||||
};
|
||||
|
||||
light::foreach_visible(lrd, pixel, vP.z, ctx, tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
COMPUTE_SHADER_CREATE_INFO(gpu_shader_test)
|
||||
|
||||
#include "eevee_shadow_lib.glsl"
|
||||
#include "eevee_shadow.bsl.hh"
|
||||
|
||||
#include "gpu_shader_math_vector_lib.glsl"
|
||||
#include "gpu_shader_test_lib.glsl"
|
||||
|
|
|
|||
|
|
@ -17,44 +17,30 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "draw_view_infos.hh"
|
||||
|
||||
FRAGMENT_SHADER_CREATE_INFO(draw_view)
|
||||
|
||||
#include "eevee_defines.hh"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_iter.bsl.hh"
|
||||
#include "eevee_shadow_shared.hh"
|
||||
#include "eevee_shadow_tilemap_lib.bsl.hh"
|
||||
|
||||
namespace eevee {
|
||||
|
||||
struct TilemapAmend {
|
||||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
|
||||
[[storage(LIGHT_CULL_BUF_SLOT, read)]] const LightCullingData &light_cull_buf;
|
||||
[[storage(LIGHT_BUF_SLOT, read_write)]] LightData (&light_buf)[];
|
||||
/* The call bind_resources(lights) also uses LIGHT_ZBIN_BUF_SLOT and LIGHT_TILE_BUF_SLOT. */
|
||||
[[storage(4, read)]] const ShadowTileMapData (&tilemaps_buf)[];
|
||||
[[storage(5, read_write)]] LightData (&light_buf_write)[];
|
||||
|
||||
[[shared]] uint tiles_local[SHADOW_TILEMAP_RES][SHADOW_TILEMAP_RES];
|
||||
|
||||
[[image(0, read_write, UINT_32)]] uimage2D tilemaps_img;
|
||||
};
|
||||
|
||||
[[compute, local_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)]]
|
||||
void tilemap_amend([[resource_table]] TilemapAmend &srt,
|
||||
[[global_invocation_id]] const uint3 global_id)
|
||||
{
|
||||
int2 tile_co = int2(global_id.xy);
|
||||
struct AmendCtx {
|
||||
int2 tile_co;
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (srt.light_cull_buf, l_idx) {
|
||||
LightData light = srt.light_buf[l_idx];
|
||||
void eval_directional([[resource_table]] TilemapAmend &srt, uint /*index*/, LightData light)
|
||||
{
|
||||
/* This only works on clip-maps. Cascade have already the same LOD for every tile-maps. */
|
||||
if (light.type != LIGHT_SUN) {
|
||||
break;
|
||||
}
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||
continue;
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW || light.type != LIGHT_SUN) {
|
||||
return;
|
||||
}
|
||||
|
||||
int2 base_offset_neg = light.sun().clipmap_base_offset_neg;
|
||||
|
|
@ -87,8 +73,9 @@ void tilemap_amend([[resource_table]] TilemapAmend &srt,
|
|||
* Increase with each new invalid level. */
|
||||
tile_prev.lod += 1;
|
||||
|
||||
/* The offset (in tile of current LOD) is equal to the offset from the bottom left corner
|
||||
* of both LODs modulo the size of a tile of the source LOD (in tile of current LOD). */
|
||||
/* The offset (in tile of current LOD) is equal to the offset from the bottom left
|
||||
* corner of both LODs modulo the size of a tile of the source LOD (in tile of current
|
||||
* LOD). */
|
||||
|
||||
/* Offset corner to center. */
|
||||
tile_prev.lod_offset = uint2(SHADOW_TILEMAP_RES / 2) << tile_prev.lod;
|
||||
|
|
@ -114,13 +101,11 @@ void tilemap_amend([[resource_table]] TilemapAmend &srt,
|
|||
barrier();
|
||||
}
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
LIGHT_FOREACH_BEGIN_LOCAL_NO_CULL(srt.light_cull_buf, l_idx)
|
||||
void eval_local([[resource_table]] TilemapAmend &srt, uint index, LightData light)
|
||||
{
|
||||
LightData light = srt.light_buf[l_idx];
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
int lod_min = 0;
|
||||
|
|
@ -133,10 +118,23 @@ void tilemap_amend([[resource_table]] TilemapAmend &srt,
|
|||
/* Override the effective lod min distance in absolute mode (negative).
|
||||
* Note that this only changes the sampling for this AA sample. */
|
||||
constexpr float projection_diagonal = 2.0f * M_SQRT2;
|
||||
srt.light_buf[l_idx].lod_min = -(projection_diagonal / float(SHADOW_MAP_MAX_RES >> lod_min));
|
||||
srt.light_buf_write[index].lod_min = -(projection_diagonal /
|
||||
float(SHADOW_MAP_MAX_RES >> lod_min));
|
||||
}
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
};
|
||||
|
||||
template void light::foreach<AmendCtx, TilemapAmend>(const LightRenderData &,
|
||||
AmendCtx &,
|
||||
TilemapAmend &);
|
||||
|
||||
[[compute, local_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)]] void tilemap_amend(
|
||||
[[resource_table]] TilemapAmend &srt,
|
||||
[[resource_table]] LightRenderData &lrd,
|
||||
[[global_invocation_id]] const uint3 global_id)
|
||||
{
|
||||
AmendCtx ctx = {.tile_co = int2(global_id.xy)};
|
||||
light::foreach(lrd, ctx, srt);
|
||||
}
|
||||
|
||||
PipelineCompute shadow_tilemap_amend(tilemap_amend);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include "draw_shader_shared.hh"
|
||||
#include "draw_shape_lib.glsl"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_iter.bsl.hh"
|
||||
#include "eevee_shadow_shared.hh"
|
||||
#include "gpu_shader_utildefines_lib.glsl"
|
||||
|
||||
|
|
@ -36,54 +36,33 @@ void tilemap_bounds_clear([[resource_table]] TilemapBoundsInit &srt,
|
|||
}
|
||||
|
||||
struct TilemapBounds {
|
||||
[[storage(LIGHT_CULL_BUF_SLOT, read)]] const LightCullingData &light_cull_buf;
|
||||
[[storage(LIGHT_BUF_SLOT, read_write)]] LightData (&light_buf)[];
|
||||
[[resource_table]] srt_t<LightRenderData> light_data;
|
||||
|
||||
[[storage(4, read)]] const uint (&casters_id_buf)[];
|
||||
[[storage(5, read_write)]] ShadowTileMapData (&tilemaps_buf)[];
|
||||
[[storage(6, read)]] const ObjectBounds (&bounds_buf)[];
|
||||
[[storage(7, read_write)]] ShadowTileMapClip (&tilemaps_clip_buf)[];
|
||||
|
||||
[[storage(8, read_write)]] LightData (&light_buf_write)[];
|
||||
|
||||
[[push_constant]] const int resource_len;
|
||||
|
||||
[[shared]] int global_min;
|
||||
[[shared]] int global_max;
|
||||
};
|
||||
|
||||
[[compute, local_size(SHADOW_BOUNDS_GROUP_SIZE)]]
|
||||
void tilemap_bounds_min_max([[resource_table]] TilemapBounds &srt,
|
||||
[[global_invocation_id]] const uint3 global_id,
|
||||
[[local_invocation_index]] const uint local_index)
|
||||
{
|
||||
struct TilemapBoundsCtx {
|
||||
Box box;
|
||||
bool is_valid = true;
|
||||
bool is_valid;
|
||||
uint local_id;
|
||||
|
||||
if (srt.resource_len > 0) {
|
||||
uint index = global_id.x;
|
||||
/* Keep uniform control flow. Do not return. */
|
||||
index = min(index, uint(srt.resource_len) - 1);
|
||||
uint resource_id = srt.casters_id_buf[index];
|
||||
resource_id = (resource_id & 0x7FFFFFFFu);
|
||||
|
||||
ObjectBounds bounds = srt.bounds_buf[resource_id];
|
||||
is_valid = drw_bounds_corners_are_valid(bounds);
|
||||
box = shape_box(bounds.bounding_corners[0].xyz,
|
||||
bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz,
|
||||
bounds.bounding_corners[0].xyz + bounds.bounding_corners[2].xyz,
|
||||
bounds.bounding_corners[0].xyz + bounds.bounding_corners[3].xyz);
|
||||
}
|
||||
else {
|
||||
/* Create a dummy box so initialization happens even when there are no shadow casters. */
|
||||
box = shape_box(float3(-1.0f),
|
||||
float3(-1.0f) + float3(1.0f, 0.0f, 0.0f),
|
||||
float3(-1.0f) + float3(0.0f, 1.0f, 0.0f),
|
||||
float3(-1.0f) + float3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (srt.light_cull_buf, l_idx) {
|
||||
LightData light = srt.light_buf[l_idx];
|
||||
void eval_directional([[resource_table]] TilemapBounds &srt, uint l_index, LightData /*light*/)
|
||||
{
|
||||
[[resource_table]] LightRenderData &lrd = srt.light_data;
|
||||
LightData light = lrd.light_buf[l_index];
|
||||
|
||||
if (light.tilemap_index == LIGHT_NO_SHADOW) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
float local_min = FLT_MAX;
|
||||
|
|
@ -94,7 +73,7 @@ void tilemap_bounds_min_max([[resource_table]] TilemapBounds &srt,
|
|||
local_max = max(local_max, z);
|
||||
}
|
||||
|
||||
if (local_index == 0u) {
|
||||
if (local_id == 0u) {
|
||||
srt.global_min = floatBitsToOrderedInt(FLT_MAX);
|
||||
srt.global_max = floatBitsToOrderedInt(-FLT_MAX);
|
||||
}
|
||||
|
|
@ -113,10 +92,10 @@ void tilemap_bounds_min_max([[resource_table]] TilemapBounds &srt,
|
|||
|
||||
barrier();
|
||||
|
||||
if (local_index == 0u) {
|
||||
if (local_id == 0u) {
|
||||
/* Final result. Min/Max of the whole dispatch. */
|
||||
atomicMin(srt.light_buf[l_idx].clip_near, srt.global_min);
|
||||
atomicMax(srt.light_buf[l_idx].clip_far, srt.global_max);
|
||||
atomicMin(srt.light_buf_write[l_index].clip_near, srt.global_min);
|
||||
atomicMax(srt.light_buf_write[l_index].clip_far, srt.global_max);
|
||||
/* TODO(fclem): This feel unnecessary but we currently have no indexing from
|
||||
* tile-map to lights. This is because the lights are selected by culling phase. */
|
||||
for (int i = light.tilemap_index; i <= light_tilemap_max_get(light); i++) {
|
||||
|
|
@ -129,7 +108,53 @@ void tilemap_bounds_min_max([[resource_table]] TilemapBounds &srt,
|
|||
/* No need for barrier here since global_min/max is only read by thread 0 before being reset by
|
||||
* thread 0. */
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
|
||||
void eval_local([[resource_table]] TilemapBounds & /*srt*/, uint /*index*/, LightData /*light*/)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace eevee::shadow
|
||||
|
||||
template void eevee::light::foreach<eevee::shadow::TilemapBoundsCtx, eevee::shadow::TilemapBounds>(
|
||||
const eevee::LightRenderData &,
|
||||
eevee::shadow::TilemapBoundsCtx &,
|
||||
eevee::shadow::TilemapBounds &);
|
||||
|
||||
namespace eevee::shadow {
|
||||
|
||||
[[compute, local_size(SHADOW_BOUNDS_GROUP_SIZE)]]
|
||||
void tilemap_bounds_min_max([[resource_table]] TilemapBounds &srt,
|
||||
[[global_invocation_id]] const uint3 global_id,
|
||||
[[local_invocation_index]] const uint local_index)
|
||||
{
|
||||
TilemapBoundsCtx ctx;
|
||||
ctx.is_valid = true;
|
||||
ctx.local_id = local_index;
|
||||
|
||||
if (srt.resource_len > 0) {
|
||||
uint index = global_id.x;
|
||||
/* Keep uniform control flow. Do not return. */
|
||||
index = min(index, uint(srt.resource_len) - 1);
|
||||
uint resource_id = srt.casters_id_buf[index];
|
||||
resource_id = (resource_id & 0x7FFFFFFFu);
|
||||
|
||||
ObjectBounds bounds = srt.bounds_buf[resource_id];
|
||||
ctx.is_valid = drw_bounds_corners_are_valid(bounds);
|
||||
ctx.box = shape_box(bounds.bounding_corners[0].xyz,
|
||||
bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz,
|
||||
bounds.bounding_corners[0].xyz + bounds.bounding_corners[2].xyz,
|
||||
bounds.bounding_corners[0].xyz + bounds.bounding_corners[3].xyz);
|
||||
}
|
||||
else {
|
||||
/* Create a dummy box so initialization happens even when there are no shadow casters. */
|
||||
ctx.box = shape_box(float3(-1.0f),
|
||||
float3(-1.0f) + float3(1.0f, 0.0f, 0.0f),
|
||||
float3(-1.0f) + float3(0.0f, 1.0f, 0.0f),
|
||||
float3(-1.0f) + float3(0.0f, 0.0f, 1.0f));
|
||||
}
|
||||
|
||||
light::foreach(srt.light_data, ctx, srt);
|
||||
}
|
||||
|
||||
PipelineCompute tilemap_bounds_init(tilemap_bounds_clear);
|
||||
|
|
|
|||
|
|
@ -8,22 +8,23 @@
|
|||
* Evaluate shadowing using shadow map ray-tracing.
|
||||
*/
|
||||
|
||||
#include "infos/eevee_shadow_infos.hh"
|
||||
#include "infos/eevee_uniform_infos.hh"
|
||||
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_global_ubo)
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_shadow_data)
|
||||
|
||||
#include "draw_math_geom_lib.glsl"
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_sampling_lib.glsl"
|
||||
#include "eevee_shadow_lib.glsl"
|
||||
#include "eevee_shadow.bsl.hh"
|
||||
#include "eevee_thickness_lib.bsl.hh"
|
||||
#include "gpu_shader_math_base_lib.glsl"
|
||||
#include "gpu_shader_math_fast_lib.glsl"
|
||||
#include "gpu_shader_math_vector_safe_lib.glsl"
|
||||
#include "gpu_shader_ray_utils_lib.glsl"
|
||||
|
||||
namespace eevee {
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Shadow Map Tracing loop
|
||||
* \{ */
|
||||
|
|
@ -119,14 +120,17 @@ void shadow_map_trace_hit_check(ShadowMapTracingState &state,
|
|||
* Most of the code is wrapped into functions to avoid to debug issues inside macro code.
|
||||
*/
|
||||
template<typename ShadowRayType>
|
||||
bool shadow_map_trace(ShadowRayType ray, int sample_count, float step_offset)
|
||||
bool shadow_map_trace([[resource_table]] ShadowRenderData &srd,
|
||||
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++)
|
||||
{ /* Saturate to always cover the shading point position when i == sample_count. */
|
||||
state.ray_time = square(saturate(float(i) * state.ray_step_mul + state.ray_step_bias));
|
||||
|
||||
ShadowTracingSample samp = shadow_map_trace_sample(state, ray);
|
||||
ShadowTracingSample samp = shadow_map_trace_sample(srd, state, ray);
|
||||
|
||||
shadow_map_trace_hit_check(state, samp, i == sample_count);
|
||||
}
|
||||
|
|
@ -179,14 +183,16 @@ ShadowRayDirectional shadow_ray_generate_directional(LightData light,
|
|||
return ray;
|
||||
}
|
||||
|
||||
ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state, ShadowRayDirectional &ray)
|
||||
ShadowTracingSample shadow_map_trace_sample([[resource_table]] ShadowRenderData &srd,
|
||||
ShadowMapTracingState state,
|
||||
ShadowRayDirectional &ray)
|
||||
{
|
||||
/* Ray position is ray local position with origin at light origin. */
|
||||
float3 ray_pos = ray.origin + ray.direction * state.ray_time;
|
||||
|
||||
ShadowCoordinates coord = shadow_directional_coordinates(ray.light, ray_pos);
|
||||
|
||||
float depth = shadow_read_depth(shadow_atlas_tx, shadow_tilemaps_tx, coord);
|
||||
float depth = srd.read_depth(coord);
|
||||
/* Distance from near plane. */
|
||||
float clip_near = orderedIntBitsToFloat(ray.light.clip_near);
|
||||
float3 occluder_pos = float3(ray_pos.xy, -depth - clip_near);
|
||||
|
|
@ -200,7 +206,10 @@ ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state, ShadowR
|
|||
return samp;
|
||||
}
|
||||
|
||||
template bool shadow_map_trace<ShadowRayDirectional>(ShadowRayDirectional, int, float);
|
||||
template bool shadow_map_trace<ShadowRayDirectional>(ShadowRenderData &,
|
||||
ShadowRayDirectional,
|
||||
int,
|
||||
float);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
@ -277,14 +286,16 @@ ShadowRayPunctual shadow_ray_generate_punctual(LightData light, float2 random_2d
|
|||
return ray;
|
||||
}
|
||||
|
||||
ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state, ShadowRayPunctual &ray)
|
||||
ShadowTracingSample shadow_map_trace_sample([[resource_table]] ShadowRenderData &srd,
|
||||
ShadowMapTracingState state,
|
||||
ShadowRayPunctual &ray)
|
||||
{
|
||||
float3 receiver_pos = ray.origin + ray.direction * state.ray_time;
|
||||
int face_id = shadow_punctual_face_index_get(receiver_pos);
|
||||
float3 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);
|
||||
float radial_occluder_depth = srd.read_depth(coord);
|
||||
float3 occluder_pos = receiver_pos * (radial_occluder_depth / length(receiver_pos));
|
||||
|
||||
/* Transform to ray local space. */
|
||||
|
|
@ -297,7 +308,10 @@ ShadowTracingSample shadow_map_trace_sample(ShadowMapTracingState state, ShadowR
|
|||
return samp;
|
||||
}
|
||||
|
||||
template bool shadow_map_trace<ShadowRayPunctual>(ShadowRayPunctual, int, float);
|
||||
template bool shadow_map_trace<ShadowRayPunctual>(ShadowRenderData &,
|
||||
ShadowRayPunctual,
|
||||
int,
|
||||
float);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
@ -424,7 +438,8 @@ float shadow_terminator_offset(float3 N,
|
|||
* Evaluate shadowing by casting rays toward the light direction.
|
||||
* Returns light visibility.
|
||||
*/
|
||||
float shadow_eval(LightData light,
|
||||
float shadow_eval([[resource_table]] ShadowRenderData &srd,
|
||||
LightData light,
|
||||
const bool is_directional,
|
||||
const bool is_transmission,
|
||||
bool is_translucent_with_thickness,
|
||||
|
|
@ -502,11 +517,11 @@ float shadow_eval(LightData light,
|
|||
if (is_directional) {
|
||||
ShadowRayDirectional clip_ray = shadow_ray_generate_directional(
|
||||
light, random_ray_2d, lP, texel_radius);
|
||||
has_hit = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z);
|
||||
has_hit = shadow_map_trace(srd, clip_ray, ray_step_count, random_shadow_3d.z);
|
||||
}
|
||||
else {
|
||||
ShadowRayPunctual clip_ray = shadow_ray_generate_punctual(light, random_ray_2d, lP);
|
||||
has_hit = shadow_map_trace(clip_ray, ray_step_count, random_shadow_3d.z);
|
||||
has_hit = shadow_map_trace(srd, clip_ray, ray_step_count, random_shadow_3d.z);
|
||||
}
|
||||
|
||||
surface_hit += float(has_hit);
|
||||
|
|
@ -516,3 +531,5 @@ float shadow_eval(LightData light,
|
|||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace eevee
|
||||
|
|
@ -11,7 +11,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "infos/eevee_common_infos.hh"
|
||||
#include "infos/eevee_shadow_infos.hh"
|
||||
|
||||
COMPUTE_SHADER_CREATE_INFO(draw_view)
|
||||
COMPUTE_SHADER_CREATE_INFO(draw_view_culling)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Thickness g_thickness_forward;
|
|||
float4 closure_to_rgba_forward(Closure /*cl_unused*/)
|
||||
{
|
||||
float3 radiance, transmittance;
|
||||
forward_lighting_eval(g_thickness_forward, gl_FragCoord.xy, radiance, transmittance);
|
||||
eevee::forward_lighting_eval(g_thickness_forward, gl_FragCoord.xy, radiance, transmittance);
|
||||
|
||||
/* Reset for the next closure tree. */
|
||||
float noise = utility_tx_fetch(utility_tx, gl_FragCoord.xy, UTIL_BLUE_NOISE_LAYER).r;
|
||||
|
|
@ -61,12 +61,10 @@ namespace eevee {
|
|||
|
||||
struct SurfaceForward {
|
||||
[[legacy_info]] ShaderCreateInfo eevee_global_ubo;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_lightprobe_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_lightprobe_planar_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_utility_texture;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_sampling_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_volume_lib;
|
||||
|
||||
|
|
@ -92,6 +90,7 @@ struct SurfaceForwardFragOut {
|
|||
/* NOTE: This removes the possibility of using gl_FragDepth. */
|
||||
[[fragment]] [[early_fragment_tests]]
|
||||
void surf_forward([[resource_table]] SurfaceForward & /*srt*/,
|
||||
[[resource_table]] LightEvalIterator & /*lights*/,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[out]] SurfaceForwardFragOut &frag_out)
|
||||
{
|
||||
|
|
@ -107,7 +106,7 @@ void surf_forward([[resource_table]] SurfaceForward & /*srt*/,
|
|||
nodetree_surface(closure_rand);
|
||||
|
||||
float3 radiance, transmittance;
|
||||
forward_lighting_eval(g_thickness_forward, gl_FragCoord.xy, radiance, transmittance);
|
||||
eevee::forward_lighting_eval(g_thickness_forward, gl_FragCoord.xy, radiance, transmittance);
|
||||
|
||||
/* Volumetric resolve and compositing. */
|
||||
float2 uvs = gl_FragCoord.xy * uniform_buf.volumes.main_view_extent_inv;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Thickness g_thickness;
|
|||
float4 closure_to_rgba_hybrid(Closure /*cl*/)
|
||||
{
|
||||
float3 radiance, transmittance;
|
||||
forward_lighting_eval(g_thickness, gl_FragCoord.xy, radiance, transmittance);
|
||||
eevee::forward_lighting_eval(g_thickness, gl_FragCoord.xy, radiance, transmittance);
|
||||
|
||||
/* Reset for the next closure tree. */
|
||||
float noise = utility_tx_fetch(utility_tx, gl_FragCoord.xy, UTIL_BLUE_NOISE_LAYER).r;
|
||||
|
|
@ -72,9 +72,7 @@ struct SurfaceHybrid {
|
|||
[[legacy_info]] ShaderCreateInfo draw_view_culling;
|
||||
|
||||
/* For closure_to_rgba. */
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_lightprobe_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
|
||||
/* Everything is stored inside a two layered target, one for each format. This is to fit the
|
||||
* limitation of the number of images we can bind on a single shader. */
|
||||
|
|
@ -118,6 +116,7 @@ struct HybridFragOut {
|
|||
/* NOTE: This removes the possibility of using gl_FragDepth. */
|
||||
[[fragment]] [[early_fragment_tests]]
|
||||
void surf_hybrid([[resource_table]] SurfaceHybrid &srt,
|
||||
[[resource_table]] LightEvalIterator & /*lights*/,
|
||||
[[frag_coord]] const float4 frag_co,
|
||||
[[out]] HybridFragOut &frag_out)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,15 +18,9 @@ COMPUTE_SHADER_CREATE_INFO(draw_view)
|
|||
COMPUTE_SHADER_CREATE_INFO(eevee_global_ubo)
|
||||
COMPUTE_SHADER_CREATE_INFO(eevee_utility_texture)
|
||||
COMPUTE_SHADER_CREATE_INFO(eevee_surfel_common)
|
||||
COMPUTE_SHADER_CREATE_INFO(eevee_light_data)
|
||||
COMPUTE_SHADER_CREATE_INFO(eevee_shadow_data)
|
||||
|
||||
#include "eevee_closure_lib.glsl"
|
||||
#include "eevee_light_eval_lib.glsl"
|
||||
|
||||
#ifndef LIGHT_ITER_FORCE_NO_CULLING
|
||||
# error light_eval_reflection argument assumes this is defined
|
||||
#endif
|
||||
#include "eevee_light_eval.bsl.hh"
|
||||
|
||||
namespace eevee::surfel {
|
||||
|
||||
|
|
@ -35,15 +29,14 @@ struct EvalLight {
|
|||
[[legacy_info]] ShaderCreateInfo eevee_global_ubo;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_utility_texture;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_surfel_common;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
|
||||
[[compilation_constant]] int light_closure_eval_count;
|
||||
/* WORKAROUND: Disables culling in lighting evaluation function. */
|
||||
[[compilation_constant]] bool light_iter_force_no_culling;
|
||||
};
|
||||
|
||||
[[compute, local_size(SURFEL_GROUP_SIZE)]]
|
||||
void eval_light([[resource_table]] EvalLight & /*srt*/,
|
||||
[[resource_table]] LightEvalIterator &lights,
|
||||
[[global_invocation_id]] const uint3 global_id)
|
||||
{
|
||||
const int index = int(global_id.x);
|
||||
|
|
@ -58,32 +51,46 @@ void eval_light([[resource_table]] EvalLight & /*srt*/,
|
|||
float3 Ng = surfel.normal;
|
||||
float3 P = surfel.position;
|
||||
|
||||
ClosureLightStack stack;
|
||||
eevee::light::EvalCtx<false> ctx;
|
||||
ctx.P = P;
|
||||
ctx.Ng = Ng;
|
||||
ctx.V = V;
|
||||
ctx.thickness = Thickness::zero();
|
||||
ctx.receiver_light_set = surfel.receiver_light_set;
|
||||
ctx.terminator_normal_offset = 0.0f;
|
||||
ctx.terminator_geometry_offset = 0.0f;
|
||||
|
||||
ClosureUndetermined cl_reflect;
|
||||
cl_reflect.N = surfel.normal;
|
||||
cl_reflect.type = CLOSURE_BSDF_DIFFUSE_ID;
|
||||
stack.cl[0] = closure_light_new(cl_reflect, V);
|
||||
light_eval_reflection(stack, P, Ng, V, 0.0f, surfel.receiver_light_set, 0.0f, 0.0f);
|
||||
ctx.stack.cl[0] = closure_light_new(cl_reflect, V);
|
||||
lights.eval_reflection(ctx, float2(0.0), 1.0f);
|
||||
|
||||
if (capture_info_buf.capture_indirect) {
|
||||
surfel_buf[index].radiance_direct.front.rgb += stack.cl[0].light_shadowed *
|
||||
surfel_buf[index].radiance_direct.front.rgb += ctx.stack.cl[0].light_shadowed *
|
||||
surfel.albedo_front;
|
||||
}
|
||||
|
||||
ClosureUndetermined cl_transmit;
|
||||
cl_transmit.N = -surfel.normal;
|
||||
cl_transmit.type = CLOSURE_BSDF_DIFFUSE_ID;
|
||||
stack.cl[0] = closure_light_new(cl_transmit, -V);
|
||||
light_eval_reflection(stack, P, -Ng, -V, 0.0f, surfel.receiver_light_set, 0.0f, 0.0f);
|
||||
ctx.stack.cl[0] = closure_light_new(cl_transmit, -V);
|
||||
|
||||
ctx.Ng = -Ng;
|
||||
ctx.V = -V;
|
||||
lights.eval_reflection(ctx, float2(0.0), 1.0f);
|
||||
|
||||
if (capture_info_buf.capture_indirect) {
|
||||
surfel_buf[index].radiance_direct.back.rgb += stack.cl[0].light_shadowed * surfel.albedo_back;
|
||||
surfel_buf[index].radiance_direct.back.rgb += ctx.stack.cl[0].light_shadowed *
|
||||
surfel.albedo_back;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace eevee::surfel
|
||||
|
||||
PipelineCompute eevee_surfel_light(eevee::surfel::eval_light,
|
||||
eevee::surfel::EvalLight{.light_closure_eval_count = 1,
|
||||
.light_iter_force_no_culling = true});
|
||||
eevee::surfel::EvalLight{.light_iter_force_no_culling = true},
|
||||
eevee::LightEvalData{
|
||||
.light_closure_eval_count_reflect = 1,
|
||||
.light_closure_eval_count_transmit = 0,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,22 +7,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "infos/eevee_light_infos.hh"
|
||||
#include "infos/eevee_lightprobe_infos.hh"
|
||||
#include "infos/eevee_shadow_infos.hh"
|
||||
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_light_data)
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_shadow_data)
|
||||
SHADER_LIBRARY_CREATE_INFO(eevee_lightprobe_data)
|
||||
|
||||
#include "draw_view_lib.glsl"
|
||||
#include "eevee_colorspace_lib.bsl.hh"
|
||||
#include "eevee_defines.hh"
|
||||
#include "eevee_light_iter_lib.glsl"
|
||||
#include "eevee_light_eval.bsl.hh"
|
||||
#include "eevee_light_lib.glsl"
|
||||
#include "eevee_light_shared.hh"
|
||||
#include "eevee_lightprobe_volume_eval_lib.glsl"
|
||||
#include "eevee_shadow_lib.glsl"
|
||||
#include "eevee_shadow.bsl.hh"
|
||||
#include "eevee_volume_lib.bsl.hh"
|
||||
#include "eevee_volume_shared.hh"
|
||||
#include "gpu_shader_fullscreen_lib.glsl"
|
||||
|
|
@ -96,50 +91,6 @@ float3 volume_shadow(
|
|||
return shadow;
|
||||
}
|
||||
|
||||
float3 volume_light_eval(const bool is_directional,
|
||||
float3 P,
|
||||
float3 V,
|
||||
uint l_idx,
|
||||
float s_anisotropy,
|
||||
sampler3D extinction_tx)
|
||||
{
|
||||
LightData light = buffer_get(eevee_light_data, light_buf)[l_idx];
|
||||
auto &shadow_atlas_tx = sampler_get(eevee_shadow_data, shadow_atlas_tx);
|
||||
auto &shadow_tilemaps_tx = sampler_get(eevee_shadow_data, shadow_tilemaps_tx);
|
||||
|
||||
/* TODO(fclem): Own light list for volume without lights that have 0 volume influence. */
|
||||
if (light.power[LIGHT_VOLUME] == 0.0f) {
|
||||
return float3(0);
|
||||
}
|
||||
|
||||
LightVector lv = light_shape_vector_get(light, is_directional, P);
|
||||
|
||||
float attenuation = light_attenuation_volume(light, is_directional, lv);
|
||||
if (attenuation < LIGHT_ATTENUATION_THRESHOLD) {
|
||||
return float3(0);
|
||||
}
|
||||
|
||||
float visibility = attenuation;
|
||||
if (light.tilemap_index != LIGHT_NO_SHADOW) {
|
||||
float delta = shadow_sample(is_directional, shadow_atlas_tx, shadow_tilemaps_tx, light, P);
|
||||
if (delta > 0.0f) {
|
||||
return float3(0);
|
||||
}
|
||||
}
|
||||
visibility *= volume_phase_function(-V, lv.L, s_anisotropy);
|
||||
if (visibility < LIGHT_ATTENUATION_THRESHOLD) {
|
||||
return float3(0);
|
||||
}
|
||||
|
||||
float3 Li = volume_light(light, is_directional, lv) * visibility;
|
||||
|
||||
if (light.tilemap_index != LIGHT_NO_SHADOW) {
|
||||
Li *= volume_shadow(light, is_directional, P, lv, extinction_tx);
|
||||
}
|
||||
|
||||
return Li;
|
||||
}
|
||||
|
||||
float3 volume_lightprobe_eval(float3 P, float3 V, float s_anisotropy)
|
||||
{
|
||||
SphericalHarmonicL1<float4> phase_sh = volume_phase_function_as_sh_L1(V, s_anisotropy);
|
||||
|
|
@ -157,11 +108,12 @@ struct Scatter {
|
|||
[[legacy_info]] ShaderCreateInfo draw_view;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_global_ubo;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_hiz_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_light_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_shadow_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_lightprobe_data;
|
||||
[[legacy_info]] ShaderCreateInfo eevee_sampling_data;
|
||||
|
||||
[[resource_table]] srt_t<LightRenderData> light_data;
|
||||
[[resource_table]] srt_t<ShadowRenderData> shadow_data;
|
||||
|
||||
[[sampler(0)]] sampler3D scattering_history_tx;
|
||||
[[sampler(1)]] sampler3D extinction_history_tx;
|
||||
/* Alias of UnifiedVolumeProperties::in_extinction_img but as a sampler. */
|
||||
|
|
@ -171,6 +123,70 @@ struct Scatter {
|
|||
[[image(6, write, UFLOAT_11_11_10)]] image3D out_extinction_img;
|
||||
};
|
||||
|
||||
struct LightEvalCtx {
|
||||
float3 radiance;
|
||||
float3 P;
|
||||
float3 V;
|
||||
float anisotropy;
|
||||
|
||||
float3 light_eval_single([[resource_table]] Scatter &srt,
|
||||
LightData light,
|
||||
const bool is_directional)
|
||||
{
|
||||
[[resource_table]] ShadowRenderData &srd = srt.shadow_data;
|
||||
|
||||
/* TODO(fclem): Own light list for volume without lights that have 0 volume influence. */
|
||||
if (light.power[LIGHT_VOLUME] == 0.0f) {
|
||||
return float3(0);
|
||||
}
|
||||
|
||||
LightVector lv = light_shape_vector_get(light, is_directional, P);
|
||||
|
||||
float attenuation = light_attenuation_volume(light, is_directional, lv);
|
||||
if (attenuation < LIGHT_ATTENUATION_THRESHOLD) {
|
||||
return float3(0);
|
||||
}
|
||||
|
||||
float visibility = attenuation;
|
||||
if (light.tilemap_index != LIGHT_NO_SHADOW) {
|
||||
float delta = srd.shadow_sample(is_directional, light, P);
|
||||
if (delta > 0.0f) {
|
||||
return float3(0);
|
||||
}
|
||||
}
|
||||
visibility *= volume_phase_function(-V, lv.L, anisotropy);
|
||||
if (visibility < LIGHT_ATTENUATION_THRESHOLD) {
|
||||
return float3(0);
|
||||
}
|
||||
|
||||
float3 Li = volume_light(light, is_directional, lv) * visibility;
|
||||
|
||||
if (light.tilemap_index != LIGHT_NO_SHADOW) {
|
||||
Li *= volume_shadow(light, is_directional, P, lv, srt.extinction_tx);
|
||||
}
|
||||
|
||||
return Li;
|
||||
}
|
||||
|
||||
void eval_directional([[resource_table]] Scatter &srd, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
radiance += light_eval_single(srd, light, true);
|
||||
}
|
||||
|
||||
void eval_local([[resource_table]] Scatter &srd, uint /*l_idx*/, LightData light)
|
||||
{
|
||||
radiance += light_eval_single(srd, light, false);
|
||||
}
|
||||
};
|
||||
} // namespace eevee::volume
|
||||
|
||||
namespace eevee::light {
|
||||
template void foreach_visible<volume::LightEvalCtx, volume::Scatter>(
|
||||
const LightRenderData &, float2, float, volume::LightEvalCtx &, volume::Scatter &);
|
||||
}
|
||||
|
||||
namespace eevee::volume {
|
||||
|
||||
/* Step 2 : Evaluate all light scattering for each froxels.
|
||||
* Also do the temporal reprojection to fight aliasing artifacts. */
|
||||
[[compute, local_size(VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE, VOLUME_GROUP_SIZE)]]
|
||||
|
|
@ -208,20 +224,18 @@ void scatter_main([[resource_table]] Scatter &srt,
|
|||
|
||||
if (srt.use_volume_light) [[static_branch]] {
|
||||
if (reduce_max(s_scattering) > 0.0f) {
|
||||
LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) {
|
||||
direct_radiance += volume_light_eval(true, P, V, l_idx, s_anisotropy, srt.extinction_tx);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
volume::LightEvalCtx ctx = {
|
||||
.radiance = float3(0.0f),
|
||||
.P = P,
|
||||
.V = V,
|
||||
.anisotropy = s_anisotropy,
|
||||
};
|
||||
|
||||
float2 pixel = ((float2(froxel.xy) + 0.5f) * uniform_buf.volumes.inv_tex_size.xy) *
|
||||
uniform_buf.volumes.main_view_extent;
|
||||
|
||||
LIGHT_FOREACH_BEGIN_LOCAL (
|
||||
light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx)
|
||||
{
|
||||
direct_radiance += volume_light_eval(false, P, V, l_idx, s_anisotropy, srt.extinction_tx);
|
||||
}
|
||||
LIGHT_FOREACH_END
|
||||
light::foreach_visible(srt.light_data, pixel, vP.z, ctx, srt);
|
||||
direct_radiance = ctx.radiance;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
# define EEVEE_SAMPLING_DATA
|
||||
# define MAT_CLIP_PLANE
|
||||
# define MAT_RENDER_PASS_SUPPORT
|
||||
# define SHADOW_READ_ATOMIC
|
||||
#endif
|
||||
|
||||
#include "eevee_defines.hh"
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@
|
|||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_debug_shared.hh"
|
||||
# include "eevee_fullscreen_infos.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_lightprobe_infos.hh"
|
||||
# include "eevee_sampling_infos.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
#endif
|
||||
|
||||
#include "eevee_defines.hh"
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@
|
|||
# include "draw_view_infos.hh"
|
||||
|
||||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_sampling_infos.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
# include "eevee_shadow_shared.hh"
|
||||
# include "eevee_uniform_infos.hh"
|
||||
# include "eevee_volume_infos.hh"
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifdef GPU_SHADER
|
||||
# pragma once
|
||||
# include "gpu_shader_compat.hh"
|
||||
|
||||
# include "eevee_light_shared.hh"
|
||||
#endif
|
||||
|
||||
#include "eevee_defines.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_light_data)
|
||||
TYPEDEF_SOURCE("eevee_light_shared.hh")
|
||||
STORAGE_BUF(LIGHT_CULL_BUF_SLOT, read, LightCullingData, light_cull_buf)
|
||||
STORAGE_BUF(LIGHT_BUF_SLOT, read, LightData, light_buf[])
|
||||
STORAGE_BUF(LIGHT_ZBIN_BUF_SLOT, read, uint, light_zbin_buf[])
|
||||
STORAGE_BUF(LIGHT_TILE_BUF_SLOT, read, uint, light_tile_buf[])
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
|
@ -10,10 +10,8 @@
|
|||
# include "draw_view_infos.hh"
|
||||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_debug_shared.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_lightprobe_infos.hh"
|
||||
# include "eevee_lightprobe_shared.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
# include "eevee_uniform_infos.hh"
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifdef GPU_SHADER
|
||||
# pragma once
|
||||
# include "gpu_shader_compat.hh"
|
||||
|
||||
# include "eevee_shadow_shared.hh"
|
||||
#endif
|
||||
|
||||
#include "eevee_defines.hh"
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_shadow_data)
|
||||
TYPEDEF_SOURCE("eevee_shadow_shared.hh")
|
||||
/* SHADOW_READ_ATOMIC macro indicating shadow functions should use `usampler2DArrayAtomic` as
|
||||
* the atlas type. */
|
||||
DEFINE("SHADOW_READ_ATOMIC")
|
||||
BUILTINS(BuiltinBits::TEXTURE_ATOMIC)
|
||||
SAMPLER(SHADOW_ATLAS_TEX_SLOT, usampler2DArrayAtomic, shadow_atlas_tx)
|
||||
SAMPLER(SHADOW_TILEMAPS_TEX_SLOT, usampler2D, shadow_tilemaps_tx)
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_shadow_data_non_atomic)
|
||||
TYPEDEF_SOURCE("eevee_shadow_shared.hh")
|
||||
SAMPLER(SHADOW_ATLAS_TEX_SLOT, usampler2DArray, shadow_atlas_tx)
|
||||
SAMPLER(SHADOW_TILEMAPS_TEX_SLOT, usampler2D, shadow_tilemaps_tx)
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
|
@ -12,9 +12,7 @@
|
|||
# include "draw_view_infos.hh"
|
||||
|
||||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_sampling_infos.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
# include "eevee_shadow_shared.hh"
|
||||
# include "eevee_uniform_infos.hh"
|
||||
# include "eevee_volume_infos.hh"
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@
|
|||
# include "draw_view_infos.hh"
|
||||
|
||||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_sampling_infos.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
# include "eevee_shadow_shared.hh"
|
||||
# include "eevee_uniform_infos.hh"
|
||||
# include "eevee_volume_infos.hh"
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@
|
|||
# include "draw_view_infos.hh"
|
||||
|
||||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_sampling_infos.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
# include "eevee_shadow_shared.hh"
|
||||
# include "eevee_uniform_infos.hh"
|
||||
# include "eevee_volume_infos.hh"
|
||||
|
|
|
|||
|
|
@ -12,9 +12,7 @@
|
|||
# include "draw_view_infos.hh"
|
||||
|
||||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_sampling_infos.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
# include "eevee_shadow_shared.hh"
|
||||
# include "eevee_uniform_infos.hh"
|
||||
# include "eevee_volume_infos.hh"
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@
|
|||
# include "draw_view_infos.hh"
|
||||
# include "eevee_common_infos.hh"
|
||||
# include "eevee_fullscreen_infos.hh"
|
||||
# include "eevee_light_infos.hh"
|
||||
# include "eevee_lightprobe_infos.hh"
|
||||
# include "eevee_sampling_infos.hh"
|
||||
# include "eevee_shadow_infos.hh"
|
||||
# include "eevee_volume_resolved_infos.hh"
|
||||
# include "eevee_volume_shared.hh"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1310,6 +1310,7 @@ static void test_eevee_shadow_tilemap_amend()
|
|||
pass.bind_ssbo(LIGHT_BUF_SLOT, culling_light_buf);
|
||||
pass.bind_ssbo(LIGHT_ZBIN_BUF_SLOT, culling_zbin_buf);
|
||||
pass.bind_ssbo(LIGHT_TILE_BUF_SLOT, culling_tile_buf);
|
||||
pass.bind_ssbo("light_buf_write", culling_light_buf);
|
||||
pass.dispatch(int3(1));
|
||||
pass.barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
|
||||
|
|
|
|||
|
|
@ -275,62 +275,71 @@ void SourceProcessor::lower_loop_unroll(Parser &parser)
|
|||
|
||||
void SourceProcessor::lower_static_branch(Parser &parser)
|
||||
{
|
||||
parser().foreach_match("i(..)[[A]]{..}", [&](const vector<Token> &tokens) {
|
||||
Token if_tok = tokens[0];
|
||||
Scope condition = tokens[1].scope();
|
||||
Token attribute = tokens[7];
|
||||
Scope body = tokens[10].scope();
|
||||
do {
|
||||
parser().foreach_match("i(..)[[A]]{..}", [&](const vector<Token> &tokens) {
|
||||
Token if_tok = tokens[0];
|
||||
Scope condition = tokens[1].scope();
|
||||
Token attribute = tokens[7];
|
||||
Scope body = tokens[10].scope();
|
||||
|
||||
if (attribute.str() != "static_branch") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (condition.str().find("&&") != string::npos || condition.str().find("||") != string::npos) {
|
||||
report_error(condition[0], "Expecting single condition.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (condition[1].str() != "srt_access") {
|
||||
report_error(if_tok,
|
||||
"Expecting compilation or specialization constant. Make sure SRT arguments "
|
||||
"have the [[resource_table]] attribute.");
|
||||
return;
|
||||
}
|
||||
|
||||
Token before_body = body.front().prev();
|
||||
|
||||
string test = "SRT_CONSTANT_" + string(condition[5].str()) + " ";
|
||||
if (condition[7] != condition.back().prev()) {
|
||||
test += parser.substr_range_inclusive(condition[7], condition.back().prev());
|
||||
}
|
||||
string directive = (if_tok.prev() == Else ? "#elif " : "#if ");
|
||||
|
||||
parser.insert_directive(before_body, directive + test);
|
||||
parser.erase(if_tok, before_body);
|
||||
|
||||
if (body.back().next() == Else) {
|
||||
Token else_tok = body.back().next();
|
||||
parser.erase(else_tok);
|
||||
if (else_tok.next() == If) {
|
||||
/* Will be processed later. */
|
||||
Token next_if = else_tok.next();
|
||||
/* Ensure the rest of the if clauses also have the attribute. */
|
||||
Scope attributes = next_if.next().scope().back().next().scope();
|
||||
if (attributes.type() != ScopeType::Subscript ||
|
||||
attributes.front().next().scope().str_exclusive() != "static_branch")
|
||||
{
|
||||
report_error(next_if, "Expecting next if statement to also be a static branch.");
|
||||
return;
|
||||
}
|
||||
if (attribute.str() != "static_branch") {
|
||||
return;
|
||||
}
|
||||
body = else_tok.next().scope();
|
||||
|
||||
parser.insert_directive(else_tok, "#else");
|
||||
}
|
||||
parser.insert_directive(body.back(), "#endif");
|
||||
});
|
||||
parser.apply_mutations();
|
||||
if (condition.str().find("&&") != string::npos || condition.str().find("||") != string::npos)
|
||||
{
|
||||
report_error(condition[0], "Expecting single condition.");
|
||||
return;
|
||||
}
|
||||
|
||||
const int i = condition[1].str() == "!" ? 2 : 1;
|
||||
/* TODO(fclem): Make full check of all params. */
|
||||
const bool is_constexpr = condition[i].str() == "true" || condition[i].str() == "false";
|
||||
const bool constexpr_val = is_constexpr ? (condition[i].str() == "true") ^ (i == 2) : false;
|
||||
|
||||
if (condition[1].str() != "srt_access" && !is_constexpr) {
|
||||
report_error(if_tok,
|
||||
"Expecting compilation or specialization constant. Make sure SRT arguments "
|
||||
"have the [[resource_table]] attribute.");
|
||||
return;
|
||||
}
|
||||
|
||||
Token before_body = body.front().prev();
|
||||
|
||||
string test = is_constexpr ? string(constexpr_val ? "1" : "0") :
|
||||
"SRT_CONSTANT_" + string(condition[5].str()) + " ";
|
||||
if (condition[is_constexpr ? 2 : 7] != condition.back().prev()) {
|
||||
test += parser.substr_range_inclusive(condition[is_constexpr ? 2 : 7],
|
||||
condition.back().prev());
|
||||
}
|
||||
string directive = (if_tok.prev() == Else ? "#elif " : "#if ");
|
||||
|
||||
parser.insert_directive(before_body, directive + test);
|
||||
parser.erase(if_tok, before_body);
|
||||
|
||||
if (body.back().next() == Else) {
|
||||
Token else_tok = body.back().next();
|
||||
parser.erase(else_tok);
|
||||
if (else_tok.next() == If) {
|
||||
/* Will be processed later. */
|
||||
Token next_if = else_tok.next();
|
||||
/* Ensure the rest of the if clauses also have the attribute. */
|
||||
Scope attributes = next_if.next().scope().back().next().scope();
|
||||
if (attributes.type() != ScopeType::Subscript ||
|
||||
attributes.front().next().scope().str_exclusive() != "static_branch")
|
||||
{
|
||||
report_error(next_if, "Expecting next if statement to also be a static branch.");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
body = else_tok.next().scope();
|
||||
|
||||
parser.insert_directive(else_tok, "#else");
|
||||
}
|
||||
parser.insert_directive(body.back(), "#endif");
|
||||
});
|
||||
} while (parser.apply_mutations());
|
||||
}
|
||||
|
||||
} // namespace blender::gpu::shader
|
||||
|
|
|
|||
|
|
@ -346,6 +346,10 @@ void SourceProcessor::parse_defines(Parser &parser)
|
|||
{
|
||||
parser().foreach_match<true>("#A", [&](const vector<Token> &tokens) {
|
||||
if (tokens[1].str() == "define") {
|
||||
if (tokens[1].next().str().starts_with("LIGHT_STACK_SIZE_")) {
|
||||
/* WORKAROUND: Avoid warning caused by EEVEE macro setup. */
|
||||
return;
|
||||
}
|
||||
metadata_.create_infos_defines.emplace_back(tokens[1].next().scope().str_with_whitespace());
|
||||
}
|
||||
if (tokens[1].str() == "undef") {
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ template<typename T> struct union_t {
|
|||
* WORKAROUND(fclem): Only used for cases when passing down the resource_table is impractical.
|
||||
* Note that this placeholder is just for the code to compile.
|
||||
*/
|
||||
#define resource_table_get(table_type) (*(table_type *)(new char[1]))
|
||||
#define resource_table_get(table_type) (*(table_type *)(new char[64]))
|
||||
|
||||
/**
|
||||
* Member hiding type.
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ RESHAPE(float3x3, mat3x3, mat3x4)
|
|||
* WORKAROUND(fclem): Only used for cases when passing down the resource_table is impractical.
|
||||
* Note that this placeholder is just for the code to compile.
|
||||
*/
|
||||
#define resource_table_get(table_type) table_type()
|
||||
#define resource_table_get(table_type) table_type##_ctor_()
|
||||
|
||||
/* Incompatible keywords. */
|
||||
#define static
|
||||
|
|
|
|||
|
|
@ -1440,6 +1440,12 @@ void func([[resource_table]] Resources &srt)
|
|||
} else {
|
||||
test;
|
||||
}
|
||||
|
||||
if (srt.use_color_band) [[static_branch]] {
|
||||
if (srt.use_color_band) [[static_branch]] {
|
||||
test;
|
||||
}
|
||||
}
|
||||
}
|
||||
)";
|
||||
string expect = R"(
|
||||
|
|
@ -1544,13 +1550,28 @@ void func(Resources srt)
|
|||
{
|
||||
test;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SRT_CONSTANT_use_color_band
|
||||
#line 38
|
||||
{
|
||||
|
||||
#if SRT_CONSTANT_use_color_band
|
||||
#line 39
|
||||
{
|
||||
test;
|
||||
}
|
||||
|
||||
#endif
|
||||
#line 37
|
||||
#line 42
|
||||
}
|
||||
|
||||
#endif
|
||||
#line 43
|
||||
}
|
||||
|
||||
#endif
|
||||
#line 38
|
||||
#line 44
|
||||
)";
|
||||
string error;
|
||||
string output = process_test_string(input, error);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue