From 03ead30027814f348f659b73cbfc8da0b653771c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 14 Jul 2023 11:22:18 +0200 Subject: [PATCH] Eevee-next: Reflective Light Baking This PR introduces baking reflective light from light probes. Light probes are baked on the fly when the light probe data has changed. It doesn't update directly when other scene data is changed in the viewport. When doing image rendering the light probes are updated on each frame. Currently the world probe and closest reflection probe are composited together in shader. This allows different resolutions. We expect that we eventually composite it before usage. This would improve the performance. Unclear if we would support both compositing options eventually. Pull Request: https://projects.blender.org/blender/blender/pulls/109909 --- .../bl_ui/properties_data_lightprobe.py | 3 + .../draw/engines/eevee_next/eevee_instance.cc | 23 +- .../draw/engines/eevee_next/eevee_instance.hh | 5 + .../draw/engines/eevee_next/eevee_material.cc | 20 +- .../draw/engines/eevee_next/eevee_material.hh | 9 +- .../draw/engines/eevee_next/eevee_pipeline.cc | 198 ++++++++++++++- .../draw/engines/eevee_next/eevee_pipeline.hh | 70 ++++- .../eevee_next/eevee_reflection_probes.cc | 239 ++++++++---------- .../eevee_next/eevee_reflection_probes.hh | 62 ++++- .../draw/engines/eevee_next/eevee_shader.cc | 2 + .../draw/engines/eevee_next/eevee_shader.hh | 1 + .../draw/engines/eevee_next/eevee_sync.cc | 5 + .../draw/engines/eevee_next/eevee_view.cc | 78 +++++- .../draw/engines/eevee_next/eevee_view.hh | 3 +- .../shaders/eevee_deferred_light_frag.glsl | 3 + .../eevee_reflection_probe_remap_comp.glsl | 8 +- .../shaders/infos/eevee_deferred_info.hh | 12 +- .../infos/eevee_reflection_probe_info.hh | 1 + 18 files changed, 576 insertions(+), 166 deletions(-) diff --git a/scripts/startup/bl_ui/properties_data_lightprobe.py b/scripts/startup/bl_ui/properties_data_lightprobe.py index 26c393dd021..73d75a0d37a 100644 --- a/scripts/startup/bl_ui/properties_data_lightprobe.py +++ b/scripts/startup/bl_ui/properties_data_lightprobe.py @@ -114,6 +114,9 @@ class DATA_PT_lightprobe_eevee_next(DataButtonsPanel, Panel): elif probe.type == 'CUBEMAP': col = layout.column() col.prop(probe, "resolution") + sub = layout.column(align=True) + sub.prop(probe, "clip_start", text="Clipping Start") + sub.prop(probe, "clip_end", text="End") elif probe.type == 'PLANAR': # Currently unsupported diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 44450299725..a3a64026db3 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -273,6 +273,17 @@ void Instance::render_sync() // DRW_hair_update(); } +bool Instance::do_probe_sync() const +{ + if (materials.queued_shaders_count > 0) { + return false; + } + if (!reflection_probes.update_probes_this_sample_) { + return false; + } + return true; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -297,7 +308,9 @@ void Instance::render_sample() sampling.step(); - capture_view.render(); + capture_view.render_world(); + capture_view.render_probes(); + main_view.render(); motion_blur.step(); @@ -379,6 +392,12 @@ void Instance::render_read_result(RenderLayer *render_layer, const char *view_na void Instance::render_frame(RenderLayer *render_layer, const char *view_name) { + /* TODO(jbakker): should we check on the subtype as well? Now it also populates even when there + * are other light probes in the scene. */ + if (DEG_id_type_any_exists(this->depsgraph, ID_LP)) { + reflection_probes.update_probes_next_sample_ = true; + } + while (!sampling.finished()) { this->render_sample(); @@ -523,7 +542,7 @@ void Instance::light_bake_irradiance( render_sync(); manager->end_sync(); - capture_view.render(); + capture_view.render_world(); irradiance_cache.bake.surfels_create(probe); irradiance_cache.bake.surfels_lights_eval(); diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index c2b1746b3d5..d81fb325687 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -147,6 +147,11 @@ class Instance { void object_sync(Object *ob); void end_sync(); + /** + * Return true when probe pipeline is used during this sample. + */ + bool do_probe_sync() const; + /* Render. */ void render_sync(); diff --git a/source/blender/draw/engines/eevee_next/eevee_material.cc b/source/blender/draw/engines/eevee_next/eevee_material.cc index 5a9c3090652..e925208ece1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.cc +++ b/source/blender/draw/engines/eevee_next/eevee_material.cc @@ -158,7 +158,8 @@ void MaterialModule::begin_sync() MaterialPass MaterialModule::material_pass_get(Object *ob, ::Material *blender_mat, eMaterialPipeline pipeline_type, - eMaterialGeometry geometry_type) + eMaterialGeometry geometry_type, + bool probe_capture) { bNodeTree *ntree = (blender_mat->use_nodes && blender_mat->nodetree != nullptr) ? blender_mat->nodetree : @@ -205,11 +206,13 @@ MaterialPass MaterialModule::material_pass_get(Object *ob, matpass.sub_pass = nullptr; } else { - ShaderKey shader_key(matpass.gpumat, geometry_type, pipeline_type, blender_mat->blend_flag); + ShaderKey shader_key( + matpass.gpumat, geometry_type, pipeline_type, blender_mat->blend_flag, probe_capture); PassMain::Sub *shader_sub = shader_map_.lookup_or_add_cb(shader_key, [&]() { /* First time encountering this shader. Create a sub that will contain materials using it. */ - return inst_.pipelines.material_add(ob, blender_mat, matpass.gpumat, pipeline_type); + return inst_.pipelines.material_add( + ob, blender_mat, matpass.gpumat, pipeline_type, probe_capture); }); if (shader_sub != nullptr) { @@ -248,12 +251,23 @@ Material &MaterialModule::material_sync(Object *ob, * to avoid this shader compilation in another context. */ mat.shading = material_pass_get(ob, blender_mat, surface_pipe, geometry_type); mat.capture = material_pass_get(ob, blender_mat, MAT_PIPE_CAPTURE, geometry_type); + mat.probe_prepass = MaterialPass(); + mat.probe_shading = MaterialPass(); } else { /* Order is important for transparent. */ mat.prepass = material_pass_get(ob, blender_mat, prepass_pipe, geometry_type); mat.shading = material_pass_get(ob, blender_mat, surface_pipe, geometry_type); mat.capture = MaterialPass(); + mat.probe_prepass = MaterialPass(); + mat.probe_shading = MaterialPass(); + + if (inst_.do_probe_sync()) { + mat.probe_prepass = material_pass_get( + ob, blender_mat, MAT_PIPE_DEFERRED_PREPASS, geometry_type, true); + mat.probe_shading = material_pass_get( + ob, blender_mat, MAT_PIPE_DEFERRED, geometry_type, true); + } } if (blender_mat->blend_shadow == MA_BS_NONE) { diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh index e458376cee3..0d779072974 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.hh +++ b/source/blender/draw/engines/eevee_next/eevee_material.hh @@ -149,12 +149,14 @@ struct ShaderKey { ShaderKey(GPUMaterial *gpumat, eMaterialGeometry geometry, eMaterialPipeline pipeline, - char blend_flags) + char blend_flags, + bool probe_capture) { shader = GPU_material_get_shader(gpumat); options = blend_flags; options = (options << 6u) | shader_uuid_from_material_type(pipeline, geometry); options = (options << 16u) | shader_closure_bits_from_flag(gpumat); + options = (options << 1u) | probe_capture; } uint64_t hash() const @@ -214,7 +216,7 @@ struct MaterialPass { struct Material { bool is_alpha_blend_transparent; - MaterialPass shadow, shading, prepass, capture; + MaterialPass shadow, shading, prepass, capture, probe_prepass, probe_shading; }; struct MaterialArray { @@ -268,7 +270,8 @@ class MaterialModule { MaterialPass material_pass_get(Object *ob, ::Material *blender_mat, eMaterialPipeline pipeline_type, - eMaterialGeometry geometry_type); + eMaterialGeometry geometry_type, + bool probe_capture = false); }; /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 8e117a35c88..03724e32a40 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -63,7 +63,8 @@ void BackgroundPipeline::render(View &view) void WorldPipeline::sync(GPUMaterial *gpumat) { const int2 extent(1); - constexpr eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_WRITE; + constexpr eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_WRITE | + GPU_TEXTURE_USAGE_SHADER_READ; dummy_cryptomatte_tx_.ensure_2d(GPU_RGBA32F, extent, usage); dummy_renderpass_tx_.ensure_2d(GPU_RGBA16F, extent, usage); dummy_aov_color_tx_.ensure_2d_array(GPU_RGBA16F, extent, 1, usage); @@ -557,6 +558,201 @@ void DeferredPipeline::render(View &view, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Deferred Probe Layer + * \{ */ + +void DeferredProbeLayer::begin_sync() +{ + { + prepass_ps_.init(); + { + /* Common resources. */ + + /* Textures. */ + prepass_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + /* Uniform Buffer. */ + prepass_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get()); + + inst_.velocity.bind_resources(&prepass_ps_); + inst_.sampling.bind_resources(&prepass_ps_); + } + + DRWState state_depth_only = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + + prepass_double_sided_ps_ = &prepass_ps_.sub("DoubleSided"); + prepass_double_sided_ps_->state_set(state_depth_only); + + prepass_single_sided_ps_ = &prepass_ps_.sub("SingleSided"); + prepass_single_sided_ps_->state_set(state_depth_only | DRW_STATE_CULL_BACK); + } + { + gbuffer_ps_.init(); + gbuffer_ps_.clear_stencil(0x00u); + gbuffer_ps_.state_stencil(0xFFu, 0xFFu, 0xFFu); + + { + /* Common resources. */ + + /* G-buffer. */ + gbuffer_ps_.bind_image(GBUF_CLOSURE_SLOT, &inst_.gbuffer.closure_tx); + gbuffer_ps_.bind_image(GBUF_COLOR_SLOT, &inst_.gbuffer.color_tx); + /* RenderPasses & AOVs. */ + gbuffer_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); + gbuffer_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); + /* Cryptomatte. */ + gbuffer_ps_.bind_image(RBUFS_CRYPTOMATTE_SLOT, &inst_.render_buffers.cryptomatte_tx); + /* Storage Buffer. */ + /* Textures. */ + gbuffer_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + /* Uniform Buffer. */ + gbuffer_ps_.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get()); + gbuffer_ps_.bind_ubo(RBUFS_BUF_SLOT, &inst_.render_buffers.data); + + inst_.sampling.bind_resources(&gbuffer_ps_); + inst_.hiz_buffer.bind_resources(&gbuffer_ps_); + inst_.ambient_occlusion.bind_resources(&gbuffer_ps_); + inst_.cryptomatte.bind_resources(&gbuffer_ps_); + } + + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_EQUAL | + DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; + + gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided"); + gbuffer_double_sided_ps_->state_set(state); + + gbuffer_single_sided_ps_ = &gbuffer_ps_.sub("SingleSided"); + gbuffer_single_sided_ps_->state_set(state | DRW_STATE_CULL_BACK); + } + + /* Light eval resources.*/ + { + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE; + dummy_light_tx_.ensure_2d(GPU_RGBA16F, int2(1), usage); + } +} + +void DeferredProbeLayer::end_sync() +{ + if (closure_bits_ & (CLOSURE_DIFFUSE | CLOSURE_REFLECTION)) { + const bool is_last_eval_pass = !(closure_bits_ & CLOSURE_SSS); + + eval_light_ps_.init(); + /* Use stencil test to reject pixel not written by this layer. */ + eval_light_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | + DRW_STATE_BLEND_CUSTOM); + eval_light_ps_.state_stencil(0x00u, 0x00u, (CLOSURE_DIFFUSE | CLOSURE_REFLECTION)); + eval_light_ps_.shader_set(inst_.shaders.static_shader_get(DEFERRED_LIGHT_DIFFUSE_ONLY)); + eval_light_ps_.bind_image("out_diffuse_light_img", dummy_light_tx_); + eval_light_ps_.bind_image("out_specular_light_img", dummy_light_tx_); + eval_light_ps_.bind_texture("gbuffer_closure_tx", &inst_.gbuffer.closure_tx); + eval_light_ps_.bind_texture("gbuffer_color_tx", &inst_.gbuffer.color_tx); + eval_light_ps_.push_constant("is_last_eval_pass", is_last_eval_pass); + eval_light_ps_.bind_image(RBUFS_COLOR_SLOT, &inst_.render_buffers.rp_color_tx); + eval_light_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx); + eval_light_ps_.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + eval_light_ps_.bind_texture(SSS_TRANSMITTANCE_TEX_SLOT, + inst_.subsurface.transmittance_tx_get()); + eval_light_ps_.bind_ubo(RBUFS_BUF_SLOT, &inst_.render_buffers.data); + + inst_.lights.bind_resources(&eval_light_ps_); + inst_.shadows.bind_resources(&eval_light_ps_); + inst_.sampling.bind_resources(&eval_light_ps_); + inst_.hiz_buffer.bind_resources(&eval_light_ps_); + inst_.ambient_occlusion.bind_resources(&eval_light_ps_); + inst_.reflection_probes.bind_resources(&eval_light_ps_); + inst_.irradiance_cache.bind_resources(&eval_light_ps_); + + eval_light_ps_.barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS); + eval_light_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); + } +} + +PassMain::Sub *DeferredProbeLayer::prepass_add(::Material *blender_mat, GPUMaterial *gpumat) +{ + PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? + prepass_single_sided_ps_ : + prepass_double_sided_ps_; + + return &pass->sub(GPU_material_get_name(gpumat)); +} + +PassMain::Sub *DeferredProbeLayer::material_add(::Material *blender_mat, GPUMaterial *gpumat) +{ + eClosureBits closure_bits = shader_closure_bits_from_flag(gpumat); + closure_bits_ |= closure_bits; + + PassMain::Sub *pass = (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) ? + gbuffer_single_sided_ps_ : + gbuffer_double_sided_ps_; + pass = &pass->sub(GPU_material_get_name(gpumat)); + pass->state_stencil(closure_bits, 0xFFu, 0xFFu); + return pass; +} + +void DeferredProbeLayer::render(View &view, + Framebuffer &prepass_fb, + Framebuffer &combined_fb, + int2 extent) +{ + GPU_framebuffer_bind(prepass_fb); + inst_.manager->submit(prepass_ps_, view); + + inst_.hiz_buffer.set_dirty(); + inst_.lights.set_view(view, extent); + inst_.shadows.set_view(view); + inst_.irradiance_cache.set_view(view); + + inst_.gbuffer.acquire(extent, closure_bits_); + + GPU_framebuffer_bind(combined_fb); + inst_.manager->submit(gbuffer_ps_, view); + + inst_.manager->submit(eval_light_ps_, view); + + inst_.gbuffer.release(); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Deferred Probe Pipeline + * + * Closure data are written to intermediate buffer allowing screen space processing. + * \{ */ + +void DeferredProbePipeline::begin_sync() +{ + opaque_layer_.begin_sync(); +} + +void DeferredProbePipeline::end_sync() +{ + opaque_layer_.end_sync(); +} + +PassMain::Sub *DeferredProbePipeline::prepass_add(::Material *blender_mat, GPUMaterial *gpumat) +{ + return opaque_layer_.prepass_add(blender_mat, gpumat); +} + +PassMain::Sub *DeferredProbePipeline::material_add(::Material *blender_mat, GPUMaterial *gpumat) +{ + return opaque_layer_.material_add(blender_mat, gpumat); +} + +void DeferredProbePipeline::render(View &view, + Framebuffer &prepass_fb, + Framebuffer &combined_fb, + int2 extent) +{ + GPU_debug_group_begin("Probe.Render"); + opaque_layer_.render(view, prepass_fb, combined_fb, extent); + GPU_debug_group_end(); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Capture Pipeline * diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index 69fa4014402..467dd444d53 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -210,6 +210,58 @@ class DeferredPipeline { /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Deferred Probe Capture. + * \{ */ +class DeferredProbeLayer { + private: + Instance &inst_; + + PassMain prepass_ps_ = {"Prepass"}; + PassMain::Sub *prepass_single_sided_ps_ = nullptr; + PassMain::Sub *prepass_double_sided_ps_ = nullptr; + + PassMain gbuffer_ps_ = {"Shading"}; + PassMain::Sub *gbuffer_single_sided_ps_ = nullptr; + PassMain::Sub *gbuffer_double_sided_ps_ = nullptr; + + PassSimple eval_light_ps_ = {"EvalLights"}; + + /* Closures bits from the materials in this pass. */ + eClosureBits closure_bits_; + + Texture dummy_light_tx_ = {"dummy_light_accum_tx"}; + + public: + DeferredProbeLayer(Instance &inst) : inst_(inst){}; + + void begin_sync(); + void end_sync(); + + PassMain::Sub *prepass_add(::Material *blender_mat, GPUMaterial *gpumat); + PassMain::Sub *material_add(::Material *blender_mat, GPUMaterial *gpumat); + + void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent); +}; + +class DeferredProbePipeline { + private: + DeferredProbeLayer opaque_layer_; + + public: + DeferredProbePipeline(Instance &inst) : opaque_layer_(inst){}; + + void begin_sync(); + void end_sync(); + + PassMain::Sub *prepass_add(::Material *material, GPUMaterial *gpumat); + PassMain::Sub *material_add(::Material *material, GPUMaterial *gpumat); + + void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb, int2 extent); +}; + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Capture Pipeline * @@ -317,6 +369,7 @@ class PipelineModule { public: BackgroundPipeline background; WorldPipeline world; + DeferredProbePipeline probe; DeferredPipeline deferred; ForwardPipeline forward; ShadowPipeline shadow; @@ -328,6 +381,7 @@ class PipelineModule { PipelineModule(Instance &inst) : background(inst), world(inst), + probe(inst), deferred(inst), forward(inst), shadow(inst), @@ -335,6 +389,7 @@ class PipelineModule { void begin_sync() { + probe.begin_sync(); deferred.begin_sync(); forward.sync(); shadow.sync(); @@ -343,14 +398,27 @@ class PipelineModule { void end_sync() { + probe.end_sync(); deferred.end_sync(); } PassMain::Sub *material_add(Object *ob, ::Material *blender_mat, GPUMaterial *gpumat, - eMaterialPipeline pipeline_type) + eMaterialPipeline pipeline_type, + bool probe_capture) { + if (probe_capture) { + switch (pipeline_type) { + case MAT_PIPE_DEFERRED_PREPASS: + return probe.prepass_add(blender_mat, gpumat); + case MAT_PIPE_DEFERRED: + return probe.material_add(blender_mat, gpumat); + default: + break; + } + } + switch (pipeline_type) { case MAT_PIPE_DEFERRED_PREPASS: return deferred.prepass_add(blender_mat, gpumat, false); diff --git a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc index d638ff5a8bf..ea3a9df451d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -5,13 +5,6 @@ #include "eevee_reflection_probes.hh" #include "eevee_instance.hh" -/* Generate dummy light probe texture. - * - * Baking of Light probes aren't implemented yet. For testing purposes this can be enabled to - * generate a dummy texture. - */ -#define GENERATE_DUMMY_LIGHT_PROBE_TEXTURE false - namespace blender::eevee { void ReflectionProbeModule::init() @@ -36,29 +29,29 @@ void ReflectionProbeModule::init() world_probe.do_update_data = true; world_probe.do_render = true; world_probe.index = 0; + world_probe.clipping_distances = float2(1.0f, 10.0f); probes_.add(world_object_key_, world_probe); probes_tx_.ensure_2d_array(GPU_RGBA16F, int2(max_resolution_), init_num_probes_, - GPU_TEXTURE_USAGE_SHADER_WRITE, + GPU_TEXTURE_USAGE_SHADER_WRITE | GPU_TEXTURE_USAGE_SHADER_READ, nullptr, - REFLECTION_PROBE_MIPMAP_LEVELS); + 9999); GPU_texture_mipmap_mode(probes_tx_, true, true); - /* Cube-map is half of the resolution of the octahedral map. */ - cubemap_tx_.ensure_cube( - GPU_RGBA16F, max_resolution_ / 2, GPU_TEXTURE_USAGE_ATTACHMENT, nullptr, 9999); - GPU_texture_mipmap_mode(cubemap_tx_, true, true); + recalc_lod_factors(); + data_buf_.push_update(); } { PassSimple &pass = remap_ps_; pass.init(); pass.shader_set(instance_.shaders.static_shader_get(REFLECTION_PROBE_REMAP)); - pass.bind_texture("cubemap_tx", cubemap_tx_); - pass.bind_image("octahedral_img", probes_tx_); + pass.bind_texture("cubemap_tx", &cubemap_tx_); + pass.bind_image("octahedral_img", &probes_tx_); pass.bind_ssbo(REFLECTION_PROBE_BUF_SLOT, data_buf_); + pass.push_constant("reflection_probe_index", &reflection_probe_index_); pass.dispatch(&dispatch_probe_pack_); } } @@ -69,39 +62,24 @@ void ReflectionProbeModule::begin_sync() reflection_probe.is_probe_used = false; } } + + update_probes_this_sample_ = false; + if (update_probes_next_sample_) { + update_probes_this_sample_ = true; + instance_.sampling.reset(); + } } int ReflectionProbeModule::needed_layers_get() const { - const int max_probe_data_index = reflection_probe_data_index_max(); int max_layer = 0; - for (const ReflectionProbeData &data : - Span(data_buf_.data(), max_probe_data_index + 1)) - { - max_layer = max_ii(max_layer, data.layer); + for (const ReflectionProbe &probe : probes_.values()) { + const ReflectionProbeData &probe_data = data_buf_[probe.index]; + max_layer = max_ii(max_layer, probe_data.layer); } return max_layer + 1; } -void ReflectionProbeModule::sync(ReflectionProbe &probe) -{ - switch (probe.type) { - case ReflectionProbe::Type::World: { - break; - } - case ReflectionProbe::Type::Probe: { - if (probe.do_render) { - upload_dummy_texture(probe); - probe.do_render = false; - } - break; - } - case ReflectionProbe::Type::Unused: { - break; - } - } -} - static int layer_subdivision_for(const int max_resolution, const eLightProbeResolution probe_resolution) { @@ -119,7 +97,6 @@ void ReflectionProbeModule::sync_world(::World *world, WorldHandle & /*ob_handle void ReflectionProbeModule::sync_object(Object *ob, ObjectHandle &ob_handle) { -#if GENERATE_DUMMY_LIGHT_PROBE_TEXTURE const ::LightProbe *light_probe = (::LightProbe *)ob->data; if (light_probe->type != LIGHTPROBE_TYPE_CUBE) { return; @@ -128,15 +105,27 @@ void ReflectionProbeModule::sync_object(Object *ob, ObjectHandle &ob_handle) int subdivision = layer_subdivision_for( max_resolution_, static_cast(light_probe->resolution)); ReflectionProbe &probe = find_or_insert(ob_handle, subdivision); - probe.do_update_data |= is_dirty; + probe.do_render |= is_dirty; probe.is_probe_used = true; + /* Only update data when rerendering the probes to reduce flickering. */ + if (!instance_.do_probe_sync()) { + update_probes_next_sample_ = true; + return; + } + + probe.do_update_data |= is_dirty; + probe.clipping_distances = float2(light_probe->clipsta, light_probe->clipend); + ReflectionProbeData &probe_data = data_buf_[probe.index]; + if (probe_data.layer_subdivision != subdivision) { + ReflectionProbeData new_probe_data = find_empty_reflection_probe_data(subdivision); + probe_data.layer = new_probe_data.layer; + probe_data.layer_subdivision = new_probe_data.layer_subdivision; + probe_data.area_index = new_probe_data.area_index; + } + probe_data.pos = float3(float4x4(ob->object_to_world) * float4(0.0, 0.0, 0.0, 1.0)); - probe_data.layer_subdivision = subdivision; -#else - UNUSED_VARS(ob, ob_handle); -#endif } ReflectionProbe &ReflectionProbeModule::find_or_insert(ObjectHandle &ob_handle, @@ -290,62 +279,32 @@ void ReflectionProbeModule::end_sync() { remove_unused_probes(); + const bool probe_sync_done = instance_.do_probe_sync(); + if (!probe_sync_done) { + return; + } + int number_layers_needed = needed_layers_get(); int current_layers = probes_tx_.depth(); bool resize_layers = current_layers < number_layers_needed; + if (resize_layers) { - /* TODO: Create new texture and copy previous texture so we don't need to rerender all the - * probes.*/ probes_tx_.ensure_2d_array(GPU_RGBA16F, int2(max_resolution_), number_layers_needed, - GPU_TEXTURE_USAGE_SHADER_WRITE, + GPU_TEXTURE_USAGE_SHADER_WRITE | GPU_TEXTURE_USAGE_SHADER_READ, nullptr, - REFLECTION_PROBE_MIPMAP_LEVELS); + 9999); GPU_texture_mipmap_mode(probes_tx_, true, true); + + for (ReflectionProbe &probe : probes_.values()) { + probe.do_update_data = true; + probe.do_render = true; + } } recalc_lod_factors(); data_buf_.push_update(); - - /* Regenerate mipmaps when a probe texture is updated. It can be postponed when the world probe - * is also updated. In this case it would happen as part of the WorldProbePipeline. */ - bool regenerate_mipmaps = false; - bool regenerate_mipmaps_postponed = false; - - for (ReflectionProbe &probe : probes_.values()) { - if (resize_layers) { - probe.do_update_data = true; - probe.do_render = true; - } - - if (!probe.needs_update()) { - continue; - } - sync(probe); - - switch (probe.type) { - case ReflectionProbe::Type::World: - regenerate_mipmaps_postponed = true; - break; - - case ReflectionProbe::Type::Probe: - regenerate_mipmaps = probe.do_render; - break; - - case ReflectionProbe::Type::Unused: - BLI_assert_unreachable(); - break; - } - probe.do_update_data = false; - } - - if (regenerate_mipmaps) { - GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); - if (!regenerate_mipmaps_postponed) { - GPU_texture_update_mipmap_chain(probes_tx_); - } - } } void ReflectionProbeModule::remove_unused_probes() @@ -470,57 +429,73 @@ std::ostream &operator<<(std::ostream &os, const ReflectionProbe &probe) return os; } -void ReflectionProbeModule::upload_dummy_texture(const ReflectionProbe &probe) -{ - const ReflectionProbeData &probe_data = data_buf_[probe.index]; - const int resolution = max_resolution_ >> probe_data.layer_subdivision; - float4 *data = static_cast( - MEM_mallocN(sizeof(float4) * resolution * resolution, __func__)); - - /* Generate dummy checker pattern. */ - int index = 0; - const int BLOCK_SIZE = max_ii(1024 >> probe_data.layer_subdivision, 1); - for (int y : IndexRange(resolution)) { - for (int x : IndexRange(resolution)) { - int tx = (x / BLOCK_SIZE) & 1; - int ty = (y / BLOCK_SIZE) & 1; - bool solid = (tx + ty) & 1; - if (solid) { - data[index] = float4((probe.index & 1) == 0 ? 0.0f : 1.0f, - (probe.index & 2) == 0 ? 0.0f : 1.0f, - (probe.index & 4) == 0 ? 0.0f : 1.0f, - 1.0f); - } - else { - data[index] = float4(0.0f); - } - - index++; - } - } - - /* Upload the checker pattern. */ - int probes_per_dimension = 1 << probe_data.layer_subdivision; - int2 probe_area_pos(probe_data.area_index % probes_per_dimension, - probe_data.area_index / probes_per_dimension); - int2 pos = probe_area_pos * int2(max_resolution_ / probes_per_dimension); - GPU_texture_update_sub( - probes_tx_, GPU_DATA_FLOAT, data, UNPACK2(pos), probe_data.layer, resolution, resolution, 1); - - MEM_freeN(data); -} - /** \} */ -void ReflectionProbeModule::remap_to_octahedral_projection() +std::optional ReflectionProbeModule::update_info_pop( + const ReflectionProbe::Type probe_type) { - const ReflectionProbe &world_probe = probes_.lookup(world_object_key_); - const ReflectionProbeData &probe_data = data_buf_[world_probe.index]; + const bool do_probe_sync = instance_.do_probe_sync(); + const int max_shift = int(log2(max_resolution_)); + for (const Map::Item &item : probes_.items()) { + if (!item.value.do_render) { + continue; + } + if (probe_type == ReflectionProbe::Type::World && item.value.type != probe_type) { + return std::nullopt; + } + if (probe_type == ReflectionProbe::Type::Probe && item.value.type != probe_type) { + continue; + } + /* Do not update this probe during this sample. */ + if (item.value.type == ReflectionProbe::Type::Probe && !do_probe_sync) { + continue; + } + probes_.lookup(item.key).do_render = false; + + ReflectionProbeData &probe_data = data_buf_[item.value.index]; + ReflectionProbeUpdateInfo info = {}; + info.probe_type = item.value.type; + info.object_key = item.key; + info.resolution = 1 << (max_shift - probe_data.layer_subdivision - 1); + info.clipping_distances = item.value.clipping_distances; + info.probe_pos = probe_data.pos; + + if (cubemap_tx_.ensure_cube(GPU_RGBA16F, + info.resolution, + GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_SHADER_READ)) + { + GPU_texture_mipmap_mode(cubemap_tx_, false, true); + } + + return info; + } + + /* Check reset probe updating as we completed rendering all Probes. */ + if (probe_type == ReflectionProbe::Type::Probe && update_probes_this_sample_ && + update_probes_next_sample_) + { + update_probes_next_sample_ = false; + } + + return std::nullopt; +} + +void ReflectionProbeModule::remap_to_octahedral_projection(uint64_t object_key) +{ + const ReflectionProbe &probe = probes_.lookup(object_key); + const ReflectionProbeData &probe_data = data_buf_[probe.index]; + + /* Update shader parameters that change per dispatch. */ + reflection_probe_index_ = probe.index; dispatch_probe_pack_ = int3(int2(ceil_division(max_resolution_ >> probe_data.layer_subdivision, REFLECTION_PROBE_GROUP_SIZE)), 1); + instance_.manager->submit(remap_ps_); - /* TODO: Performance - Should only update the area that has changed. */ +} + +void ReflectionProbeModule::update_probes_texture_mipmaps() +{ GPU_texture_update_mipmap_chain(probes_tx_); } diff --git a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh index 74790c10bcb..66624d99e43 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -22,9 +22,10 @@ class Instance; struct ObjectHandle; struct WorldHandle; class CaptureView; +struct ReflectionProbeUpdateInfo; /* -------------------------------------------------------------------- */ -/** \name Reflection Probes +/** \name Reflection Probe * \{ */ struct ReflectionProbe { @@ -32,7 +33,8 @@ struct ReflectionProbe { Type type = Type::Unused; - /* Probe data needs to be updated. */ + /* Probe data needs to be updated. + * TODO: Remove this flag? */ bool do_update_data = false; /* Should the area in the probes_tx_ be updated? */ bool do_render = false; @@ -50,6 +52,11 @@ struct ReflectionProbe { */ int index = -1; + /** + * Far and near clipping distances for rendering + */ + float2 clipping_distances; + /** * Check if the probe needs to be updated during this sample. */ @@ -67,6 +74,12 @@ struct ReflectionProbe { } }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reflection Probe Module + * \{ */ + class ReflectionProbeModule { private: /** The max number of probes to initially allocate. */ @@ -85,8 +98,6 @@ class ReflectionProbeModule { ReflectionProbeDataBuf data_buf_; Map probes_; - /** Texture containing a cubemap used as input for updating #probes_tx_. */ - Texture cubemap_tx_ = {"Probe.Cubemap"}; /** Probes texture stored in octahedral mapping. */ Texture probes_tx_ = {"Probes"}; @@ -94,6 +105,17 @@ class ReflectionProbeModule { int3 dispatch_probe_pack_ = int3(0); + /** + * Texture containing a cubemap where the probe should be rendering to. + * + * NOTE: TextureFromPool doesn't support cubemaps. + */ + Texture cubemap_tx_ = {"Probe.Cubemap"}; + int reflection_probe_index_ = 0; + + bool update_probes_next_sample_ = false; + bool update_probes_this_sample_ = false; + public: ReflectionProbeModule(Instance &instance) : instance_(instance) {} @@ -115,7 +137,6 @@ class ReflectionProbeModule { void debug_print() const; private: - void sync(ReflectionProbe &cubemap); ReflectionProbe &find_or_insert(ObjectHandle &ob_handle, int subdivision_level); /** Get the number of layers that is needed to store probes. */ @@ -140,16 +161,41 @@ class ReflectionProbeModule { */ ReflectionProbeData find_empty_reflection_probe_data(int subdivision_level) const; - void upload_dummy_texture(const ReflectionProbe &probe); - - void remap_to_octahedral_projection(); + /** + * Pop the next reflection probe that requires to be updated. + */ + std::optional update_info_pop(ReflectionProbe::Type probe_type); + void remap_to_octahedral_projection(uint64_t object_key); + void update_probes_texture_mipmaps(); /* Capture View requires access to the cube-maps texture for frame-buffer configuration. */ friend class CaptureView; + /* Instance requires access to #update_probes_this_sample_ */ + friend class Instance; }; std::ostream &operator<<(std::ostream &os, const ReflectionProbeModule &module); std::ostream &operator<<(std::ostream &os, const ReflectionProbeData &probe_data); std::ostream &operator<<(std::ostream &os, const ReflectionProbe &probe); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Reflection Probe Update Info + * \{ */ + +struct ReflectionProbeUpdateInfo { + float3 probe_pos; + ReflectionProbe::Type probe_type; + /** + * Resolution of the cubemap to be rendered. + */ + int resolution; + + float2 clipping_distances; + uint64_t object_key; +}; + +/** \} */ + } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 997e4ed9aae..cd0160de836 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -90,6 +90,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_film_cryptomatte_post"; case DEFERRED_LIGHT: return "eevee_deferred_light"; + case DEFERRED_LIGHT_DIFFUSE_ONLY: + return "eevee_deferred_light_diffuse"; case HIZ_DEBUG: return "eevee_hiz_debug"; case HIZ_UPDATE: diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh index 820904f5b4b..840192ba07f 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh @@ -33,6 +33,7 @@ enum eShaderType { FILM_CRYPTOMATTE_POST, DEFERRED_LIGHT, + DEFERRED_LIGHT_DIFFUSE_ONLY, DEBUG_SURFELS, diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index 24a96b5767f..c510891d5ba 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -122,6 +122,7 @@ void SyncModule::sync_mesh(Object *ob, bool is_shadow_caster = false; bool is_alpha_blend = false; + bool do_probe_sync = inst_.do_probe_sync(); for (auto i : material_array.gpu_materials.index_range()) { GPUBatch *geom = mat_geom[i]; if (geom == nullptr) { @@ -132,6 +133,10 @@ void SyncModule::sync_mesh(Object *ob, geometry_call(material.prepass.sub_pass, geom, res_handle); geometry_call(material.shadow.sub_pass, geom, res_handle); geometry_call(material.capture.sub_pass, geom, res_handle); + if (do_probe_sync) { + geometry_call(material.probe_prepass.sub_pass, geom, res_handle); + geometry_call(material.probe_shading.sub_pass, geom, res_handle); + } is_shadow_caster = is_shadow_caster || material.shadow.sub_pass != nullptr; is_alpha_blend = is_alpha_blend || material.is_alpha_blend_transparent; diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index b4ac0646caf..25a265ff43a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -195,31 +195,89 @@ void ShadingView::update_view() /** \name Capture View * \{ */ -void CaptureView::render() +void CaptureView::render_world() { - if (!inst_.reflection_probes.do_world_update_get()) { + const std::optional update_info = + inst_.reflection_probes.update_info_pop(ReflectionProbe::Type::World); + if (!update_info.has_value()) { return; } - inst_.reflection_probes.do_world_update_set(false); + View view = {"Capture.View"}; GPU_debug_group_begin("World.Capture"); - View view = {"World.Capture.View"}; for (int face : IndexRange(6)) { + float4x4 view_m4 = cubeface_mat(face); + float4x4 win_m4 = math::projection::perspective(-update_info->clipping_distances.x, + update_info->clipping_distances.x, + -update_info->clipping_distances.x, + update_info->clipping_distances.x, + update_info->clipping_distances.x, + update_info->clipping_distances.y); + view.sync(view_m4, win_m4); + capture_fb_.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE_CUBEFACE(inst_.reflection_probes.cubemap_tx_, face)); GPU_framebuffer_bind(capture_fb_); - - float4x4 view_m4 = cubeface_mat(face); - float4x4 win_m4 = math::projection::perspective(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 10.0f); - view.sync(view_m4, win_m4); inst_.pipelines.world.render(view); } - GPU_texture_update_mipmap_chain(inst_.reflection_probes.cubemap_tx_); - inst_.reflection_probes.remap_to_octahedral_projection(); + + inst_.reflection_probes.remap_to_octahedral_projection(update_info->object_key); + inst_.reflection_probes.update_probes_texture_mipmaps(); + GPU_debug_group_end(); } +void CaptureView::render_probes() +{ + Framebuffer prepass_fb; + View view = {"Capture.View"}; + bool do_update_mipmap_chain = false; + while (const std::optional update_info = + inst_.reflection_probes.update_info_pop(ReflectionProbe::Type::Probe)) + { + GPU_debug_group_begin("Probe.Capture"); + do_update_mipmap_chain = true; + + int2 extent = int2(update_info->resolution); + inst_.render_buffers.acquire(extent); + + inst_.render_buffers.vector_tx.clear(float4(0.0f)); + prepass_fb.ensure(GPU_ATTACHMENT_TEXTURE(inst_.render_buffers.depth_tx), + GPU_ATTACHMENT_TEXTURE(inst_.render_buffers.vector_tx)); + + for (int face : IndexRange(6)) { + float4x4 view_m4 = cubeface_mat(face); + view_m4 = math::translate(view_m4, -update_info->probe_pos); + float4x4 win_m4 = math::projection::perspective(-update_info->clipping_distances.x, + update_info->clipping_distances.x, + -update_info->clipping_distances.x, + update_info->clipping_distances.x, + update_info->clipping_distances.x, + update_info->clipping_distances.y); + view.sync(view_m4, win_m4); + + capture_fb_.ensure( + GPU_ATTACHMENT_TEXTURE(inst_.render_buffers.depth_tx), + GPU_ATTACHMENT_TEXTURE_CUBEFACE(inst_.reflection_probes.cubemap_tx_, face)); + + GPU_framebuffer_bind(capture_fb_); + GPU_framebuffer_clear_color_depth(capture_fb_, float4(0.0f, 0.0f, 0.0f, 1.0f), 1.0f); + inst_.pipelines.probe.render(view, prepass_fb, capture_fb_, extent); + } + + inst_.render_buffers.release(); + GPU_debug_group_end(); + inst_.reflection_probes.remap_to_octahedral_projection(update_info->object_key); + } + + if (do_update_mipmap_chain) { + /* TODO: only update the regions that have been updated. */ + /* TODO: Composite world into the probes. */ + inst_.reflection_probes.update_probes_texture_mipmaps(); + } +} + /** \} */ } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh index 52281e91e27..e58aa938beb 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.hh +++ b/source/blender/draw/engines/eevee_next/eevee_view.hh @@ -155,7 +155,8 @@ class CaptureView { public: CaptureView(Instance &inst) : inst_(inst) {} - void render(); + void render_world(); + void render_probes(); }; /** \} */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl index 81fd2c73efb..67702104b8c 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_deferred_light_frag.glsl @@ -55,7 +55,10 @@ void main() vec3 reflection_light = vec3(0.0); float shadow = 1.0; +#ifdef DO_REFLECTION_PROBES reflection_probes_eval(reflection_data, P, V, reflection_light); +#endif + lightprobe_eval(diffuse_data, reflection_data, P, Ng, V, diffuse_light, reflection_light); light_eval(diffuse_data, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_remap_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_remap_comp.glsl index ade2d3326e2..2a18691a6b5 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_remap_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_remap_comp.glsl @@ -5,7 +5,7 @@ void main() { - ReflectionProbeData probe_data = reflection_probe_buf[0]; + ReflectionProbeData probe_data = reflection_probe_buf[reflection_probe_index]; ivec3 texture_coord = ivec3(gl_GlobalInvocationID.xyz); ivec3 texture_size = imageSize(octahedral_img); @@ -25,12 +25,14 @@ void main() vec3 R = octahedral_uv_to_direction(octahedral_uv); vec4 col = textureLod(cubemap_tx, R, float(probe_data.layer_subdivision)); - // col.xy = octahedral_uv; int probes_per_dimension = 1 << probe_data.layer_subdivision; ivec2 area_coord = ivec2(probe_data.area_index % probes_per_dimension, probe_data.area_index / probes_per_dimension); ivec2 area_offset = area_coord * octahedral_size; - imageStore(octahedral_img, octahedral_coord + ivec3(area_offset, 0), col); + /* Convert transmittance to transparency. */ + col.a = 1.0 - col.a; + + imageStore(octahedral_img, octahedral_coord + ivec3(area_offset, probe_data.layer), col); } diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh index 660a5970f46..02500247454 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh @@ -30,7 +30,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_base) .image_out(2, Qualifier::WRITE, GPU_RGBA16F, "out_diffuse_light_img") .image_out(3, Qualifier::WRITE, GPU_RGBA16F, "out_specular_light_img"); -GPU_SHADER_CREATE_INFO(eevee_deferred_light) +GPU_SHADER_CREATE_INFO(eevee_deferred_light_base) .fragment_source("eevee_deferred_light_frag.glsl") .sampler(0, ImageType::FLOAT_2D_ARRAY, "gbuffer_closure_tx") .sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_color_tx") @@ -46,7 +46,15 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light) "eevee_hiz_data", "eevee_render_pass_out", "draw_view", - "draw_fullscreen") + "draw_fullscreen"); + +GPU_SHADER_CREATE_INFO(eevee_deferred_light) + .additional_info("eevee_deferred_light_base") + .define("DO_REFLECTION_PROBES") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(eevee_deferred_light_diffuse) + .additional_info("eevee_deferred_light_base") .do_static_compilation(true); #undef image_array_out diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh index 1980b114053..a6699a2931a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh @@ -19,6 +19,7 @@ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_data) /* Sample cubemap and remap into an octahedral texture. */ GPU_SHADER_CREATE_INFO(eevee_reflection_probe_remap) .local_group_size(REFLECTION_PROBE_GROUP_SIZE, REFLECTION_PROBE_GROUP_SIZE) + .push_constant(Type::INT, "reflection_probe_index") .storage_buf(REFLECTION_PROBE_BUF_SLOT, Qualifier::READ, "ReflectionProbeData",