diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index b5b094503ff..1f14a602f33 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -154,6 +154,7 @@ set(SRC engines/eevee_next/eevee_material.cc engines/eevee_next/eevee_motion_blur.cc engines/eevee_next/eevee_pipeline.cc + engines/eevee_next/eevee_reflection_probes.cc engines/eevee_next/eevee_renderbuffers.cc engines/eevee_next/eevee_sampling.cc engines/eevee_next/eevee_shader.cc @@ -294,6 +295,7 @@ set(SRC engines/eevee_next/eevee_material.hh engines/eevee_next/eevee_motion_blur.hh engines/eevee_next/eevee_pipeline.hh + engines/eevee_next/eevee_reflection_probes.hh engines/eevee_next/eevee_renderbuffers.hh engines/eevee_next/eevee_sampling.hh engines/eevee_next/eevee_shader.hh @@ -508,6 +510,7 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_motion_blur_gather_comp.glsl engines/eevee_next/shaders/eevee_motion_blur_lib.glsl engines/eevee_next/shaders/eevee_nodetree_lib.glsl + engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl engines/eevee_next/shaders/eevee_sampling_lib.glsl engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl engines/eevee_next/shaders/eevee_shadow_lib.glsl diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index 0969638dcab..e0d985f5d45 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -108,6 +108,7 @@ #define SHADOW_ATLAS_TEX_SLOT 5 #define SSS_TRANSMITTANCE_TEX_SLOT 6 #define IRRADIANCE_ATLAS_TEX_SLOT 7 +#define REFLECTION_PROBE_TEX_SLOT 8 /* Only during shadow rendering. */ #define SHADOW_RENDER_MAP_SLOT 4 diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 2094e1ec585..0cae4c1df93 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -70,6 +70,7 @@ void Instance::init(const int2 &output_res, motion_blur.init(); main_view.init(); irradiance_cache.init(); + reflection_probes.init(); } void Instance::init_light_bake(Depsgraph *depsgraph, draw::Manager *manager) @@ -99,6 +100,7 @@ void Instance::init_light_bake(Depsgraph *depsgraph, draw::Manager *manager) shadows.init(); main_view.init(); irradiance_cache.init(); + reflection_probes.init(); } void Instance::set_time(float time) @@ -146,6 +148,7 @@ void Instance::begin_sync() hiz_buffer.sync(); main_view.sync(); world.sync(); + reflection_probes.sync(); film.sync(); render_buffers.sync(); irradiance_cache.sync(); @@ -514,6 +517,8 @@ void Instance::light_bake_irradiance( render_sync(); manager->end_sync(); + pipelines.world_probe.render(); + 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 5c95a35503d..4a894acd24c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -27,6 +27,7 @@ #include "eevee_material.hh" #include "eevee_motion_blur.hh" #include "eevee_pipeline.hh" +#include "eevee_reflection_probes.hh" #include "eevee_renderbuffers.hh" #include "eevee_sampling.hh" #include "eevee_shader.hh" @@ -54,6 +55,7 @@ class Instance { PipelineModule pipelines; ShadowModule shadows; LightModule lights; + ReflectionProbeModule reflection_probes; VelocityModule velocity; MotionBlurModule motion_blur; DepthOfField depth_of_field; @@ -105,6 +107,7 @@ class Instance { pipelines(*this), shadows(*this), lights(*this), + reflection_probes(*this), velocity(*this), motion_blur(*this), depth_of_field(*this), diff --git a/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.hh b/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.hh index 9f9ca0ffdd8..3a23c4caa97 100644 --- a/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.hh +++ b/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.hh @@ -6,6 +6,10 @@ * \ingroup eevee */ +/** \file + * \ingroup eevee + */ + #pragma once #include "DNA_lightprobe_types.h" diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index c5d1ac4f836..312488b7031 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -56,6 +56,107 @@ void WorldPipeline::render(View &view) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name World Probe Pipeline + * \{ */ + +void WorldProbePipeline::sync() +{ + for (int face : IndexRange(6)) { + CubemapSide &side = sides_[face]; + /* View */ + float4x4 view_m4 = cubeface_mat(face); + float4x4 win_m4; + cubeface_winmat_get(win_m4, 1.0f, 10.0f); + side.view.sync(view_m4, win_m4); + + side.cubemap_face_ps.init(); + side.cubemap_face_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); + } + const int2 extent(1); + constexpr eGPUTextureUsage usage = GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE; + 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); + dummy_aov_value_tx_.ensure_2d_array(GPU_R16F, extent, 1, usage); + + has_draw_commands_ = false; +} + +void WorldProbePipeline::sync(GPUMaterial *gpumat) +{ + for (int face : IndexRange(6)) { + sync(gpumat, face); + } + has_draw_commands_ = true; +} + +void WorldProbePipeline::sync(GPUMaterial *gpumat, int face) +{ + Manager &manager = *inst_.manager; + + CubemapSide &side = sides_[face]; + + /* Framebuffer. */ + Texture &cubemap = inst_.reflection_probes.cubemaps_tx_; + side.cubemap_face_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE_CUBEFACE(cubemap, face)); + + ResourceHandle handle = manager.resource_handle(float4x4::identity()); + PassSimple &pass = side.cubemap_face_ps; + + pass.framebuffer_set(&side.cubemap_face_fb); + pass.material_set(manager, gpumat); + pass.push_constant("world_opacity_fade", 1.0f); + + pass.bind_texture(RBUFS_UTILITY_TEX_SLOT, inst_.pipelines.utility_tx); + pass.bind_ubo(CAMERA_BUF_SLOT, inst_.camera.ubo_get()); + pass.bind_ubo(RBUFS_BUF_SLOT, &inst_.render_buffers.data); + pass.bind_image("rp_normal_img", dummy_renderpass_tx_); + pass.bind_image("rp_light_img", dummy_renderpass_tx_); + pass.bind_image("rp_diffuse_color_img", dummy_renderpass_tx_); + pass.bind_image("rp_specular_color_img", dummy_renderpass_tx_); + pass.bind_image("rp_emission_img", dummy_renderpass_tx_); + pass.bind_image("rp_cryptomatte_img", dummy_cryptomatte_tx_); + pass.bind_image("rp_color_img", dummy_aov_color_tx_); + pass.bind_image("rp_value_img", dummy_aov_value_tx_); + /* Required by validation layers. */ + inst_.cryptomatte.bind_resources(&pass); + + pass.bind_image("aov_color_img", dummy_aov_color_tx_); + pass.bind_image("aov_value_img", dummy_aov_value_tx_); + pass.bind_ssbo("aov_buf", &inst_.film.aovs_info); + + pass.draw(DRW_cache_fullscreen_quad_get(), handle); + + pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); +} + +void WorldProbePipeline::render() +{ + if (!has_draw_commands_) { + return; + } + GPUFrameBuffer *previous_framebuffer = GPU_framebuffer_active_get(); + + GPU_debug_group_begin("World.Probe"); + for (int face : IndexRange(6)) { + sides_[face].render(inst_); + } + GPU_debug_group_end(); + + GPU_texture_update_mipmap_chain(inst_.reflection_probes.cubemaps_tx_); + if (previous_framebuffer) { + GPU_framebuffer_bind(previous_framebuffer); + } +} + +void WorldProbePipeline::CubemapSide::render(Instance &instance) +{ + instance.manager->submit(cubemap_face_ps, view); +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Shadow Pipeline * @@ -372,6 +473,8 @@ void DeferredLayer::end_sync() inst_.sampling.bind_resources(&eval_light_ps_); inst_.hiz_buffer.bind_resources(&eval_light_ps_); inst_.irradiance_cache.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); diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index 5daf5f3576c..87f168681b9 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -43,6 +43,56 @@ class WorldPipeline { /** \} */ +/* -------------------------------------------------------------------- */ +/** \name World Probe Pipeline + * + * Render reflection probe of the world background. + * \{ */ + +class WorldProbePipeline { + private: + Instance &inst_; + + Texture dummy_renderpass_tx_; + Texture dummy_cryptomatte_tx_; + Texture dummy_aov_color_tx_; + Texture dummy_aov_value_tx_; + + struct CubemapSide { + PassSimple cubemap_face_ps; + View view; + Framebuffer cubemap_face_fb; + void render(Instance &instance); + }; + + /** + * Keep track if the world probe needs to be updated. This should only be the case when the + * world is updated. This flag is used to skip updating mipmaps when the world isn't changed. + */ + bool has_draw_commands_ = false; + + CubemapSide sides_[6] = { + {{"PosX"}, {"PosX"}}, + {{"NegX"}, {"NegX"}}, + {{"PosY"}, {"PosY"}}, + {{"NegY"}, {"NegY"}}, + {{"PosZ"}, {"PosZ"}}, + {{"NegZ"}, {"NegZ"}}, + }; + + public: + WorldProbePipeline(Instance &inst) : inst_(inst){}; + + void sync(); + void sync(GPUMaterial *gpumat); + void render(); + + private: + void sync(GPUMaterial *gpumat, int face); +}; // namespace blender::eevee + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Shadow Pass * @@ -288,6 +338,7 @@ class UtilityTexture : public Texture { class PipelineModule { public: WorldPipeline world; + WorldProbePipeline world_probe; DeferredPipeline deferred; ForwardPipeline forward; ShadowPipeline shadow; @@ -297,13 +348,19 @@ class PipelineModule { public: PipelineModule(Instance &inst) - : world(inst), deferred(inst), forward(inst), shadow(inst), capture(inst){}; + : world(inst), + world_probe(inst), + deferred(inst), + forward(inst), + shadow(inst), + capture(inst){}; void begin_sync() { deferred.begin_sync(); forward.sync(); shadow.sync(); + world_probe.sync(); capture.sync(); } diff --git a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc new file mode 100644 index 00000000000..ac48420f65e --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. */ + +#include "eevee_reflection_probes.hh" +#include "eevee_instance.hh" + +namespace blender::eevee { + +void ReflectionProbeModule::init() +{ + if (cubemaps_.is_empty()) { + cubemaps_.reserve(MAX_PROBES); + + /* Initialize the world cubemap. */ + ReflectionProbe world_cubemap; + world_cubemap.type = ReflectionProbe::Type::World; + world_cubemap.is_dirty = true; + cubemaps_.append(world_cubemap); + + cubemaps_tx_.ensure_cube_array(GPU_RGBA16F, + MAX_RESOLUTION, + MAX_PROBES, + GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, + NULL, + MIPMAP_LEVELS); + GPU_texture_mipmap_mode(cubemaps_tx_, true, true); + + dummy_tx_.ensure_cube_array( + GPU_RGBA16F, 1, 1, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, NULL, 1); + dummy_tx_.clear(float4(0.0f)); + GPU_texture_mipmap_mode(dummy_tx_, false, false); + } +} + +void ReflectionProbeModule::sync() +{ + for (int index : IndexRange(MAX_PROBES)) { + ReflectionProbe &cubemap = cubemaps_[index]; + if (!cubemap.needs_update()) { + continue; + } + sync(cubemap); + cubemap.is_dirty = false; + } +} + +void ReflectionProbeModule::sync(const ReflectionProbe &cubemap) +{ + if (cubemap.type == ReflectionProbe::Type::World) { + GPUMaterial *world_material = instance_.world.get_world_material(); + instance_.pipelines.world_probe.sync(world_material); + } + else { + BLI_assert_unreachable(); + } +} + +void ReflectionProbeModule::set_world_dirty() +{ + cubemaps_[WORLD_SLOT].is_dirty = true; +} + +/* -------------------------------------------------------------------- */ +/** \name World + * + * \{ */ + +bool ReflectionProbe::needs_update() const +{ + return type != Type::Unused && is_dirty; +} + +/** \} */ + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh new file mode 100644 index 00000000000..1d4c0476b08 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. */ + +/** \file + * \ingroup eevee + * + * Cubemaps + * + * Cubemaps record light from different locations in the scene. These cubemaps are used to add + * environment and indirect lighting from light probes. + * + * - Although we have Global illumination light probes can still be used for situations that + * GI doesn't work. For example semi-transparent surfaces. + * - The first cubemap is always reserved for the world shading. + * + */ + +#pragma once + +#include "eevee_shader_shared.hh" + +#include "BKE_cryptomatte.hh" + +extern "C" { +struct Material; +} + +namespace blender::eevee { + +class Instance; +class WorldProbePipeline; + +/* -------------------------------------------------------------------- */ +/** \name Reflection Probes + * \{ */ +class ReflectionProbe { + public: + enum Type { Unused, World }; + + Type type; + bool is_dirty = false; + + bool needs_update() const; +}; + +class ReflectionProbeModule { + private: + /** The max number of probes to track. */ + static constexpr int MAX_PROBES = 1; + + /** + * The maximum resolution of a cubemap side. + * + * Must be a power of two; intension to be used as a cubemap atlas. + */ + static constexpr int MAX_RESOLUTION = 2048; + static constexpr int MIPMAP_LEVELS = 12; + + /** + * Index of the probe that is used for world background. + * + * NOTE: First probe always contains the world probe. + */ + static constexpr int WORLD_SLOT = 0; + + Instance &instance_; + + Vector cubemaps_; + Texture cubemaps_tx_ = {"Probes"}; + Texture dummy_tx_ = {"DummyProbes"}; + + public: + ReflectionProbeModule(Instance &instance) : instance_(instance) {} + + void init(); + void set_world_dirty(); + + void sync(); + + template void bind_resources(draw::detail::PassBase *pass) + { + pass->bind_texture(REFLECTION_PROBE_TEX_SLOT, cubemaps_tx_); + } + + template void bind_dummy_resources(draw::detail::PassBase *pass) + { + pass->bind_texture(REFLECTION_PROBE_TEX_SLOT, dummy_tx_); + } + + private: + void sync(const ReflectionProbe &cubemap); + + friend class WorldProbePipeline; +}; + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index 73e4e76a316..b0cc3d0c7b3 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -118,6 +118,7 @@ void ShadingView::render() GPU_framebuffer_bind(combined_fb_); GPU_framebuffer_clear_color_depth(combined_fb_, clear_color, 1.0f); + inst_.pipelines.world_probe.render(); inst_.pipelines.world.render(render_view_new_); /* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */ @@ -125,8 +126,6 @@ void ShadingView::render() inst_.pipelines.deferred.render(render_view_new_, prepass_fb_, combined_fb_, extent_); - // inst_.lightprobes.draw_cache_display(); - // inst_.lookdev.render_overlay(view_fb_); inst_.pipelines.forward.render(render_view_new_, prepass_fb_, combined_fb_, rbufs.combined_tx); diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc index f4e3c868c02..9b083040b76 100644 --- a/source/blender/draw/engines/eevee_next/eevee_world.cc +++ b/source/blender/draw/engines/eevee_next/eevee_world.cc @@ -90,7 +90,7 @@ void World::sync() WorldHandle &wo_handle = inst_.sync.sync_world(bl_world); if (wo_handle.recalc != 0) { - // inst_.lightprobes.set_world_dirty(); + inst_.reflection_probes.set_world_dirty(); } wo_handle.reset_recalc_flag(); @@ -111,6 +111,21 @@ void World::sync() inst_.pipelines.world.sync(gpumat); } +GPUMaterial *World::get_world_material() +{ + ::World *bl_world = inst_.scene->world; + if (bl_world == nullptr) { + bl_world = default_world_get(); + } + + bNodeTree *ntree = (bl_world->nodetree && bl_world->use_nodes) ? + bl_world->nodetree : + default_tree.nodetree_get(bl_world); + + GPUMaterial *gpumat = inst_.shaders.world_shader_get(bl_world, ntree); + return gpumat; +} + /** \} */ } // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_world.hh b/source/blender/draw/engines/eevee_next/eevee_world.hh index c589ffec290..30d5e146897 100644 --- a/source/blender/draw/engines/eevee_next/eevee_world.hh +++ b/source/blender/draw/engines/eevee_next/eevee_world.hh @@ -62,6 +62,13 @@ class World { ~World(); void sync(); + + /** + * Get the world material. + * + * NOTE: this function should only be called after World::sync has been executed. + */ + GPUMaterial *get_world_material(); }; /** \} */ 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 9781486fe2d..75dfc73b8f5 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 @@ -10,6 +10,8 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) #pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_reflection_probe_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_lightprobe_eval_lib.glsl) void main() { @@ -56,6 +58,8 @@ void main() lightprobe_eval(diffuse_data, reflection_data, P, Ng, V, diffuse_light, reflection_light); + light_world_eval(reflection_data, P, V, reflection_light); + light_eval(diffuse_data, reflection_data, P, diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_irradiance_ray_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_irradiance_ray_comp.glsl index 444eda6f232..114aed16155 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_irradiance_ray_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_lightprobe_irradiance_ray_comp.glsl @@ -13,6 +13,7 @@ #pragma BLENDER_REQUIRE(eevee_surfel_list_lib.glsl) #pragma BLENDER_REQUIRE(eevee_lightprobe_lib.glsl) #pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(cubemap_lib.glsl) void irradiance_capture(vec3 L, vec3 irradiance, inout SphericalHarmonicL1 sh) { @@ -40,6 +41,11 @@ void irradiance_capture(Surfel surfel, vec3 P, inout SphericalHarmonicL1 sh) irradiance_capture(L, irradiance, sh); } +vec3 irradiance_sky_sample(vec3 R) +{ + return textureLod_cubemapArray(reflectionProbes, vec4(R, 0.0), 0.0).rgb; +} + void main() { ivec3 grid_coord = ivec3(gl_GlobalInvocationID); @@ -88,8 +94,8 @@ void main() irradiance_capture(surfel, P, sh); } else { - /* TODO(fclem): Sky radiance. */ - irradiance_capture(sky_L, vec3(0.0), sh); + vec3 world_radiance = irradiance_sky_sample(sky_L); + irradiance_capture(sky_L, world_radiance, sh); } if (surfel_prev > -1) { @@ -97,8 +103,8 @@ void main() irradiance_capture(surfel, P, sh); } else { - /* TODO(fclem): Sky radiance. */ - irradiance_capture(-sky_L, vec3(0.0), sh); + vec3 world_radiance = irradiance_sky_sample(-sky_L); + irradiance_capture(-sky_L, world_radiance, sh); } /* Normalize for storage. We accumulated 2 samples. */ diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl new file mode 100644 index 00000000000..d297b3d80c3 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl @@ -0,0 +1,12 @@ +void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 out_specular) +{ + float linear_roughness = fast_sqrt(reflection.roughness); + /* TODO: This should be based by actual resolution. Currently the resolution is fixed but + * eventually this should based on a user setting. */ + float lod_cube_max = 12.0; + float lod = linear_roughness * lod_cube_max; + + vec3 R = -reflect(V, reflection.N); + vec3 world_light = textureLod_cubemapArray(reflectionProbes, vec4(R, 0.0), lod).rgb; + out_specular += world_light; +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_surfel_ray_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_surfel_ray_comp.glsl index 50c48013ac8..dffe8b0942a 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_surfel_ray_comp.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_surfel_ray_comp.glsl @@ -12,6 +12,7 @@ #pragma BLENDER_REQUIRE(gpu_shader_math_base_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(cubemap_lib.glsl) void radiance_transfer(inout Surfel surfel, vec3 in_radiance, vec3 L) { @@ -69,6 +70,11 @@ void radiance_transfer_world(inout Surfel receiver, vec3 sky_L) radiance_transfer(receiver, radiance, -sky_L); } +vec3 radiance_sky_sample(vec3 R) +{ + return textureLod_cubemapArray(reflectionProbes, vec4(R, 0.0), 0.0).rgb; +} + void main() { int surfel_index = int(gl_GlobalInvocationID.x); @@ -85,7 +91,8 @@ void main() radiance_transfer_surfel(surfel, surfel_next); } else { - radiance_transfer_world(surfel, sky_L); + vec3 world_radiance = radiance_sky_sample(sky_L); + radiance_transfer(surfel, world_radiance, sky_L); } if (surfel.prev > -1) { @@ -93,7 +100,8 @@ void main() radiance_transfer_surfel(surfel, surfel_prev); } else { - radiance_transfer_world(surfel, -sky_L); + vec3 world_radiance = radiance_sky_sample(-sky_L); + radiance_transfer(surfel, world_radiance, -sky_L); } surfel_buf[surfel_index] = surfel; 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 aeae90b61c6..63d29cbb562 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 @@ -38,6 +38,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light) "eevee_utility_texture", "eevee_light_data", "eevee_lightprobe_data", + "eevee_reflection_probe_data", "eevee_shadow_data", "eevee_deferred_base", "eevee_transmittance_data", diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh index aa021bc64b6..a141e8f6669 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh @@ -83,7 +83,10 @@ GPU_SHADER_CREATE_INFO(eevee_surfel_list_sort) GPU_SHADER_CREATE_INFO(eevee_surfel_ray) .local_group_size(SURFEL_GROUP_SIZE) - .additional_info("eevee_shared", "eevee_surfel_common", "draw_view") + .additional_info("eevee_shared", + "eevee_surfel_common", + "eevee_reflection_probe_data", + "draw_view") .push_constant(Type::INT, "radiance_src") .push_constant(Type::INT, "radiance_dst") .compute_source("eevee_surfel_ray_comp.glsl") @@ -103,7 +106,10 @@ GPU_SHADER_CREATE_INFO(eevee_lightprobe_irradiance_ray) .local_group_size(IRRADIANCE_GRID_GROUP_SIZE, IRRADIANCE_GRID_GROUP_SIZE, IRRADIANCE_GRID_GROUP_SIZE) - .additional_info("eevee_shared", "eevee_surfel_common", "draw_view") + .additional_info("eevee_shared", + "eevee_surfel_common", + "eevee_reflection_probe_data", + "draw_view") .push_constant(Type::INT, "radiance_src") .storage_buf(0, Qualifier::READ, "int", "list_start_buf[]") .storage_buf(6, Qualifier::READ, "SurfelListInfoData", "list_info_buf") 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 new file mode 100644 index 00000000000..9eac2f05e89 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh @@ -0,0 +1,11 @@ +#include "eevee_defines.hh" +#include "gpu_shader_create_info.hh" + +/* -------------------------------------------------------------------- */ +/** \name Shared + * \{ */ + +GPU_SHADER_CREATE_INFO(eevee_reflection_probe_data) + .sampler(REFLECTION_PROBE_TEX_SLOT, ImageType::FLOAT_CUBE_ARRAY, "reflectionProbes"); + +/** \} */ diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index 57fa0cf1787..86b87ac092c 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -691,7 +691,7 @@ class Texture : NonCopyable { float *data = nullptr, int mip_len = 1) { - return ensure_impl(extent, extent, layers, mip_len, format, usage, data, false, true); + return ensure_impl(extent, extent, layers, mip_len, format, usage, data, true, true); } /** diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index fa979510b20..9e77a75df46 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -651,6 +651,7 @@ set(SRC_SHADER_CREATE_INFOS ../draw/engines/eevee_next/shaders/infos/eevee_light_culling_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh + ../draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_subsurface_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_velocity_info.hh diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index aa9b13e44f8..72e27c73edb 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -895,6 +895,11 @@ static char *glsl_patch_compute_get() STR_CONCAT(patch, slen, "#version 430\n"); STR_CONCAT(patch, slen, "#extension GL_ARB_compute_shader :enable\n"); + if (GLContext::texture_cube_map_array_support) { + STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n"); + STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n"); + } + /* Array compat. */ STR_CONCAT(patch, slen, "#define gpu_Array(_type) _type[]\n");