EEVEE-Next: Irradiance Cache: Initial Implementation #108639

Merged
Clément Foucault merged 86 commits from fclem/blender:eevee-next-irradiance-cache into main 2023-06-23 08:39:52 +02:00
12 changed files with 87 additions and 29 deletions
Showing only changes of commit 73f96fe216 - Show all commits

View File

@ -596,6 +596,7 @@ class RENDER_PT_eevee_next_indirect_lighting(RenderButtonsPanel, Panel):
col.label(text=cache_info)
col.prop(props, "gi_auto_bake")
col.prop(props, "gi_diffuse_bounces")
col.prop(props, "gi_irradiance_samples")

View File

@ -499,6 +499,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_surf_lib.glsl
engines/eevee_next/shaders/eevee_surf_shadow_frag.glsl
engines/eevee_next/shaders/eevee_surf_world_frag.glsl
engines/eevee_next/shaders/eevee_surfel_bounce_comp.glsl
engines/eevee_next/shaders/eevee_surfel_light_comp.glsl
engines/eevee_next/shaders/eevee_surfel_list_build_comp.glsl
engines/eevee_next/shaders/eevee_surfel_list_sort_comp.glsl

View File

@ -535,19 +535,20 @@ void Instance::light_bake_irradiance(LightCache *&r_light_cache,
return;
}
/* TODO(fclem): Multiple bounce. We need to use the previous bounce result. */
for (int bounce = 0; bounce < 1; bounce++) {
for (auto i : light_probes.grids.index_range()) {
custom_pipeline_wrapper([&]() {
/* TODO: lightprobe visibility group option. */
manager->begin_sync();
render_sync();
manager->end_sync();
irradiance_cache.bake.surfels_create(light_probes.grids[i]);
irradiance_cache.bake.surfels_lights_eval();
});
for (auto i : light_probes.grids.index_range()) {
custom_pipeline_wrapper([&]() {
/* TODO: lightprobe visibility group option. */
manager->begin_sync();
render_sync();
manager->end_sync();
irradiance_cache.bake.surfels_create(light_probes.grids[i]);
irradiance_cache.bake.surfels_lights_eval();
});
sampling.reset();
int bounce_len = scene->eevee.gi_diffuse_bounces;
/* Start at bounce 1 as 0 bounce is no indirect lighting. */
for (int bounce = 1; bounce <= bounce_len; bounce++) {
sampling.init(scene);
while (!sampling.finished()) {
context_wrapper([&]() {
/* Batch ray cast by pack of 16 to avoid too much overhead of
@ -556,11 +557,19 @@ void Instance::light_bake_irradiance(LightCache *&r_light_cache,
sampling.step();
irradiance_cache.bake.propagate_light_sample();
}
if (sampling.finished()) {
irradiance_cache.bake.accumulate_bounce();
}
irradiance_cache.bake.read_result(r_light_cache->grids[i]);
});
// do_update = true;
}
}
if (bounce_len == 0) {
/* Still read result for debugging surfel direct lighting. */
context_wrapper([&]() { irradiance_cache.bake.read_result(r_light_cache->grids[i]); });
}
}
r_light_cache->flag &= ~LIGHTCACHE_BAKING;

View File

@ -124,6 +124,7 @@ void IrradianceBake::sync()
PassSimple::Sub &sub = pass.sub("ListSort");
sub.shader_set(inst_.shaders.static_shader_get(SURFEL_LIST_SORT));
sub.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
sub.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
sub.bind_ssbo("list_start_buf", &list_start_buf_);
sub.bind_ssbo("list_info_buf", &list_info_buf_);
sub.barrier(GPU_BARRIER_SHADER_STORAGE);
@ -143,6 +144,15 @@ void IrradianceBake::sync()
pass.init();
/* TODO */
}
{
PassSimple &pass = surfel_light_bounce_ps_;
pass.init();
pass.shader_set(inst_.shaders.static_shader_get(SURFEL_BOUNCE));
pass.bind_ssbo(SURFEL_BUF_SLOT, &surfels_buf_);
pass.bind_ssbo(CAPTURE_BUF_SLOT, &capture_info_buf_);
pass.barrier(GPU_BARRIER_SHADER_STORAGE);
pass.dispatch(&dispatch_per_surfel_);
}
}
void IrradianceBake::surfels_create(const IrradianceGrid &grid)
@ -304,6 +314,11 @@ void IrradianceBake::propagate_light_sample()
inst_.manager->submit(surfel_light_propagate_ps_, ray_view);
}
void IrradianceBake::accumulate_bounce()
{
inst_.manager->submit(surfel_light_bounce_ps_);
}
void IrradianceBake::read_result(LightCacheIrradianceGrid &light_cache_grid)
{
switch (inst_.debug_mode) {

View File

@ -39,6 +39,8 @@ class IrradianceBake {
PassSimple surfel_light_eval_ps_ = {"LightEval"};
/** Propagate light from surfel to surfel. */
PassSimple surfel_light_propagate_ps_ = {"LightPropagate"};
/** Start of a light bounce. Accumulate light from previous propagation. */
PassSimple surfel_light_bounce_ps_ = {"LightBounce"};
/** Capture surfel lighting to irradiance samples. */
PassSimple irradiance_capture_ps_ = {"IrradianceCapture"};
@ -85,6 +87,8 @@ class IrradianceBake {
void surfels_lights_eval();
/** Propagate light from surfel to surfel in a random direction over the sphere. */
void propagate_light_sample();
/** Accumulate light inside `surfel.radiance_bounce` to `surfel.radiance`. */
void accumulate_bounce();
/** Read grid final irradiance back to CPU into \a light_cache_grid . */
void read_result(LightCacheIrradianceGrid &light_cache_grid);

View File

@ -26,6 +26,7 @@ void Sampling::init(const Scene *scene)
{
if (inst_.is_baking()) {
sample_count_ = max_ii(1, scene->eevee.gi_irradiance_samples);
sample_ = 0;
}
else {
sample_count_ = inst_.is_viewport() ? scene->eevee.taa_samples :

View File

@ -172,6 +172,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_
return "eevee_shadow_tag_usage_opaque";
case SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT:
return "eevee_shadow_tag_usage_transparent";
case SURFEL_BOUNCE:
return "eevee_surfel_bounce";
case SURFEL_LIGHT:
return "eevee_surfel_light";
case SURFEL_LIST_BUILD:

View File

@ -80,6 +80,7 @@ enum eShaderType {
SHADOW_TILEMAP_TAG_USAGE_OPAQUE,
SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT,
SURFEL_BOUNCE,
SURFEL_LIGHT,
SURFEL_LIST_BUILD,
SURFEL_LIST_SORT,

View File

@ -3,8 +3,6 @@ void main()
{
Surfel surfel = surfels_buf[surfel_index];
vec4 radiance_bounce = gl_FrontFacing ? surfel.radiance_bounce_front :
surfel.radiance_bounce_back;
vec3 radiance = gl_FrontFacing ? surfel.radiance_front : surfel.radiance_back;
switch (eDebugMode(debug_mode)) {
@ -13,9 +11,7 @@ void main()
out_color = vec4(pow(surfel.normal * 0.5 + 0.5, vec3(2.2)), 0.0);
break;
case DEBUG_IRRADIANCE_CACHE_SURFELS_IRRADIANCE:
out_color = (radiance_bounce.w > 0.0) ?
vec4(radiance + radiance_bounce.rgb / radiance_bounce.w, 0.0) :
vec4(radiance, 0.0);
out_color = vec4(radiance, 0.0);
break;
}

View File

@ -0,0 +1,24 @@
/**
* Accumulate light from a bounce of indirect light into each surfel radiance.
* This feeds back the light for the next bounce.
*/
#pragma BLENDER_REQUIRE(common_math_lib.glsl)
void main()
{
int surfel_index = int(gl_GlobalInvocationID);
if (surfel_index >= capture_info_buf.surfel_len) {
return;
}
vec4 radiance_bounce_front = surfel_buf[surfel_index].radiance_bounce_front;
vec4 radiance_bounce_back = surfel_buf[surfel_index].radiance_bounce_back;
surfel_buf[surfel_index].radiance_front += radiance_bounce_front.rgb *
safe_rcp(radiance_bounce_front.w);
surfel_buf[surfel_index].radiance_back += radiance_bounce_back.rgb *
safe_rcp(radiance_bounce_back.w);
surfel_buf[surfel_index].radiance_bounce_front = vec4(0.0);
surfel_buf[surfel_index].radiance_bounce_back = vec4(0.0);
}

View File

@ -20,13 +20,13 @@
*/
void radiance_transfer(Surfel surfel_a, inout Surfel surfel_b)
{
bool facing = dot(surfel_a.normal, surfel_b.normal) < 0.0;
vec3 L = normalize(surfel_a.position - surfel_b.position);
vec3 N = surfel_b.normal;
float NL = dot(N, L);
float pdf = abs(NL);
bool facing = dot(-L, surfel_a.normal) > 0.0;
vec3 irradiance = facing ? surfel_a.radiance_front : surfel_a.radiance_back;
irradiance *= M_1_PI;
if (NL > 0.0) {
surfel_b.radiance_bounce_front += vec4(surfel_b.albedo_front * irradiance * pdf, pdf);

View File

@ -18,41 +18,45 @@ GPU_SHADER_CREATE_INFO(eevee_debug_surfels)
.push_constant(Type::INT, "debug_mode")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_surfel_common)
.storage_buf(SURFEL_BUF_SLOT, Qualifier::READ_WRITE, "Surfel", "surfel_buf[]")
.storage_buf(CAPTURE_BUF_SLOT, Qualifier::READ, "CaptureInfoData", "capture_info_buf");
GPU_SHADER_CREATE_INFO(eevee_surfel_light)
.local_group_size(SURFEL_GROUP_SIZE)
.additional_info("eevee_shared",
"draw_view",
"eevee_utility_texture",
"eevee_surfel_common",
"eevee_light_data",
"eevee_shadow_data")
.compute_source("eevee_surfel_light_comp.glsl")
.storage_buf(SURFEL_BUF_SLOT, Qualifier::READ_WRITE, "Surfel", "surfel_buf[]")
.storage_buf(CAPTURE_BUF_SLOT, Qualifier::READ, "CaptureInfoData", "capture_info_buf")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_surfel_bounce)
.local_group_size(SURFEL_GROUP_SIZE)
.additional_info("eevee_shared", "eevee_surfel_common")
.compute_source("eevee_surfel_bounce_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_surfel_list_build)
.local_group_size(SURFEL_GROUP_SIZE)
.additional_info("eevee_shared", "draw_view")
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
.storage_buf(0, Qualifier::READ_WRITE, "int", "list_start_buf[]")
.storage_buf(SURFEL_BUF_SLOT, Qualifier::READ_WRITE, "Surfel", "surfel_buf[]")
.storage_buf(CAPTURE_BUF_SLOT, Qualifier::READ, "CaptureInfoData", "capture_info_buf")
.storage_buf(6, Qualifier::READ_WRITE, "SurfelListInfoData", "list_info_buf")
.compute_source("eevee_surfel_list_build_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_surfel_list_sort)
.local_group_size(SURFEL_LIST_GROUP_SIZE)
.additional_info("eevee_shared", "draw_view")
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
.storage_buf(0, Qualifier::READ_WRITE, "int", "list_start_buf[]")
.storage_buf(SURFEL_BUF_SLOT, Qualifier::READ_WRITE, "Surfel", "surfel_buf[]")
.storage_buf(6, Qualifier::READ, "SurfelListInfoData", "list_info_buf")
.compute_source("eevee_surfel_list_sort_comp.glsl")
.do_static_compilation(true);
GPU_SHADER_CREATE_INFO(eevee_surfel_ray)
.local_group_size(SURFEL_GROUP_SIZE)
.additional_info("eevee_shared", "draw_view")
.storage_buf(SURFEL_BUF_SLOT, Qualifier::READ_WRITE, "Surfel", "surfel_buf[]")
.storage_buf(CAPTURE_BUF_SLOT, Qualifier::READ, "CaptureInfoData", "capture_info_buf")
.additional_info("eevee_shared", "eevee_surfel_common", "draw_view")
.compute_source("eevee_surfel_ray_comp.glsl")
.do_static_compilation(true);