From e3608d689d8841a4a64a7c6380a41a483108a51e Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 26 May 2023 09:22:15 +0200 Subject: [PATCH 01/23] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f6b871b57a45710b550314b29b9efe75454bddde Merge: f8e24de1764 ad6fa960410 Author: Jeroen Bakker Date: Fri May 26 08:41:34 2023 +0200 Merge branch 'main' into eevee-next-world-shader commit f8e24de1764691d9776ed9e6df9378e81aaaaee9 Author: Jeroen Bakker Date: Fri May 26 08:30:28 2023 +0200 Fix cubemap array. commit 27e98ea4d0b96ec6e3bf98943d0ca961fb7278c5 Author: Jeroen Bakker Date: Thu May 25 18:03:39 2023 +0200 Mark initial world dirty. commit fb7c5cadf25c58185ab0c29d25792f5d74509028 Author: Jeroen Bakker Date: Thu May 25 17:56:58 2023 +0200 Use same reflection as eevee-legacy commit 773c58ba3caf38b90f6235dfafefb9ddffc378d5 Author: Jeroen Bakker Date: Thu May 25 15:24:33 2023 +0200 Incorrect merge. commit 6e6281a8456970134f2ab2b55dc06baf40029334 Author: Jeroen Bakker Date: Thu May 25 15:23:52 2023 +0200 Revert "Merge branch 'eevee-next-irradiance-cache' into eevee-next-world-shader" This reverts commit 272eb1da8243ca5030a69b9a034f6879e56f2017, reversing changes made to d09a8d09e1028fa9d96da4956715368f4a102be4. commit 7dc261508a6cb76e49b7f3d201b6bd52879f6c8c Author: Jeroen Bakker Date: Thu May 25 15:16:22 2023 +0200 Fixed many small issues. commit 9ad112740dddaa1848fffa66b3255d35fc8d7c54 Author: Jeroen Bakker Date: Thu May 25 11:08:03 2023 +0200 Remove flags structure. commit e243f56f207a253a4a21a03e50769e573cb10ac1 Author: Jeroen Bakker Date: Thu May 25 10:12:16 2023 +0200 Fix compilation issue commit 272eb1da8243ca5030a69b9a034f6879e56f2017 Merge: d09a8d09e10 4ad77fcc74c Author: Jeroen Bakker Date: Thu May 25 10:12:06 2023 +0200 Merge branch 'eevee-next-irradiance-cache' into eevee-next-world-shader commit 4ad77fcc74c90bca593984c42efd82f813f386a0 Author: Clément Foucault Date: Wed May 24 22:51:44 2023 +0200 EEVEE-Next: Add progress to irradiance bake commit d09a8d09e1028fa9d96da4956715368f4a102be4 Author: Jeroen Bakker Date: Tue May 23 14:28:39 2023 +0200 Removed comments. commit 94d4d77936347c4c97282c3cbef65585f2cd9cb7 Author: Jeroen Bakker Date: Tue May 23 14:19:23 2023 +0200 Rendering of cubemap. commit fc91ed10a9260e81348e3ce34bb35bef5dcda79f Merge: 487ab2073bd a9beb624494 Author: Clément Foucault Date: Tue May 23 12:31:50 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit cb2dd516503afbb9eacdfc3f3005c335374c518d Author: Jeroen Bakker Date: Tue May 23 11:49:20 2023 +0200 Initial world probe pipeline. commit 2167d5c32eb23b29bb0132c5da96478fc3eec9d9 Author: Jeroen Bakker Date: Tue May 23 11:32:29 2023 +0200 Renames and reorganizing code according to code review. commit 7d1ec9cfd49a2beb1a54d33d023b700fce811414 Author: Jeroen Bakker Date: Tue May 23 11:18:24 2023 +0200 Rename module to eevee_reflection_probes commit 01382ca4eb60742ebabe56f40143ffbd1242215e Merge: 3e2cd9ab68a 4997748e5e6 Author: Jeroen Bakker Date: Tue May 23 11:15:07 2023 +0200 Merge branch 'main' into eevee-next-world-shader commit 3e2cd9ab68a5a316d07628a2801941f0523fc2ff Author: Jeroen Bakker Date: Tue May 23 09:28:35 2023 +0200 Research how to use GPUMaterials commit 1381e4c4171cdf776dbf74b56aee4d08a5261170 Author: Jeroen Bakker Date: Mon May 22 16:00:59 2023 +0200 Add initial CubemapsModule. commit 45d5339f3ac711ebf7f7eaeed1168a0561e082a3 Merge: 1ab265f5350 2164515fab1 Author: Jeroen Bakker Date: Mon May 22 13:00:02 2023 +0200 Merge branch 'main' into eevee-next-world-shader commit 487ab2073bd2ca6f725c50f58fc61c6607167bf6 Author: Clément Foucault Date: Sun May 7 16:06:04 2023 +0200 EEVEE-Next: Irradiance Bake: Avoid asserts on Metal This avoid triggering the asserts in place in the Metal backend. However it does not work yet. commit 63a2736e5e6768285a44f056e23d3777207ce935 Merge: 12fc600d7f8 c796cbebefc Author: Clément Foucault Date: Fri May 5 16:18:36 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit 12fc600d7f807afcbf776ff32720611e43c4dbd2 Author: Clément Foucault Date: Fri May 5 16:14:11 2023 +0200 EEVEE-Next: Fix compilation error with Metal commit 76777bb87485223f53d57c4440fa5c6c49356b5a Merge: dcf3392cec0 29053c5c025 Author: Clément Foucault Date: Fri May 5 14:54:31 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit dcf3392cec085cb3712235de6e4748f3b8f935e3 Merge: e6d1a42d12b 358ce4f52b5 Author: Clément Foucault Date: Sun Apr 30 22:14:57 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit e6d1a42d12bb3f858fb6dcba8b1d22e9541ab396 Author: Clément Foucault Date: Sun Apr 30 22:06:59 2023 +0200 EEVEE-Next: Irradiance Cache: Add version control for new parameter commit 502d9db82c74df563094a451959be020e6e9b7b9 Author: Clément Foucault Date: Sun Apr 30 22:02:56 2023 +0200 EEVEE-Next: Irradiance Cache: Add support for cancelling operator commit 95b8b71908249eee1f8ccb633541147c040d840d Author: Clément Foucault Date: Sun Apr 30 21:35:42 2023 +0200 EEVEE-Next: Irradiance Cache: Reserve slot for world irradiance This doesn't implement the world irradiance extraction process, but only reserve the storage for it. commit 12095b8e16b8bba779ebfe37d8a2c7732d351b17 Author: Clément Foucault Date: Sun Apr 30 21:10:55 2023 +0200 EEVEE-Next: Irradiance Cache: Use scene bounds for surfel cache This remove the per irradiance grid approach. The idea is to do the light transport only once for each visibility collection and store the irradiance for all irradiance grid using this visibility mask. This removes the need for the lightprobe near/far clip parameters. commit 0388f93e790883c7c7d6c389d7e63af7d38776f6 Author: Clément Foucault Date: Thu Apr 27 19:59:11 2023 +0200 EEVEE-Next: Irradiance Cache: Store final format commit f14c7e804c44ba424b9b38b45323b996c1e967a5 Author: Clément Foucault Date: Sat Apr 22 18:08:27 2023 +0200 EEVEE-Next: Irradiance Cache: Load irradiance in atlas This approach allow streaming of visible grids and has a controlled memory budget. commit 3452d3998cb4786e335a738c22e2aea67aecaef0 Merge: d3e761cda3d 99f5e60b86d Author: Clément Foucault Date: Sat Apr 22 17:37:49 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit d3e761cda3d1e3786465ddd1690a21a338b80581 Author: Clément Foucault Date: Sun Apr 16 22:00:56 2023 +0200 EEVEE-Next: Make Spherical harmonic follow object transform This make the baking step output local space spherical harmonics which need to be rotated back to world before being evaluated. In practice we rotate the evaluated direction. commit a5310b77205fd80dc25c7f4e891af4a4d0e44cfc Author: Clément Foucault Date: Thu Apr 13 20:12:32 2023 +0200 EEVEE-Next: Adapt code to new irradiance cache commit b1af33d52ae97132dec275503e754becdf1a9652 Merge: 892f7077bcf 7e764ec692f Author: Clément Foucault Date: Thu Apr 13 14:12:40 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit 892f7077bcf14d643ab23563f6fd7becaf6553be Author: Clément Foucault Date: Thu Apr 13 11:51:59 2023 +0200 Add new lightprobe cache Waiting for the commit to be in master. commit 2018d6c8c14e0009feb1d8e19d7c51b42872a29e Merge: d30ad0e381d c26083b6be7 Author: Clément Foucault Date: Thu Apr 13 11:40:30 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit d30ad0e381d55dccfcb2c53c71072610e442f08f Author: Clément Foucault Date: Wed Apr 5 12:47:24 2023 +0200 Cleanup: EEVEE-Next: Avoid implicit type cast commit a0610ef654fce6fe862da04fce8c9e8c87234cfa Author: Clément Foucault Date: Sun Apr 2 20:09:20 2023 +0200 EEVEE-Next: IrradianceBake: Fix shadow tagging & rendering commit ff5db3a72effc103b3873fe9d4beb4a34aecab35 Merge: 74d89d0b241 70970299ef2 Author: Clément Foucault Date: Sun Apr 2 16:23:52 2023 +0200 Merge branch 'eevee-next-irradiance-cache' of projects.blender.org:pragma37/blender into eevee-next-irradiance-cache commit 74d89d0b241dfba1c8b8e42488a64c20168a5100 Merge: 9461d7fc9ad 7592ec35d34 Author: Clément Foucault Date: Sat Apr 1 17:17:19 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit 9461d7fc9ad5edf66171c780b47384b6b8423d3e Author: Clément Foucault Date: Sat Apr 1 17:10:23 2023 +0200 EEVEE-Next: IrradianceBake: Add spherical harmonic encoding This adds a separate pass to project the neighbor surfels to the final irradiance sample points. commit 6a6ff3310a46cba4a752d46b090c6001c6faa2e6 Merge: 85bbf53f849 e652d0002b5 Author: Clément Foucault Date: Sat Apr 1 13:31:18 2023 +0200 Merge branch 'main' into eevee-next-irradiance-cache commit 85bbf53f8490f89ac71dc4c18955a87471207acf Author: Clément Foucault Date: Sat Apr 1 12:02:46 2023 +0200 EEVEE-Next: Fix wrong irradiance surfel spawning area commit 14973fabe617ad640ba8bd4a6665081dbbf4ceb8 Author: Clément Foucault Date: Sat Apr 1 12:00:33 2023 +0200 BLI: Rotation: Add CartesianBasis `transform_point` and `invert` commit 34adebcf43e489c8707bfc79ddf8b0091c946e29 Author: Clément Foucault Date: Sat Apr 1 11:54:02 2023 +0200 GPU: FrameBuffer: Fix empty framebuffer update The framebuffer default size was only set during the first bind. This is because the `dirty_attachments_ tag` wasn't set and thus the framebuffer size was never passed down to the GL. Split to `default_size_set()` to not affect other code paths that use `size_set()`. commit 70970299ef2c28356c76b999dbeb1af30ff8f1ae Author: Miguel Pozo Date: Wed Mar 29 18:48:24 2023 +0200 Shadow tag usage for surfels commit bfeb1a1a8d9f4398e7c25bb614948061c8cc9672 Author: Clément Foucault Date: Wed Mar 29 21:01:09 2023 +0200 EEVEE-Next: IrradianceBake: Fix light bounce Light bouncing needs a feedback mechanism. We cannot reuse the same radiance for scattering light and accumulating it. This splits the final accumulation to `radiance` and bouncing light into `incomming_light` and `outgoing_light`. commit 5dc6535591153306618640c2466e3b0087f595a9 Author: Clément Foucault Date: Wed Mar 29 14:52:44 2023 +0200 EEVEE-Next: IrradianceBake: Fix integration power and inconsistencies Now it follows proper conventional notation. commit a484f43a177dd30d1a1bd360cd7634acab95352a Author: Miguel Pozo Date: Tue Mar 28 20:05:15 2023 +0200 Irradiance Cache: Display Grid commit 114713c3544ec727ba5f41f69d89ad0a14806e66 Author: Miguel Pozo Date: Tue Mar 28 20:00:19 2023 +0200 Workaround compilation error on Win Nvidia drivers commit a4c571dc8e0f32ec3f5ddc1d576155256abce1a0 Author: Miguel Pozo Date: Tue Mar 28 19:59:35 2023 +0200 Fix irradiance_grid.world_to_grid commit 22ccf837001221201b2ea00a6dc0a1d2f34a4157 Author: Miguel Pozo Date: Tue Mar 28 17:51:27 2023 +0200 Cleanup: Fix typo commit 73f96fe2161e0f8c6c2ba539546e37ff9096bd18 Author: Clément Foucault Date: Tue Mar 28 18:12:28 2023 +0200 EEVEE-Next: IrradianceBake: Implement multi bounce support This is still broken as the light seems to never converge. commit db3028a6249d719913523a2c2a8a69108a655def Author: Clément Foucault Date: Tue Mar 28 13:21:04 2023 +0200 EEVEE-Next: IrradianceBake: Implement light propagation commit 4e3eb2f7a5d1509da3fe2685a9f29d339c2018d6 Author: Clément Foucault Date: Tue Mar 28 13:18:22 2023 +0200 EEVEE-Next: IrradianceBake: Fix crash caused by motion blur commit 5de76bbbffde17d56a4c9f601e56048aaac5f244 Author: Clément Foucault Date: Tue Mar 28 13:17:25 2023 +0200 EEVEE-Next: IrradianceBake: Fix light-leak This fixes the light leaking issue caused by the surfel lists. The fix consists in clumping more surfel together when creating the lists then rewire the coplanar surfels to more valid surfels up and down the same list. commit da91a2ccb028dc7399a10fbae277a6d1dcac42b7 Author: Clément Foucault Date: Sun Mar 26 15:39:17 2023 +0200 EEVEE-Next: IrradianceBake: Fix memleak commit 75b62a9cfb2cecde91300ae0f19c2a746bfe671a Author: Clément Foucault Date: Fri Mar 24 20:46:02 2023 +0100 EEVEE-Next: IrradianceBake: Add surfel list & sorting commit 6f6c3afe912f7f21e86e535c3cce84b408c98771 Merge: 0297bde6290 9c8cb823a05 Author: Clément Foucault Date: Fri Mar 24 17:45:20 2023 +0100 Merge branch 'main' into eevee-next-irradiance-cache commit 0297bde6290d38d9b7267bab358793d7d59d03d4 Author: Clément Foucault Date: Fri Mar 24 17:34:39 2023 +0100 EEVEE-Next: Debug: Fix surfel debugging showing background commit caa0e7edcfc122a26a701cba9f2b3ffe4385752e Author: Clément Foucault Date: Fri Mar 24 17:34:20 2023 +0100 EEVEE-Next: IrradianceBake: Correct surfel placement from grid objects commit 6669771215c81607a2fe8542666143fb56d45ee6 Author: Clément Foucault Date: Thu Mar 23 18:16:22 2023 +0100 EEVEE-Next: LightBake: Fix few mistakes preventing correct baking & debug Was missing manager sync, a buffer read and copy-on-write tagging. commit e696507aa5e9c2ab626c5cf2a208f86575175b3d Merge: 38f6de30cf1 b57b22388cd Author: Clément Foucault Date: Thu Mar 23 16:44:05 2023 +0100 Merge branch 'main' into eevee-next-irradiance-cache commit 38f6de30cf15d3c43768f9a501a1bf7e5b7a6f5f Author: Clément Foucault Date: Thu Mar 23 16:41:48 2023 +0100 EEVEE-Next: LightCache: Solidify the baking pipeline commit e6de2fc4f70655b360efc0f3257a97521df04842 Author: Clément Foucault Date: Thu Mar 23 16:39:02 2023 +0100 EEVEE-Next: GI: Add irradiance sample count option commit 7b3d4c9e4980e6ab4ad2b6231618ef4ff4d13e3b Author: Clément Foucault Date: Tue Mar 21 20:15:59 2023 +0100 EEVEE-Next: LightCache: Add basis of new lightcache version This should allow to keep both version working during the period where both eevee versions are available. commit 795bc96cfe4449c125f7d6c1db0d49bf8ba89500 Author: Clément Foucault Date: Tue Mar 21 12:25:17 2023 +0100 EEVEE-Next: LightCache: Add GL & GPU context functions commit dddfcd6f7abab96eda776576380bc610c27fd26b Author: Clément Foucault Date: Mon Mar 20 22:07:21 2023 +0100 EEVEE-Next: LightProbe: Add auto update detection This allow probe update and deletion to trigger an auto bake. commit 52a7125ce3cdc6467dc3965ef9a68a0490642b4c Author: Clément Foucault Date: Mon Mar 20 19:45:25 2023 +0100 EEVEE-Next: LightCache: Port basic lightcache structure to C++ This removes the complexity of resource sharing as it isn't even leveraged yet. So keep the code as simple as possible for now. commit 408c5d72810ef4bb5f5f8a7ce814164f8858a375 Author: Clément Foucault Date: Sun Mar 19 21:33:55 2023 +0100 EEVEE-Next: Irradiance-Cache: Add surfel placement Spawning surfels uses a new shader pipeline (called `capture`) to avoid the complexity of modifying the deferred or forward pipeline. The shaders are light to compile and should only be compiled on bake. This is very WIP: the surfel projection box is hardcoded and the 3 projections are done every frame. The surfels are placed in a regular grid because of the raster pipeline used to spawn them. Note: While this is really fast, I am not sure this will scale well for highly detailed lighting conditions. In the case where the surfel density is too low, the aliasing might create really poor result. --- source/blender/draw/CMakeLists.txt | 3 + .../draw/engines/eevee_next/eevee_defines.hh | 1 + .../draw/engines/eevee_next/eevee_instance.cc | 2 + .../draw/engines/eevee_next/eevee_instance.hh | 3 + .../draw/engines/eevee_next/eevee_pipeline.cc | 70 +++++++++++++++ .../draw/engines/eevee_next/eevee_pipeline.hh | 44 ++++++++- .../eevee_next/eevee_reflection_probes.cc | 70 +++++++++++++++ .../eevee_next/eevee_reflection_probes.hh | 89 +++++++++++++++++++ .../draw/engines/eevee_next/eevee_view.cc | 3 +- .../draw/engines/eevee_next/eevee_world.cc | 17 +++- .../draw/engines/eevee_next/eevee_world.hh | 7 ++ .../shaders/eevee_deferred_light_frag.glsl | 2 + .../shaders/eevee_reflection_probe_lib.glsl | 16 ++++ .../shaders/infos/eevee_deferred_info.hh | 1 + .../infos/eevee_reflection_probe_info.hh | 11 +++ source/blender/draw/intern/DRW_gpu_wrapper.hh | 5 +- source/blender/gpu/CMakeLists.txt | 1 + 17 files changed, 338 insertions(+), 7 deletions(-) create mode 100644 source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc create mode 100644 source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh create mode 100644 source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl create mode 100644 source/blender/draw/engines/eevee_next/shaders/infos/eevee_reflection_probe_info.hh diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 6edd63698b2..7709c1cf9ea 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -148,6 +148,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 @@ -286,6 +287,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 @@ -478,6 +480,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 fd7fd7b55b6..9e98dd21210 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -95,6 +95,7 @@ /* Only during shadow rendering. */ #define SHADOW_RENDER_MAP_SLOT 13 #define RBUFS_UTILITY_TEX_SLOT 14 +#define REFLECTION_PROBE_TEX_SLOT 16 /* Images. */ #define RBUFS_NORMAL_SLOT 0 diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 575ef7a086d..995a7d5c323 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -71,6 +71,7 @@ void Instance::init(const int2 &output_res, motion_blur.init(); main_view.init(); irradiance_cache.init(); + reflection_probes.init(); } void Instance::set_time(float time) @@ -117,6 +118,7 @@ void Instance::begin_sync() hiz_buffer.sync(); main_view.sync(); world.sync(); + reflection_probes.sync(); film.sync(); irradiance_cache.sync(); } diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index 8e7855961e4..5bc280bc8cf 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -26,6 +26,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" @@ -51,6 +52,7 @@ class Instance { PipelineModule pipelines; ShadowModule shadows; LightModule lights; + ReflectionProbeModule reflection_probes; VelocityModule velocity; MotionBlurModule motion_blur; DepthOfField depth_of_field; @@ -97,6 +99,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_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 78ff35136aa..5d695cbd88e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -62,6 +62,75 @@ 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); + } +} + +void WorldProbePipeline::sync(GPUMaterial *gpumat) +{ + for (int face : IndexRange(6)) { + sync(gpumat, face); + } +} + +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()); + + side.cubemap_face_ps.framebuffer_set(&side.cubemap_face_fb); + side.cubemap_face_ps.material_set(manager, gpumat); + + side.cubemap_face_ps.draw(DRW_cache_fullscreen_quad_get(), handle); + /* To allow opaque pass rendering over it. */ + side.cubemap_face_ps.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); +} + +void WorldProbePipeline::render() +{ + 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 * @@ -387,6 +456,7 @@ void DeferredLayer::end_sync() inst_.shadows.bind_resources(&eval_light_ps_); inst_.sampling.bind_resources(&eval_light_ps_); inst_.hiz_buffer.bind_resources(&eval_light_ps_); + inst_.reflection_probes.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 c09f5fe99cf..e1e1af08821 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -43,6 +43,45 @@ class WorldPipeline { /** \} */ +/* -------------------------------------------------------------------- */ +/** \name World Probe Pipeline + * + * Render reflection probe of the world background. + * \{ */ + +class WorldProbePipeline { + private: + Instance &inst_; + + struct CubemapSide { + PassSimple cubemap_face_ps; + View view; + Framebuffer cubemap_face_fb; + void render(Instance &instance); + }; + + 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 * @@ -266,6 +305,7 @@ class UtilityTexture : public Texture { class PipelineModule { public: WorldPipeline world; + WorldProbePipeline world_probe; DeferredPipeline deferred; ForwardPipeline forward; ShadowPipeline shadow; @@ -273,13 +313,15 @@ class PipelineModule { UtilityTexture utility_tx; public: - PipelineModule(Instance &inst) : world(inst), deferred(inst), forward(inst), shadow(inst){}; + PipelineModule(Instance &inst) + : world(inst), world_probe(inst), deferred(inst), forward(inst), shadow(inst){}; void begin_sync() { deferred.begin_sync(); forward.sync(); shadow.sync(); + world_probe.sync(); } void end_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..62d61ee7251 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -0,0 +1,70 @@ +/* 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, + 12); + GPU_texture_mipmap_mode(cubemaps_tx_, true, true); + } +} + +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..7e567d1de73 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -0,0 +1,89 @@ +/* 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; + + /** + * 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"}; + + 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_); + } + + 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 d2d8f80feb7..86a4b4635c1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -119,14 +119,13 @@ void ShadingView::render() GPU_framebuffer_clear_color_depth(combined_fb_, clear_color, 1.0f); inst_.pipelines.world.render(render_view_new_); + inst_.pipelines.world_probe.render(); /* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */ inst_.lights.set_view(render_view_new_, extent_); 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 97312ca5800..3c25b9d5d5e 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 f21c9b964f0..ae599021302 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 80dcaaf67cb..8d6953bfafb 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 @@ -9,6 +9,7 @@ #pragma BLENDER_REQUIRE(eevee_gbuffer_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) #pragma BLENDER_REQUIRE(eevee_light_eval_lib.glsl) +#pragma BLENDER_REQUIRE(eevee_reflection_probe_lib.glsl) void main() { @@ -52,6 +53,7 @@ void main() vec3 diffuse_light = vec3(0.0); vec3 reflection_light = vec3(0.0); + light_world_eval(diffuse_data, reflection_data, P, V, diffuse_light, reflection_light); light_eval( diffuse_data, reflection_data, P, Ng, V, vP_z, thickness, diffuse_light, reflection_light); 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..eef1569cff3 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl @@ -0,0 +1,16 @@ +void light_world_eval(ClosureDiffuse diffuse, + ClosureReflection reflection, + vec3 P, + vec3 V, + inout vec3 out_diffuse, + inout vec3 out_specular) +{ + float linear_roughness = fast_sqrt(reflection.roughness); + /* TODO: This should be based by actual LOD?.*/ + 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/infos/eevee_deferred_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_deferred_info.hh index f5bc967e5b6..af402ec7601 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 @@ -37,6 +37,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light) .additional_info("eevee_shared", "eevee_utility_texture", "eevee_light_data", + "eevee_reflection_probe_data", "eevee_shadow_data", "eevee_deferred_base", "eevee_hiz_data", 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 2c7e3623a43..d7e68b1bdb7 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -674,7 +674,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); } /** @@ -1033,8 +1033,7 @@ class TextureRef : public Texture { * Dummy type to bind texture as image. * It is just a GPUTexture in disguise. */ -class Image { -}; +class Image {}; static inline Image *as_image(GPUTexture *tex) { diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5e2ac715a7e..845b8425dc3 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -648,6 +648,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_velocity_info.hh ../draw/engines/gpencil/shaders/infos/gpencil_info.hh -- 2.30.2 From d58847b79863bac228600e60f53cd7fa7128f61b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 30 May 2023 08:13:15 +0200 Subject: [PATCH 02/23] Don't apply film transparecy to world probe. --- source/blender/draw/engines/eevee_next/eevee_pipeline.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 5d695cbd88e..0c11fc3aabb 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -102,6 +102,7 @@ void WorldProbePipeline::sync(GPUMaterial *gpumat, int face) side.cubemap_face_ps.framebuffer_set(&side.cubemap_face_fb); side.cubemap_face_ps.material_set(manager, gpumat); + side.cubemap_face_ps.push_constant("world_opacity_fade", 1.0f); side.cubemap_face_ps.draw(DRW_cache_fullscreen_quad_get(), handle); /* To allow opaque pass rendering over it. */ -- 2.30.2 From 95771741ae49ea08fbebb960d646fa10a8f8bc8b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 1 Jun 2023 08:06:11 +0200 Subject: [PATCH 03/23] Use dummy textures when drawing world reflection probe. --- .../draw/engines/eevee_next/eevee_pipeline.cc | 30 +++++++++++++++---- .../draw/engines/eevee_next/eevee_pipeline.hh | 5 ++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 0c11fc3aabb..2ba0bf51839 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -79,6 +79,14 @@ void WorldProbePipeline::sync() side.cubemap_face_ps.init(); side.cubemap_face_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); } + dummy_cryptomatte_tx_.ensure_2d( + GPU_RGBA16F, int2(1), GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); + dummy_renderpass_tx_.ensure_2d( + GPU_RGBA32F, int2(1), GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); + dummy_aov_color_tx_.ensure_2d_array( + GPU_RGBA16F, int2(1), 1, GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); + dummy_aov_value_tx_.ensure_2d_array( + GPU_R16F, int2(1), 1, GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); } void WorldProbePipeline::sync(GPUMaterial *gpumat) @@ -99,14 +107,26 @@ void WorldProbePipeline::sync(GPUMaterial *gpumat, int face) 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; - side.cubemap_face_ps.framebuffer_set(&side.cubemap_face_fb); - side.cubemap_face_ps.material_set(manager, gpumat); - side.cubemap_face_ps.push_constant("world_opacity_fade", 1.0f); + pass.framebuffer_set(&side.cubemap_face_fb); + pass.material_set(manager, gpumat); + pass.push_constant("world_opacity_fade", 1.0f); - side.cubemap_face_ps.draw(DRW_cache_fullscreen_quad_get(), handle); + 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("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); /* To allow opaque pass rendering over it. */ - side.cubemap_face_ps.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); + pass.barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS); } void WorldProbePipeline::render() diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index e1e1af08821..b08cc723e70 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -53,6 +53,11 @@ 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; -- 2.30.2 From 48dacdabb8ae8ec4604b18052489612757b2c92b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 1 Jun 2023 08:25:24 +0200 Subject: [PATCH 04/23] Skip mipmap generation when world isn't changed. --- .../draw/engines/eevee_next/eevee_pipeline.cc | 24 ++++++++++++------- .../draw/engines/eevee_next/eevee_pipeline.hh | 6 +++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index 2ba0bf51839..d29a74a3220 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -79,14 +79,14 @@ void WorldProbePipeline::sync() side.cubemap_face_ps.init(); side.cubemap_face_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); } - dummy_cryptomatte_tx_.ensure_2d( - GPU_RGBA16F, int2(1), GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); - dummy_renderpass_tx_.ensure_2d( - GPU_RGBA32F, int2(1), GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); - dummy_aov_color_tx_.ensure_2d_array( - GPU_RGBA16F, int2(1), 1, GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); - dummy_aov_value_tx_.ensure_2d_array( - GPU_R16F, int2(1), 1, GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE); + const int2 extent(1); + const 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) @@ -94,6 +94,7 @@ void WorldProbePipeline::sync(GPUMaterial *gpumat) for (int face : IndexRange(6)) { sync(gpumat, face); } + has_draw_commands_ = true; } void WorldProbePipeline::sync(GPUMaterial *gpumat, int face) @@ -119,18 +120,23 @@ void WorldProbePipeline::sync(GPUMaterial *gpumat, int face) 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_); + /* 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); - /* To allow opaque pass rendering over it. */ + 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"); diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index b08cc723e70..e66549b2d77 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -65,6 +65,12 @@ class WorldProbePipeline { 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"}}, -- 2.30.2 From a58620c766e807c7c9be321fa96eeb7cff18ad0c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 1 Jun 2023 08:45:44 +0200 Subject: [PATCH 05/23] Some small cleanups and code comments. --- source/blender/draw/engines/eevee_next/eevee_pipeline.cc | 2 +- .../blender/draw/engines/eevee_next/eevee_reflection_probes.cc | 2 +- .../blender/draw/engines/eevee_next/eevee_reflection_probes.hh | 1 + .../engines/eevee_next/shaders/eevee_reflection_probe_lib.glsl | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index d29a74a3220..a75341936f5 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -80,7 +80,7 @@ void WorldProbePipeline::sync() side.cubemap_face_ps.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); } const int2 extent(1); - const eGPUTextureUsage usage = GPU_TEXTURE_USAGE_MEMORYLESS | GPU_TEXTURE_USAGE_SHADER_WRITE; + 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); 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 62d61ee7251..505325f3072 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -22,7 +22,7 @@ void ReflectionProbeModule::init() MAX_PROBES, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, NULL, - 12); + MIPMAP_LEVELS); GPU_texture_mipmap_mode(cubemaps_tx_, true, true); } } 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 7e567d1de73..5f9740d9794 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -54,6 +54,7 @@ class ReflectionProbeModule { * 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. 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 index eef1569cff3..b6b73c57c34 100644 --- 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 @@ -6,7 +6,8 @@ void light_world_eval(ClosureDiffuse diffuse, inout vec3 out_specular) { float linear_roughness = fast_sqrt(reflection.roughness); - /* TODO: This should be based by actual LOD?.*/ + /* 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; -- 2.30.2 From 845406721f1e7cd3c360fa404fb35f0f6c446a62 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 16 Jun 2023 07:59:44 +0200 Subject: [PATCH 06/23] Make format --- source/blender/draw/intern/DRW_gpu_wrapper.hh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index 12eb202db4b..9ff08b18498 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -1035,7 +1035,8 @@ class TextureRef : public Texture { * Dummy type to bind texture as image. * It is just a GPUTexture in disguise. */ -class Image {}; +class Image { +}; static inline Image *as_image(GPUTexture *tex) { -- 2.30.2 From dd7948de9d1bcb110bd137e8d5bc2e97bb2ecbc6 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 19 Jun 2023 09:27:15 +0200 Subject: [PATCH 07/23] Attach missing render buffers --- source/blender/draw/engines/eevee_next/eevee_pipeline.cc | 3 +++ source/blender/draw/engines/eevee_next/eevee_view.cc | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index edec07969fb..f21eeb7d546 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -108,6 +108,9 @@ void WorldProbePipeline::sync(GPUMaterial *gpumat, int face) 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_); diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index c7dd6486358..9ba82467e1e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -118,8 +118,8 @@ void ShadingView::render() GPU_framebuffer_bind(combined_fb_); GPU_framebuffer_clear_color_depth(combined_fb_, clear_color, 1.0f); - inst_.pipelines.world.render(render_view_new_); 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. */ inst_.lights.set_view(render_view_new_, extent_); -- 2.30.2 From 9fc915ee6716e8f478c72cdeddbc218003e13b60 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Mon, 19 Jun 2023 09:38:01 +0200 Subject: [PATCH 08/23] Add all missing texture/image bindings. --- source/blender/draw/engines/eevee_next/eevee_pipeline.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index f21eeb7d546..b3fc4e02ae8 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -117,6 +117,8 @@ void WorldProbePipeline::sync(GPUMaterial *gpumat, int face) 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); -- 2.30.2 From 38e9938fac30968daf996f23ccc50bc902ca333b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 27 Jun 2023 14:39:59 +0200 Subject: [PATCH 09/23] Add ggx sampling to reflection probe evaluation. --- .../shaders/eevee_reflection_probe_lib.glsl | 69 +++++++++++++-- .../shaders/eevee_sampling_lib.glsl | 84 +++++++++++++++++++ 2 files changed, 148 insertions(+), 5 deletions(-) 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 index d297b3d80c3..5ffed38c87a 100644 --- 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 @@ -1,12 +1,71 @@ +#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl) + void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 out_specular) { - float linear_roughness = fast_sqrt(reflection.roughness); + ivec3 texture_size = textureSize(reflectionProbes, 0); /* 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; + vec3 T, B; + make_orthonormal_basis(reflection.N, T, B); + + float weight = 0.0; + vec3 out_radiance = vec3(0.0); + /* Note: this was dynamic based on the mipmap level that was read from. */ + /* lod 0 => 1 + * 1 => 32 + * 2 => 40 + * 3 => 64 + * else => 128 + * multiplied by the filter quality. */ + const int max_sample_count = 32; + /* Note this is dynamically based on the mip map level. + pinfo->lodfactor = bias + 0.5f * log(square_f(target_size) / pinfo->samples_len) / log(2); + */ + /* Pow4f for Disney Roughness distributed across lod more evenly */ + float roughness = clamp(pow4f(reflection.roughness), 1e-4f, 0.9999f); /* Avoid artifacts */ + + const float lod_factor = 1.0 + + 0.5 * log(float(square_i(texture_size.x)) / float(max_sample_count)) / + log(2); + /* We should find a math formular that would approx max_sample_count and bias. */ + for (int i = 0; i < max_sample_count; i++) { + vec3 Xi = sample_cylinder(hammersley_2d(float(i), max_sample_count)); + + /* Microfacet normal */ + float pdf; + vec3 H = sample_ggx(Xi, roughness, V, reflection.N, T, B, pdf); + + vec3 L = -reflect(V, H); + float NL = dot(reflection.N, L); + + if (NL > 0.0) { + float NH = max(1e-8, dot(reflection.N, H)); /*cosTheta */ + + /* Coarse Approximation of the mapping distortion + * Unit Sphere -> Cubemap Face */ + const float dist = 4.0 * M_PI / 6.0; + /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */ + float lod = clamp(lod_factor - 0.5 * log2(pdf * dist), 0.0, lod_cube_max); + + vec3 l_col = textureLod_cubemapArray(reflectionProbes, vec4(L, 0.0), lod).rgb; + + /* Clamped brightness. */ + float luma = max(1e-8, max_v3(l_col)); + + /* For artistic freedom this should be read from the scene/reflection probe. + * Note: Eevee-legacy read the firefly_factor from gi_glossy_clamp. */ + const float firefly_factor = 1e16; + l_col *= 1.0 - max(0.0, luma - firefly_factor) / luma; + + out_radiance += l_col * NL; + weight += NL; + } + } + + /* TODO: for artistic freedom want to read this from the reflection probe. That can be added as + * part of the reflection probe patch. */ + const float intensity_factor = 1.0; + out_specular += vec3(intensity_factor * out_radiance / weight); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl index a54133167ac..e235b795277 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_sampling_lib.glsl @@ -5,6 +5,7 @@ **/ #pragma BLENDER_REQUIRE(common_math_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) /* -------------------------------------------------------------------- */ /** \name Sampling data. @@ -102,3 +103,86 @@ vec3 sample_cylinder(vec2 rand) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Microfacet GGX distribution + * \{ */ + +#define USE_VISIBLE_NORMAL 1 + +float D_ggx_opti(float NH, float a2) +{ + float tmp = (NH * a2 - NH) * NH + 1.0; + return M_PI * tmp * tmp; /* Doing RCP and mul a2 at the end */ +} + +float G1_Smith_GGX_opti(float NX, float a2) +{ + /* Using Brian Karis approach and refactoring by NX/NX + * this way the (2*NL)*(2*NV) in G = G1(V) * G1(L) gets canceled by the brdf denominator 4*NL*NV + * Rcp is done on the whole G later + * Note that this is not convenient for the transmission formula */ + return NX + sqrt(NX * (NX - NX * a2) + a2); + /* return 2 / (1 + sqrt(1 + a2 * (1 - NX*NX) / (NX*NX) ) ); /* Reference function */ +} + +float pdf_ggx_reflect(float NH, float NV, float VH, float alpha) +{ + float a2 = sqr(alpha); +#if USE_VISIBLE_NORMAL + float D = a2 / D_ggx_opti(NH, a2); + float G1 = NV * 2.0 / G1_Smith_GGX_opti(NV, a2); + return G1 * VH * D / NV; +#else + return NH * a2 / D_ggx_opti(NH, a2); +#endif +} + +vec3 sample_ggx(vec3 rand, float alpha, vec3 Vt) +{ +#if USE_VISIBLE_NORMAL + /* From: + * "A Simpler and Exact Sampling Routine for the GGXDistribution of Visible Normals" + * by Eric Heitz. + * http://jcgt.org/published/0007/04/01/slides.pdf + * View vector is expected to be in tangent space. */ + + /* Stretch view. */ + vec3 Th, Bh, Vh = normalize(vec3(alpha * Vt.xy, Vt.z)); + make_orthonormal_basis(Vh, Th, Bh); + /* Sample point with polar coordinates (r, phi). */ + float r = sqrt(rand.x); + float x = r * rand.y; + float y = r * rand.z; + float s = 0.5 * (1.0 + Vh.z); + y = (1.0 - s) * sqrt(1.0 - x * x) + s * y; + float z = sqrt(saturate(1.0 - x * x - y * y)); + /* Compute normal. */ + vec3 Hh = x * Th + y * Bh + z * Vh; + /* Unstretch. */ + vec3 Ht = normalize(vec3(alpha * Hh.xy, saturate(Hh.z))); + /* Microfacet Normal. */ + return Ht; +#else + /* Theta is the cone angle. */ + float z = sqrt((1.0 - rand.x) / (1.0 + sqr(alpha) * rand.x - rand.x)); /* cos theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ + float x = r * rand.y; + float y = r * rand.z; + /* Microfacet Normal */ + return vec3(x, y, z); +#endif +} + +vec3 sample_ggx(vec3 rand, float alpha, vec3 V, vec3 N, vec3 T, vec3 B, out float pdf) +{ + vec3 Vt = world_to_tangent(V, N, T, B); + vec3 Ht = sample_ggx(rand, alpha, Vt); + float NH = saturate(Ht.z); + float NV = saturate(Vt.z); + float VH = saturate(dot(Vt, Ht)); + pdf = pdf_ggx_reflect(NH, NV, VH, alpha); + return tangent_to_world(Ht, N, T, B); +} + +/** \} */ -- 2.30.2 From 71096a7e624d7744108ad7bc3d08536335e6e838 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 27 Jun 2023 16:12:04 +0200 Subject: [PATCH 10/23] Sampling reflective light. --- .../shaders/eevee_reflection_probe_lib.glsl | 90 ++++++++----------- .../shaders/infos/eevee_deferred_info.hh | 1 + 2 files changed, 40 insertions(+), 51 deletions(-) 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 index 5ffed38c87a..454184d92f9 100644 --- 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 @@ -7,65 +7,53 @@ void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 o * eventually this should based on a user setting. */ float lod_cube_max = 12.0; + /* Pow2f to distributed across lod more evenly */ + float roughness = clamp(pow2f(reflection.roughness), 1e-4f, 0.9999f); /* Avoid artifacts */ + +#if defined(GPU_COMPUTE_SHADER) + vec2 frag_coord = vec2(gl_GlobalInvocationID.xy) + 0.5; +#else + vec2 frag_coord = gl_FragCoord.xy; +#endif + float noise = utility_tx_fetch(utility_tx, frag_coord, UTIL_BLUE_NOISE_LAYER).g; + vec2 rand = fract(vec2(noise) + sampling_rng_2D_get(SAMPLING_RAYTRACE_U)); + + vec3 Xi = sample_cylinder(rand); + + /* Microfacet normal */ vec3 T, B; make_orthonormal_basis(reflection.N, T, B); + float pdf; + vec3 H = sample_ggx(Xi, roughness, V, reflection.N, T, B, pdf); - float weight = 0.0; - vec3 out_radiance = vec3(0.0); - /* Note: this was dynamic based on the mipmap level that was read from. */ - /* lod 0 => 1 - * 1 => 32 - * 2 => 40 - * 3 => 64 - * else => 128 - * multiplied by the filter quality. */ - const int max_sample_count = 32; - /* Note this is dynamically based on the mip map level. - pinfo->lodfactor = bias + 0.5f * log(square_f(target_size) / pinfo->samples_len) / log(2); - */ - /* Pow4f for Disney Roughness distributed across lod more evenly */ - float roughness = clamp(pow4f(reflection.roughness), 1e-4f, 0.9999f); /* Avoid artifacts */ + vec3 L = -reflect(V, H); + float NL = dot(reflection.N, L); - const float lod_factor = 1.0 + - 0.5 * log(float(square_i(texture_size.x)) / float(max_sample_count)) / - log(2); - /* We should find a math formular that would approx max_sample_count and bias. */ - for (int i = 0; i < max_sample_count; i++) { - vec3 Xi = sample_cylinder(hammersley_2d(float(i), max_sample_count)); + if (NL > 0.0) { + float NH = max(1e-8, dot(reflection.N, H)); /*cosTheta */ - /* Microfacet normal */ - float pdf; - vec3 H = sample_ggx(Xi, roughness, V, reflection.N, T, B, pdf); + /* Coarse Approximation of the mapping distortion + * Unit Sphere -> Cubemap Face */ + const float dist = 4.0 * M_PI / 6.0; - vec3 L = -reflect(V, H); - float NL = dot(reflection.N, L); + /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */ + /* const float bias = 2.0; + const float lod_factor = bias + 0.5 * log(float(square_i(texture_size.x))) / log(2); + float lod = clamp(lod_factor - 0.5 * log2(pdf * dist), 0.0, lod_cube_max); + */ + vec3 l_col = textureLod_cubemapArray(reflectionProbes, vec4(L, 0.0), 0.0).rgb; - if (NL > 0.0) { - float NH = max(1e-8, dot(reflection.N, H)); /*cosTheta */ + /* Clamped brightness. */ + // float luma = max(1e-8, max_v3(l_col)); - /* Coarse Approximation of the mapping distortion - * Unit Sphere -> Cubemap Face */ - const float dist = 4.0 * M_PI / 6.0; - /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */ - float lod = clamp(lod_factor - 0.5 * log2(pdf * dist), 0.0, lod_cube_max); + /* For artistic freedom this should be read from the scene/reflection probe. + * Note: Eevee-legacy read the firefly_factor from gi_glossy_clamp. */ + // const float firefly_factor = 1e16; + // l_col *= 1.0 - max(0.0, luma - firefly_factor) / luma; - vec3 l_col = textureLod_cubemapArray(reflectionProbes, vec4(L, 0.0), lod).rgb; - - /* Clamped brightness. */ - float luma = max(1e-8, max_v3(l_col)); - - /* For artistic freedom this should be read from the scene/reflection probe. - * Note: Eevee-legacy read the firefly_factor from gi_glossy_clamp. */ - const float firefly_factor = 1e16; - l_col *= 1.0 - max(0.0, luma - firefly_factor) / luma; - - out_radiance += l_col * NL; - weight += NL; - } + /* TODO: for artistic freedom want to read this from the reflection probe. That can be added as + * part of the reflection probe patch. */ + const float intensity_factor = 1.0; + out_specular += vec3(intensity_factor * l_col); } - - /* TODO: for artistic freedom want to read this from the reflection probe. That can be added as - * part of the reflection probe patch. */ - const float intensity_factor = 1.0; - out_specular += vec3(intensity_factor * out_radiance / weight); } 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 69381cf2138..660a5970f46 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 @@ -36,6 +36,7 @@ GPU_SHADER_CREATE_INFO(eevee_deferred_light) .sampler(1, ImageType::FLOAT_2D_ARRAY, "gbuffer_color_tx") .additional_info("eevee_shared", "eevee_utility_texture", + "eevee_sampling_data", "eevee_light_data", "eevee_reflection_probe_data", "eevee_lightprobe_data", -- 2.30.2 From 8236179f5747ddf3bded5eb0ebcd909004a522b5 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 08:50:02 +0200 Subject: [PATCH 11/23] LOD selection --- .../shaders/eevee_reflection_probe_lib.glsl | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) 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 index 454184d92f9..f5be0950ffa 100644 --- 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 @@ -4,11 +4,12 @@ void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 o { ivec3 texture_size = textureSize(reflectionProbes, 0); /* TODO: This should be based by actual resolution. Currently the resolution is fixed but - * eventually this should based on a user setting. */ + * eventually this should based on a user setting and part of the reflection probe data that will + * be introduced by the reflection probe patch. */ float lod_cube_max = 12.0; /* Pow2f to distributed across lod more evenly */ - float roughness = clamp(pow2f(reflection.roughness), 1e-4f, 0.9999f); /* Avoid artifacts */ + float roughness = clamp(pow2f(reflection.roughness), 1e-4f, 0.9999f); #if defined(GPU_COMPUTE_SHADER) vec2 frag_coord = vec2(gl_GlobalInvocationID.xy) + 0.5; @@ -30,26 +31,26 @@ void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 o float NL = dot(reflection.N, L); if (NL > 0.0) { - float NH = max(1e-8, dot(reflection.N, H)); /*cosTheta */ - /* Coarse Approximation of the mapping distortion * Unit Sphere -> Cubemap Face */ const float dist = 4.0 * M_PI / 6.0; /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */ - /* const float bias = 2.0; - const float lod_factor = bias + 0.5 * log(float(square_i(texture_size.x))) / log(2); - float lod = clamp(lod_factor - 0.5 * log2(pdf * dist), 0.0, lod_cube_max); - */ - vec3 l_col = textureLod_cubemapArray(reflectionProbes, vec4(L, 0.0), 0.0).rgb; + /* TODO: lod_factor should be precalculated and stored inside the reflection probe data. */ + const float bias = 0; + const float lod_factor = bias + 0.5 * log(float(square_i(texture_size.x))) / log(2); + float lod = clamp(lod_factor - 0.5 * log2(pdf * dist), 0.0, lod_cube_max); + + vec3 l_col = textureLod_cubemapArray(reflectionProbes, vec4(L, 0.0), lod).rgb; /* Clamped brightness. */ - // float luma = max(1e-8, max_v3(l_col)); - /* For artistic freedom this should be read from the scene/reflection probe. - * Note: Eevee-legacy read the firefly_factor from gi_glossy_clamp. */ - // const float firefly_factor = 1e16; - // l_col *= 1.0 - max(0.0, luma - firefly_factor) / luma; + * Note: Eevee-legacy read the firefly_factor from gi_glossy_clamp. + * Note: Firefly removal should be moved to a different shader and also take SSR into + * account.*/ + float luma = max(1e-8, max_v3(l_col)); + const float firefly_factor = 1e16; + l_col *= 1.0 - max(0.0, luma - firefly_factor) / luma; /* TODO: for artistic freedom want to read this from the reflection probe. That can be added as * part of the reflection probe patch. */ -- 2.30.2 From ebb079197aaefb0c01d5c6e552ab2716acafefe9 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 08:55:40 +0200 Subject: [PATCH 12/23] Updated comments --- .../eevee_next/shaders/eevee_reflection_probe_lib.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index f5be0950ffa..92be36826d5 100644 --- 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 @@ -52,8 +52,8 @@ void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 o const float firefly_factor = 1e16; l_col *= 1.0 - max(0.0, luma - firefly_factor) / luma; - /* TODO: for artistic freedom want to read this from the reflection probe. That can be added as - * part of the reflection probe patch. */ + /* TODO: for artistic freedom want to read this from the reflection probe. That will be part of + * the reflection probe patch. */ const float intensity_factor = 1.0; out_specular += vec3(intensity_factor * l_col); } -- 2.30.2 From 72d81fe6a80774b76719b0e13243ea2c056e44ef Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 10:05:15 +0200 Subject: [PATCH 13/23] Use 2d randomizer and clamp upto 4x4 lod texture. --- .../eevee_next/shaders/eevee_reflection_probe_lib.glsl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 index 92be36826d5..b795da48798 100644 --- 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 @@ -16,8 +16,8 @@ void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 o #else vec2 frag_coord = gl_FragCoord.xy; #endif - float noise = utility_tx_fetch(utility_tx, frag_coord, UTIL_BLUE_NOISE_LAYER).g; - vec2 rand = fract(vec2(noise) + sampling_rng_2D_get(SAMPLING_RAYTRACE_U)); + vec2 noise = utility_tx_fetch(utility_tx, frag_coord, UTIL_BLUE_NOISE_LAYER).gb; + vec2 rand = fract(noise + sampling_rng_2D_get(SAMPLING_RAYTRACE_U)); vec3 Xi = sample_cylinder(rand); @@ -39,7 +39,8 @@ void light_world_eval(ClosureReflection reflection, vec3 P, vec3 V, inout vec3 o /* TODO: lod_factor should be precalculated and stored inside the reflection probe data. */ const float bias = 0; const float lod_factor = bias + 0.5 * log(float(square_i(texture_size.x))) / log(2); - float lod = clamp(lod_factor - 0.5 * log2(pdf * dist), 0.0, lod_cube_max); + /* -2: Don't use LOD levels that are smaller than 4x4 pixels. */ + float lod = clamp(lod_factor - 0.5 * log2(pdf * dist), 0.0, lod_cube_max - 2.0); vec3 l_col = textureLod_cubemapArray(reflectionProbes, vec4(L, 0.0), lod).rgb; -- 2.30.2 From b89e6ccd5bfc7bce1440dce156ba69640b9ca4a8 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 11:18:17 +0200 Subject: [PATCH 14/23] Remove usage of GPU_TEXTURE_USAGE_MEMORYLESS --- source/blender/draw/engines/eevee_next/eevee_pipeline.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index a5c7feaf831..ac664619086 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -74,7 +74,7 @@ void WorldProbePipeline::sync() 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; + constexpr eGPUTextureUsage usage = 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); -- 2.30.2 From 92a71de0cbbd346eddcfa105849b6574b18463e8 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 11:21:25 +0200 Subject: [PATCH 15/23] Add comments about dummy textures --- source/blender/draw/engines/eevee_next/eevee_pipeline.hh | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index 87f168681b9..a06a98bb600 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -53,6 +53,7 @@ class WorldProbePipeline { private: Instance &inst_; + /* Dummy textures: required to reuse background shader and avoid another shader variation. */ Texture dummy_renderpass_tx_; Texture dummy_cryptomatte_tx_; Texture dummy_aov_color_tx_; -- 2.30.2 From c7e6778f2331c6151ce4f58eab2f3ce8d780f906 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 11:55:47 +0200 Subject: [PATCH 16/23] Change casing of enum types and const attributes --- .../eevee_next/eevee_reflection_probes.cc | 18 +++++++++--------- .../eevee_next/eevee_reflection_probes.hh | 10 +++++----- 2 files changed, 14 insertions(+), 14 deletions(-) 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 27f229107b7..0dfe111190d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -9,27 +9,27 @@ namespace blender::eevee { void ReflectionProbeModule::init() { if (cubemaps_.is_empty()) { - cubemaps_.reserve(MAX_PROBES); + cubemaps_.reserve(max_probes); /* Initialize the world cubemap. */ ReflectionProbe world_cubemap; - world_cubemap.type = ReflectionProbe::Type::World; + 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, + max_resolution, + max_probes, GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, NULL, - MIPMAP_LEVELS); + max_mipmap_levels); GPU_texture_mipmap_mode(cubemaps_tx_, true, true); } } void ReflectionProbeModule::sync() { - for (int index : IndexRange(MAX_PROBES)) { + for (int index : IndexRange(max_probes)) { ReflectionProbe &cubemap = cubemaps_[index]; if (!cubemap.needs_update()) { continue; @@ -41,7 +41,7 @@ void ReflectionProbeModule::sync() void ReflectionProbeModule::sync(const ReflectionProbe &cubemap) { - if (cubemap.type == ReflectionProbe::Type::World) { + if (cubemap.type == ReflectionProbe::Type::WORLD) { GPUMaterial *world_material = instance_.world.get_world_material(); instance_.pipelines.world.sync(world_material); } @@ -52,7 +52,7 @@ void ReflectionProbeModule::sync(const ReflectionProbe &cubemap) void ReflectionProbeModule::set_world_dirty() { - cubemaps_[WORLD_SLOT].is_dirty = true; + cubemaps_[world_slot].is_dirty = true; } /* -------------------------------------------------------------------- */ @@ -62,7 +62,7 @@ void ReflectionProbeModule::set_world_dirty() bool ReflectionProbe::needs_update() const { - return type != Type::Unused && is_dirty; + return type != Type::UNUSED && is_dirty; } /** \} */ 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 beee5ec5634..5bdcc06281e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -35,7 +35,7 @@ class WorldPipeline; * \{ */ class ReflectionProbe { public: - enum Type { Unused, World }; + enum Type { UNUSED, WORLD }; Type type; bool is_dirty = false; @@ -46,22 +46,22 @@ class ReflectionProbe { class ReflectionProbeModule { private: /** The max number of probes to track. */ - static constexpr int MAX_PROBES = 1; + 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; + static constexpr int max_resolution = 2048; + static constexpr int max_mipmap_levels = log(max_resolution) + 1; /** * Index of the probe that is used for world background. * * NOTE: First probe always contains the world probe. */ - static constexpr int WORLD_SLOT = 0; + static constexpr int world_slot = 0; Instance &instance_; -- 2.30.2 From 00fda3ecdaf5ab9f775bec3b2c1f8fd2456416b7 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 12:59:11 +0200 Subject: [PATCH 17/23] Introducing capture view --- .../draw/engines/eevee_next/eevee_instance.cc | 3 +- .../draw/engines/eevee_next/eevee_instance.hh | 2 + .../draw/engines/eevee_next/eevee_pipeline.cc | 63 ++----------------- .../draw/engines/eevee_next/eevee_pipeline.hh | 28 +-------- .../eevee_next/eevee_reflection_probes.hh | 3 + .../draw/engines/eevee_next/eevee_view.cc | 28 ++++++++- .../draw/engines/eevee_next/eevee_view.hh | 19 ++++++ 7 files changed, 61 insertions(+), 85 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 97000a00660..49929f4c1a4 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -291,7 +291,8 @@ void Instance::render_sample() } sampling.step(); - + + capture_view.render(); main_view.render(); motion_blur.step(); diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index 4a894acd24c..777f3f34d74 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -67,6 +67,7 @@ class Instance { Film film; RenderBuffers render_buffers; MainView main_view; + CaptureView capture_view; World world; LightProbeModule light_probes; IrradianceCache irradiance_cache; @@ -118,6 +119,7 @@ class Instance { film(*this), render_buffers(*this), main_view(*this), + capture_view(*this), world(*this), light_probes(*this), irradiance_cache(*this){}; diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc index f887adeb177..94173a8f4ce 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.cc +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.cc @@ -60,19 +60,8 @@ void BackgroundPipeline::render(View &view) /** \name World Probe Pipeline * \{ */ -void WorldPipeline::sync() +void WorldPipeline::sync(GPUMaterial *gpumat) { - 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_SHADER_WRITE; dummy_cryptomatte_tx_.ensure_2d(GPU_RGBA32F, extent, usage); @@ -80,31 +69,12 @@ void WorldPipeline::sync() 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; -} + PassSimple &pass = cubemap_face_ps_; + pass.init(); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS); -void WorldPipeline::sync(GPUMaterial *gpumat) -{ - for (int face : IndexRange(6)) { - sync(gpumat, face); - } - has_draw_commands_ = true; -} - -void WorldPipeline::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); @@ -127,32 +97,11 @@ void WorldPipeline::sync(GPUMaterial *gpumat, int face) 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 WorldPipeline::render() +void WorldPipeline::render(View &view) { - 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 WorldPipeline::CubemapSide::render(Instance &instance) -{ - instance.manager->submit(cubemap_face_ps, view); + inst_.manager->submit(cubemap_face_ps_, view); } /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh index 86a31bc9309..f8f7b53cb15 100644 --- a/source/blender/draw/engines/eevee_next/eevee_pipeline.hh +++ b/source/blender/draw/engines/eevee_next/eevee_pipeline.hh @@ -59,37 +59,14 @@ class WorldPipeline { 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"}}, - }; + PassSimple cubemap_face_ps_ = {"World.Probe"}; public: WorldPipeline(Instance &inst) : inst_(inst){}; - void sync(); void sync(GPUMaterial *gpumat); - void render(); + void render(View &view); - private: - void sync(GPUMaterial *gpumat, int face); }; // namespace blender::eevee /** \} */ @@ -361,7 +338,6 @@ class PipelineModule { deferred.begin_sync(); forward.sync(); shadow.sync(); - world.sync(); capture.sync(); } 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 5bdcc06281e..e661bb6fb45 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -29,6 +29,7 @@ namespace blender::eevee { class Instance; class WorldPipeline; +class CaptureView; /* -------------------------------------------------------------------- */ /** \name Reflection Probes @@ -85,6 +86,8 @@ class ReflectionProbeModule { void sync(const ReflectionProbe &cubemap); friend class WorldPipeline; + /* Capture View requires access to the cubemaps texture for framebuffer configuration. */ + friend class CaptureView; }; } // 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 a87f9207ccf..76ce61c061d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -118,7 +118,6 @@ void ShadingView::render() GPU_framebuffer_bind(combined_fb_); GPU_framebuffer_clear_color_depth(combined_fb_, clear_color, 1.0f); - inst_.pipelines.world.render(); inst_.pipelines.background.render(render_view_new_); /* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */ @@ -190,4 +189,31 @@ void ShadingView::update_view() /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Capture View + * \{ */ + +void CaptureView::render() +{ + // TODO: only do this when world needs to be captured. + + View view = {"World.Capture.View"}; + + for (int face : IndexRange(6)) { + capture_fb_.ensure( + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_CUBEFACE(inst_.reflection_probes.cubemaps_tx_, face)); + GPU_framebuffer_bind(capture_fb_); + + float4x4 view_m4 = cubeface_mat(face); + float4x4 win_m4; + cubeface_winmat_get(win_m4, 1.0f, 10.0f); + view.sync(view_m4, win_m4); + inst_.pipelines.world.render(view); + } + GPU_texture_update_mipmap_chain(inst_.reflection_probes.cubemaps_tx_); +} + +/** \} */ + } // 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 9d312f49b4b..2f84dd577b3 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.hh +++ b/source/blender/draw/engines/eevee_next/eevee_view.hh @@ -142,4 +142,23 @@ class MainView { /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Capture View + * + * View for capturing cubemap renders outside a ShadingView. + * \{ */ + +class CaptureView { + private: + Instance &inst_; + Framebuffer capture_fb_ = {"World.Capture"}; + + public: + CaptureView(Instance &inst) : inst_(inst) {} + + void render(); +}; + +/** \} */ + } // namespace blender::eevee -- 2.30.2 From 1845470a72ae29108d0e88b593a304872fb82afe Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 13:31:30 +0200 Subject: [PATCH 18/23] Introduce capture view and render world probe --- source/blender/draw/engines/eevee_next/eevee_instance.cc | 2 +- source/blender/draw/engines/eevee_next/eevee_view.cc | 7 ++++++- source/blender/draw/engines/eevee_next/eevee_view.hh | 8 +++++++- source/blender/draw/engines/eevee_next/eevee_world.cc | 1 + 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 49929f4c1a4..4861fce50c4 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -291,7 +291,7 @@ void Instance::render_sample() } sampling.step(); - + capture_view.render(); main_view.render(); diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index 76ce61c061d..cea11f33ddb 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -195,8 +195,11 @@ void ShadingView::update_view() void CaptureView::render() { - // TODO: only do this when world needs to be captured. + if (!world_capture_enable_) { + return; + } + GPU_debug_group_begin("World.Capture"); View view = {"World.Capture.View"}; for (int face : IndexRange(6)) { @@ -212,6 +215,8 @@ void CaptureView::render() inst_.pipelines.world.render(view); } GPU_texture_update_mipmap_chain(inst_.reflection_probes.cubemaps_tx_); + GPU_debug_group_end(); + world_capture_enable_ = false; } /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh index 2f84dd577b3..ca73ec6fa6b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.hh +++ b/source/blender/draw/engines/eevee_next/eevee_view.hh @@ -153,10 +153,16 @@ class CaptureView { Instance &inst_; Framebuffer capture_fb_ = {"World.Capture"}; + bool world_capture_enable_ = false; + public: CaptureView(Instance &inst) : inst_(inst) {} - void render(); + + void world_capture_enable(bool enable) + { + world_capture_enable_ = enable; + } }; /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc index 4520db3750e..2099777a724 100644 --- a/source/blender/draw/engines/eevee_next/eevee_world.cc +++ b/source/blender/draw/engines/eevee_next/eevee_world.cc @@ -91,6 +91,7 @@ void World::sync() if (wo_handle.recalc != 0) { inst_.reflection_probes.set_world_dirty(); + inst_.capture_view.world_capture_enable(true); } wo_handle.reset_recalc_flag(); -- 2.30.2 From f8dd84911f1bd31e81925c3950b383d82133f88c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 13:43:32 +0200 Subject: [PATCH 19/23] Remove obsolete code --- .../draw/engines/eevee_next/eevee_instance.cc | 1 - .../eevee_next/eevee_reflection_probes.cc | 40 ------------------- .../eevee_next/eevee_reflection_probes.hh | 6 --- .../draw/engines/eevee_next/eevee_world.cc | 17 +------- .../draw/engines/eevee_next/eevee_world.hh | 7 ---- 5 files changed, 1 insertion(+), 70 deletions(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index 4861fce50c4..fa400dc4f7d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -147,7 +147,6 @@ void Instance::begin_sync() hiz_buffer.sync(); main_view.sync(); world.sync(); - reflection_probes.sync(); film.sync(); render_buffers.sync(); irradiance_cache.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 index 0dfe111190d..43135c0e69a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -27,44 +27,4 @@ void ReflectionProbeModule::init() } } -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.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 index e661bb6fb45..55873bd25fe 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -73,9 +73,6 @@ class ReflectionProbeModule { ReflectionProbeModule(Instance &instance) : instance_(instance) {} void init(); - void set_world_dirty(); - - void sync(); template void bind_resources(draw::detail::PassBase *pass) { @@ -83,9 +80,6 @@ class ReflectionProbeModule { } private: - void sync(const ReflectionProbe &cubemap); - - friend class WorldPipeline; /* Capture View requires access to the cubemaps texture for framebuffer configuration. */ friend class CaptureView; }; diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc index 2099777a724..7dc8dff60f7 100644 --- a/source/blender/draw/engines/eevee_next/eevee_world.cc +++ b/source/blender/draw/engines/eevee_next/eevee_world.cc @@ -90,7 +90,6 @@ void World::sync() WorldHandle &wo_handle = inst_.sync.sync_world(bl_world); if (wo_handle.recalc != 0) { - inst_.reflection_probes.set_world_dirty(); inst_.capture_view.world_capture_enable(true); } wo_handle.reset_recalc_flag(); @@ -110,21 +109,7 @@ void World::sync() inst_.manager->register_layer_attributes(gpumat); inst_.pipelines.background.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; + inst_.pipelines.world.sync(gpumat); } /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_world.hh b/source/blender/draw/engines/eevee_next/eevee_world.hh index 30d5e146897..c589ffec290 100644 --- a/source/blender/draw/engines/eevee_next/eevee_world.hh +++ b/source/blender/draw/engines/eevee_next/eevee_world.hh @@ -62,13 +62,6 @@ 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(); }; /** \} */ -- 2.30.2 From 7bd30acde77be99a1f009cfcec81e52d16bd9b1b Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 13:50:22 +0200 Subject: [PATCH 20/23] Remove obsolete code --- .../eevee_next/eevee_reflection_probes.cc | 24 ++++++------------- .../eevee_next/eevee_reflection_probes.hh | 23 +++--------------- 2 files changed, 10 insertions(+), 37 deletions(-) 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 43135c0e69a..6a685882f13 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -8,23 +8,13 @@ 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, - max_mipmap_levels); - GPU_texture_mipmap_mode(cubemaps_tx_, true, true); - } + cubemaps_tx_.ensure_cube_array(GPU_RGBA16F, + max_resolution_, + max_probes_, + GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, + NULL, + max_mipmap_levels_); + GPU_texture_mipmap_mode(cubemaps_tx_, true, true); } } // 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 index 55873bd25fe..775dc302b2a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -34,39 +34,22 @@ class CaptureView; /* -------------------------------------------------------------------- */ /** \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; + 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 max_mipmap_levels = log(max_resolution) + 1; - - /** - * Index of the probe that is used for world background. - * - * NOTE: First probe always contains the world probe. - */ - static constexpr int world_slot = 0; + static constexpr int max_resolution_ = 2048; + static constexpr int max_mipmap_levels_ = log(max_resolution_) + 1; Instance &instance_; - Vector cubemaps_; Texture cubemaps_tx_ = {"Probes"}; public: -- 2.30.2 From 3e099329c33666cdba5928e02610712d6425b41f Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 13:53:04 +0200 Subject: [PATCH 21/23] Remove inaccurate comments --- .../draw/engines/eevee_next/eevee_reflection_probes.hh | 10 ---------- 1 file changed, 10 deletions(-) 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 775dc302b2a..a4f01359e4a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -3,16 +3,6 @@ /** \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 -- 2.30.2 From e2ca67fe672b2129df705c251b89acdd83b17780 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 13:54:22 +0200 Subject: [PATCH 22/23] Remove obsolete code --- .../blender/draw/engines/eevee_next/eevee_reflection_probes.hh | 1 - 1 file changed, 1 deletion(-) 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 a4f01359e4a..1f6cb152e2e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -18,7 +18,6 @@ struct Material; namespace blender::eevee { class Instance; -class WorldPipeline; class CaptureView; /* -------------------------------------------------------------------- */ -- 2.30.2 From 8835017422375bfd6e5feb525734e816d5cabee5 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Thu, 29 Jun 2023 15:10:26 +0200 Subject: [PATCH 23/23] Solved review comments. --- .../eevee_next/eevee_reflection_probes.cc | 17 ++++++++++------- .../eevee_next/eevee_reflection_probes.hh | 14 ++++++++++++++ .../draw/engines/eevee_next/eevee_view.cc | 7 +++---- .../draw/engines/eevee_next/eevee_view.hh | 7 ------- .../draw/engines/eevee_next/eevee_world.cc | 2 +- 5 files changed, 28 insertions(+), 19 deletions(-) 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 6a685882f13..56fabb4fb05 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.cc @@ -8,13 +8,16 @@ namespace blender::eevee { void ReflectionProbeModule::init() { - cubemaps_tx_.ensure_cube_array(GPU_RGBA16F, - max_resolution_, - max_probes_, - GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, - NULL, - max_mipmap_levels_); - GPU_texture_mipmap_mode(cubemaps_tx_, true, true); + if (!initialized_) { + cubemaps_tx_.ensure_cube_array(GPU_RGBA16F, + max_resolution_, + max_probes_, + GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT, + NULL, + max_mipmap_levels_); + GPU_texture_mipmap_mode(cubemaps_tx_, true, true); + initialized_ = true; + } } } // 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 index 1f6cb152e2e..2f24bb777b0 100644 --- a/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh +++ b/source/blender/draw/engines/eevee_next/eevee_reflection_probes.hh @@ -41,6 +41,10 @@ class ReflectionProbeModule { Texture cubemaps_tx_ = {"Probes"}; + bool initialized_ = false; + + bool do_world_update_ = false; + public: ReflectionProbeModule(Instance &instance) : instance_(instance) {} @@ -51,7 +55,17 @@ class ReflectionProbeModule { pass->bind_texture(REFLECTION_PROBE_TEX_SLOT, cubemaps_tx_); } + void do_world_update_set(bool value) + { + do_world_update_ = value; + } + private: + bool do_world_update_get() const + { + return do_world_update_; + } + /* Capture View requires access to the cubemaps texture for framebuffer configuration. */ friend class CaptureView; }; diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index cea11f33ddb..e3b6cd39c2d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -195,9 +195,10 @@ void ShadingView::update_view() void CaptureView::render() { - if (!world_capture_enable_) { + if (!inst_.reflection_probes.do_world_update_get()) { return; } + inst_.reflection_probes.do_world_update_set(false); GPU_debug_group_begin("World.Capture"); View view = {"World.Capture.View"}; @@ -209,14 +210,12 @@ void CaptureView::render() GPU_framebuffer_bind(capture_fb_); float4x4 view_m4 = cubeface_mat(face); - float4x4 win_m4; - cubeface_winmat_get(win_m4, 1.0f, 10.0f); + 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.cubemaps_tx_); GPU_debug_group_end(); - world_capture_enable_ = false; } /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_view.hh b/source/blender/draw/engines/eevee_next/eevee_view.hh index ca73ec6fa6b..c115dbce871 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.hh +++ b/source/blender/draw/engines/eevee_next/eevee_view.hh @@ -153,16 +153,9 @@ class CaptureView { Instance &inst_; Framebuffer capture_fb_ = {"World.Capture"}; - bool world_capture_enable_ = false; - public: CaptureView(Instance &inst) : inst_(inst) {} void render(); - - void world_capture_enable(bool enable) - { - world_capture_enable_ = enable; - } }; /** \} */ diff --git a/source/blender/draw/engines/eevee_next/eevee_world.cc b/source/blender/draw/engines/eevee_next/eevee_world.cc index 7dc8dff60f7..908b6491210 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_.capture_view.world_capture_enable(true); + inst_.reflection_probes.do_world_update_set(true); } wo_handle.reset_recalc_flag(); -- 2.30.2