From f7a1775d02af78149e1f6f6902835cdc9a07999f Mon Sep 17 00:00:00 2001 From: Jens Koenen <koenen@vr.rwth-aachen.de> Date: Tue, 20 Sep 2022 13:22:13 +0200 Subject: [PATCH] Finished light propagation volumes and added documentation. --- res/dpr/utility/indirect_library.glsl | 13 +++++ res/dpr/utility/indirect_propagation.comp | 14 ++++-- res/dpr/utility/light_library.glsl | 31 ++++++------ src/scene.hpp | 2 +- src/strategy/multi_view_stereo.cpp | 43 ++--------------- src/strategy/multi_view_stereo.hpp | 6 --- src/strategy/native_stereo_deferred.cpp | 41 ++-------------- src/strategy/native_stereo_deferred.hpp | 6 --- src/strategy/native_stereo_forward.cpp | 43 ++--------------- src/strategy/native_stereo_forward.hpp | 6 --- src/utility/geometry_buffer.cpp | 2 +- src/utility/geometry_buffer.hpp | 24 ++++++---- src/utility/indirect_cache.cpp | 58 ++++++++++++++++++----- src/utility/indirect_cache.hpp | 33 +++++++++++++ src/utility/shadow_cache.hpp | 4 +- src/vr_application.cpp | 46 ++++++++++++++++++ src/vr_application.hpp | 9 ++++ 17 files changed, 203 insertions(+), 178 deletions(-) diff --git a/res/dpr/utility/indirect_library.glsl b/res/dpr/utility/indirect_library.glsl index 85f3b14b..6d439a61 100644 --- a/res/dpr/utility/indirect_library.glsl +++ b/res/dpr/utility/indirect_library.glsl @@ -7,6 +7,10 @@ #define SPHERICAL_HARMONIC_BAND0_FACTOR (0.5 * sqrt(1.0 / PI)) #define SPHERICAL_HARMONIC_BAND1_FACTOR sqrt(3.0 / (4.0 * PI)) +//NOTE: Integration of the spherical harmoinc base functions using the standard factors +#define SPHERICAL_HARMONIC_BAND0_INTEGRATED (2.0 * sqrt(PI)) +#define SPHERICAL_HARMONIC_BAND1_INTEGRATED 0.0 + //NOTE: The given factors where computed for the function I(theta, phi) = max(cos(theta), 0) / PI. // This function was choosen, since the integral over it is one. // Therefore the function describes a distribution. @@ -33,4 +37,13 @@ vec4 spherical_harmonic_cosine_lobe(vec3 direction) SPHERICAL_HARMONIC_COSINE_LOBE_BAND1_FACTOR * (-direction.x)); } +//NOTE: Integrate the given spherical haromic +float spherical_harmonic_integrate(vec4 spherical_harmonic) +{ + return dot(spherical_harmonic, vec4(SPHERICAL_HARMONIC_BAND0_INTEGRATED, + SPHERICAL_HARMONIC_BAND1_INTEGRATED, + SPHERICAL_HARMONIC_BAND1_INTEGRATED, + SPHERICAL_HARMONIC_BAND1_INTEGRATED)); +} + #endif \ No newline at end of file diff --git a/res/dpr/utility/indirect_propagation.comp b/res/dpr/utility/indirect_propagation.comp index 62cb6356..8ed550f6 100644 --- a/res/dpr/utility/indirect_propagation.comp +++ b/res/dpr/utility/indirect_propagation.comp @@ -19,7 +19,7 @@ layout(set = 0, binding = 7, rgba16f) uniform image3D image_green_indirect; layout(set = 0, binding = 8, rgba16f) uniform image3D image_blue_indirect; layout(set = 0, binding = 9) uniform sampler3D sampler_geometry_xy_distribution; -layout(set = 0, binding = 10) uniform sampler3D sampler_geometry_zy_distribution; +layout(set = 0, binding = 10) uniform sampler3D sampler_geometry_zw_distribution; layout(set = 0, binding = 11) uniform IndirectDomainBuffer { @@ -78,7 +78,13 @@ bool check_bounds(ivec3 coord) vec4 load_geometry_distribution(vec3 geometry_coord) { - return vec4(0.0); //TODO: !!! + vec3 coord = geometry_coord / vec3(indirect_domain.indirect_resolution); + + vec4 geometry_distribution = vec4(0.0); + geometry_distribution.xy = texture(sampler_geometry_xy_distribution, coord).xy; + geometry_distribution.zw = texture(sampler_geometry_zw_distribution, coord).xy; + + return geometry_distribution / max(1.0, spherical_harmonic_integrate(geometry_distribution)); } void propagate_neighbour(ivec3 cell_coord, uint neighbour, inout vec4 red_distribution, inout vec4 green_distribution, inout vec4 blue_distribution) @@ -95,8 +101,10 @@ void propagate_neighbour(ivec3 cell_coord, uint neighbour, inout vec4 red_distri vec3 geometry_coord = (vec3(cell_coord) + vec3(neighbour_coord)) / 2.0; vec4 geometry_distribution = load_geometry_distribution(geometry_coord); + vec3 geometry_direction = neighbour_orientation * (-direct_eval_direction); - float visibility = 1.0; //TODO:!!! + float opacity = spherical_harmonic_evaluate(geometry_direction, geometry_distribution); + float visibility = clamp(1.0 - opacity, 0.0, 1.0); //----- Side Faces ---------------------------------------------- diff --git a/res/dpr/utility/light_library.glsl b/res/dpr/utility/light_library.glsl index 8b474bc7..89eb1e0b 100644 --- a/res/dpr/utility/light_library.glsl +++ b/res/dpr/utility/light_library.glsl @@ -5,11 +5,14 @@ After including the light-library, the function apply_lighting(...) can be used to compute lighting. The used lighting model is physically based and was taken from the GLTF-Specification. When the light calculation should also include shadows, the define SHADOW_DESCRIPTOR_SET has to be set. - This defines specifies the descriptor set for the shadow cache. + This define specifies the descriptor set for the shadow cache. + If also indirect lighting should be included, the define INDIRECT_DESCRIPTOR_SET has to be set. + This define specifies the descriptor set for the indirect cache. Example: #define LIGHT_DESCRIPTOR_SET 42 //Required #define SHADOW_DESCRIPTOR_SET 43 //Optional + #define INDIRECT_DESCRIPTOR_SET 44 //Optional #include "light_library.glsl" void main() @@ -285,7 +288,7 @@ vec3 compute_brdf(vec3 light_direction, vec3 normal_direction, vec3 view_directi //-- Indirect Functions ---------------------------------------------------------------------------- #ifdef INDIRECT_DESCRIPTOR_SET -vec3 compute_indirect(vec3 surface_position, vec3 normal_direction, Material material) +vec3 get_indirect_radiance(vec3 surface_position, vec3 normal_direction) { vec3 cell_coord = (surface_position - indirect_domain.min) / (indirect_domain.max - indirect_domain.min); @@ -296,15 +299,12 @@ vec3 compute_indirect(vec3 surface_position, vec3 normal_direction, Material mat //Where center_distance_square is in meter^2 const float center_distance_square = pow(indirect_domain.cell_size / 2.0, 2); - vec3 indirect_light = vec3(0.0); //Where indirect light is in watts / (meter^2 * str) - indirect_light.x = max(0.0, spherical_harmonic_evaluate(-normal_direction, red_distribution)) / center_distance_square; - indirect_light.y = max(0.0, spherical_harmonic_evaluate(-normal_direction, green_distribution)) / center_distance_square; - indirect_light.z = max(0.0, spherical_harmonic_evaluate(-normal_direction, blue_distribution)) / center_distance_square; + vec3 indirect_radiance = vec3(0.0); //Where indirect light is in watts / (meter^2 * str) + indirect_radiance.x = max(0.0, spherical_harmonic_evaluate(-normal_direction, red_distribution)) / center_distance_square; + indirect_radiance.y = max(0.0, spherical_harmonic_evaluate(-normal_direction, green_distribution)) / center_distance_square; + indirect_radiance.z = max(0.0, spherical_harmonic_evaluate(-normal_direction, blue_distribution)) / center_distance_square; - vec3 diffuse_color = mix(material.base_color, vec3(0.0), material.metallic); - vec3 diffuse = compute_brdf_diffuse(diffuse_color); - - return diffuse * indirect_light; + return indirect_radiance; } #endif @@ -328,11 +328,7 @@ vec3 apply_lighting(vec3 view_position, vec3 surface_position, vec3 surface_norm vec3 normal_direction = normalize(surface_normal); vec3 view_direction = normalize(view_position - surface_position); - //lighting += material.base_color * light_parameter.ambient; //where ambient is in watts/meter^2 *str - -#ifdef INDIRECT_DESCRIPTOR_SET - lighting += compute_indirect(surface_position, normal_direction, material); -#endif + lighting += material.base_color * light_parameter.ambient; //where ambient is in watts/meter^2 *str for (uint light = 0; light < light_parameter.light_count; light++) { @@ -345,6 +341,11 @@ vec3 apply_lighting(vec3 view_position, vec3 surface_position, vec3 surface_norm #endif } +#ifdef INDIRECT_DESCRIPTOR_SET + material.roughness = 1.0; //NOTE: Set to one, since light propagation volumes can only deliver diffuse indirect. + lighting += compute_brdf(normal_direction, normal_direction, view_direction, material) * get_indirect_radiance(surface_position, normal_direction) * dot(normal_direction, normal_direction); +#endif + lighting *= (1.0 - material.occlusion); } diff --git a/src/scene.hpp b/src/scene.hpp index 6b9635ec..c96b6fbe 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -217,7 +217,7 @@ private: glm::vec3 scene_max = glm::vec3(0.0f); const glm::vec3 ambient_color = glm::vec3(0.0f); //NOTE: Indirect should be compute using an indirect cache. - float exposure = 0.1f; //NOTE: This factor is used so that the Bistro scene looks okay. + float exposure = 1.0f; bool exposure_changed = false; uint32_t light_directional_count = 0; diff --git a/src/strategy/multi_view_stereo.cpp b/src/strategy/multi_view_stereo.cpp index afb9be60..aa2b1d25 100644 --- a/src/strategy/multi_view_stereo.cpp +++ b/src/strategy/multi_view_stereo.cpp @@ -21,20 +21,6 @@ bool MultiViewStereo::on_setup_device(lava::device::create_param& parameters) bool MultiViewStereo::on_create() { - this->shadow_cache = make_shadow_cache(); - - if (!this->shadow_cache->create(this->get_scene(), ShadowCacheSettings())) - { - return false; - } - - this->indirect_cache = make_indirect_cache(); - - if (!this->indirect_cache->create(this->get_scene(), IndirectCacheSettings())) - { - return false; - } - if (!this->create_pipeline_layout()) { return false; @@ -55,17 +41,6 @@ bool MultiViewStereo::on_create() void MultiViewStereo::on_destroy() { - if (this->shadow_cache != nullptr) - { - this->shadow_cache->destroy(); - } - - if (this->indirect_cache != nullptr) - { - this->indirect_cache->destroy(); - this->indirect_computed = false; - } - if (this->pipeline_layout != nullptr) { this->pipeline_layout->destroy(); @@ -106,16 +81,6 @@ bool MultiViewStereo::on_render(VkCommandBuffer command_buffer, lava::index fram { this->get_headset()->submit_metadata(FrameMetadata()); - if (!this->indirect_computed) - { - this->indirect_cache->compute_indirect(command_buffer, frame); - this->indirect_computed = true; - } - - this->get_pass_timer()->begin_pass(command_buffer, "shadow"); - this->shadow_cache->compute_shadow(command_buffer, frame); - this->get_pass_timer()->end_pass(command_buffer); - this->get_pass_timer()->begin_pass(command_buffer, "multi_eye"); this->render_pass->process(command_buffer, 0); this->get_pass_timer()->end_pass(command_buffer); @@ -246,8 +211,8 @@ bool MultiViewStereo::create_pipeline_layout() this->pipeline_layout->add(this->get_scene()->get_mesh_descriptor()); this->pipeline_layout->add(this->get_scene()->get_material_descriptor()); this->pipeline_layout->add(this->get_scene()->get_light_descriptor()); - this->pipeline_layout->add(this->shadow_cache->get_descriptor()); - this->pipeline_layout->add(this->indirect_cache->get_descriptor()); + this->pipeline_layout->add(this->get_application()->get_shadow_cache()->get_descriptor()); + this->pipeline_layout->add(this->get_application()->get_indirect_cache()->get_descriptor()); if (!this->pipeline_layout->create(this->get_device())) { @@ -430,8 +395,8 @@ void MultiViewStereo::pipeline_function(VkCommandBuffer command_buffer) this->pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(EYE_LEFT, frame_index), 0); this->pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(EYE_RIGHT, frame_index), 1); this->pipeline_layout->bind(command_buffer, this->get_scene()->get_light_descriptor_set(frame_index), 4); - this->pipeline_layout->bind(command_buffer, this->shadow_cache->get_descriptor_set(), 5); - this->pipeline_layout->bind(command_buffer, this->indirect_cache->get_descriptor_set(), 6); + this->pipeline_layout->bind(command_buffer, this->get_application()->get_shadow_cache()->get_descriptor_set(), 5); + this->pipeline_layout->bind(command_buffer, this->get_application()->get_indirect_cache()->get_descriptor_set(), 6); const std::vector<SceneMaterial>& materials = this->get_scene()->get_materials(); diff --git a/src/strategy/multi_view_stereo.hpp b/src/strategy/multi_view_stereo.hpp index c597d223..81e53c61 100644 --- a/src/strategy/multi_view_stereo.hpp +++ b/src/strategy/multi_view_stereo.hpp @@ -3,8 +3,6 @@ #include <array> #include "stereo_strategy.hpp" -#include "utility/shadow_cache.hpp" -#include "utility/indirect_cache.hpp" class MultiViewStereo final : public StereoStrategy { @@ -37,10 +35,6 @@ private: private: VkPhysicalDeviceMultiviewFeatures features; - ShadowCache::Ptr shadow_cache; - IndirectCache::Ptr indirect_cache; - bool indirect_computed = false; - lava::pipeline_layout::ptr pipeline_layout; lava::graphics_pipeline::ptr pipeline; diff --git a/src/strategy/native_stereo_deferred.cpp b/src/strategy/native_stereo_deferred.cpp index 1bad6edf..d891225c 100644 --- a/src/strategy/native_stereo_deferred.cpp +++ b/src/strategy/native_stereo_deferred.cpp @@ -3,20 +3,6 @@ bool NativeStereoDeferred::on_create() { - this->shadow_cache = make_shadow_cache(); - - if (!this->shadow_cache->create(this->get_scene(), ShadowCacheSettings())) - { - return false; - } - - this->indirect_cache = make_indirect_cache(); - - if (!this->indirect_cache->create(this->get_scene(), IndirectCacheSettings())) - { - return false; - } - if (!this->create_pipeline_layout()) { return false; @@ -47,17 +33,6 @@ bool NativeStereoDeferred::on_create() void NativeStereoDeferred::on_destroy() { - if (this->shadow_cache != nullptr) - { - this->shadow_cache->destroy(); - } - - if (this->indirect_cache != nullptr) - { - this->indirect_cache->destroy(); - this->indirect_computed = false; - } - if (this->pipeline_layout != nullptr) { this->pipeline_layout->destroy(); @@ -96,22 +71,12 @@ bool NativeStereoDeferred::on_render(VkCommandBuffer command_buffer, lava::index { this->get_headset()->submit_metadata(FrameMetadata()); - if (!this->indirect_computed) - { - this->indirect_cache->compute_indirect(command_buffer, frame); - this->indirect_computed = true; - } - - this->get_pass_timer()->begin_pass(command_buffer, "shadow"); - this->shadow_cache->compute_shadow(command_buffer, frame); - this->get_pass_timer()->end_pass(command_buffer); - this->get_pass_timer()->begin_pass(command_buffer, "left_eye"); this->eye_passes[0].render_pass->process(command_buffer, 0); this->get_pass_timer()->end_pass(command_buffer); this->get_pass_timer()->begin_pass(command_buffer, "left_eye_lighting"); - this->eye_passes[0].geometry_buffer->apply_local_lighting(command_buffer, frame, this->get_stereo_transform()->get_descriptor_set(EYE_LEFT, get_application()->get_frame_index())); + this->eye_passes[0].geometry_buffer->apply_lighting(command_buffer, frame, this->get_stereo_transform()->get_descriptor_set(EYE_LEFT, get_application()->get_frame_index())); this->get_pass_timer()->end_pass(command_buffer); this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_LEFT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "left_eye"); @@ -123,7 +88,7 @@ bool NativeStereoDeferred::on_render(VkCommandBuffer command_buffer, lava::index this->get_pass_timer()->end_pass(command_buffer); this->get_pass_timer()->begin_pass(command_buffer, "right_eye_lighting"); - this->eye_passes[1].geometry_buffer->apply_local_lighting(command_buffer, frame, this->get_stereo_transform()->get_descriptor_set(EYE_RIGHT, get_application()->get_frame_index())); + this->eye_passes[1].geometry_buffer->apply_lighting(command_buffer, frame, this->get_stereo_transform()->get_descriptor_set(EYE_RIGHT, get_application()->get_frame_index())); this->get_pass_timer()->end_pass(command_buffer); this->get_frame_capture()->capture_image(command_buffer, this->get_headset()->get_framebuffer(EYE_RIGHT), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "right_eye"); @@ -164,7 +129,7 @@ bool NativeStereoDeferred::create_render_pass(Eye eye) { GeometryBuffer::Ptr geometry_buffer = make_geometry_buffer(); - if (!geometry_buffer->create(this->get_headset()->get_framebuffer(eye), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, this->get_stereo_transform()->get_descriptor(), this->get_scene(), this->shadow_cache, this->indirect_cache)) + if (!geometry_buffer->create(this->get_headset()->get_framebuffer(eye), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, this->get_stereo_transform()->get_descriptor(), this->get_scene(), this->get_application()->get_shadow_cache(), this->get_application()->get_indirect_cache())) { lava::log()->error("Can't create geometry buffer for native stereo deferred!"); diff --git a/src/strategy/native_stereo_deferred.hpp b/src/strategy/native_stereo_deferred.hpp index df8c17dc..0c5c48c2 100644 --- a/src/strategy/native_stereo_deferred.hpp +++ b/src/strategy/native_stereo_deferred.hpp @@ -4,8 +4,6 @@ #include "stereo_strategy.hpp" #include "utility/geometry_buffer.hpp" -#include "utility/shadow_cache.hpp" -#include "utility/indirect_cache.hpp" struct NativeStereoDeferredPass { @@ -40,10 +38,6 @@ private: void pipeline_function(VkCommandBuffer command_buffer, Eye eye); private: - ShadowCache::Ptr shadow_cache; - IndirectCache::Ptr indirect_cache; - bool indirect_computed = false; - lava::pipeline_layout::ptr pipeline_layout; std::array<NativeStereoDeferredPass, 2> eye_passes; }; diff --git a/src/strategy/native_stereo_forward.cpp b/src/strategy/native_stereo_forward.cpp index 5b00e4b1..41b2e4ed 100644 --- a/src/strategy/native_stereo_forward.cpp +++ b/src/strategy/native_stereo_forward.cpp @@ -3,20 +3,6 @@ bool NativeStereoForward::on_create() { - this->shadow_cache = make_shadow_cache(); - - if (!this->shadow_cache->create(this->get_scene(), ShadowCacheSettings())) - { - return false; - } - - this->indirect_cache = make_indirect_cache(); - - if (!this->indirect_cache->create(this->get_scene(), IndirectCacheSettings())) - { - return false; - } - if (!this->create_pipeline_layout()) { return false; @@ -47,17 +33,6 @@ bool NativeStereoForward::on_create() void NativeStereoForward::on_destroy() { - if (this->shadow_cache != nullptr) - { - this->shadow_cache->destroy(); - } - - if (this->indirect_cache != nullptr) - { - this->indirect_cache->destroy(); - this->indirect_computed = false; - } - if (this->pipeline_layout != nullptr) { this->pipeline_layout->destroy(); @@ -96,16 +71,6 @@ bool NativeStereoForward::on_render(VkCommandBuffer command_buffer, lava::index { this->get_headset()->submit_metadata(FrameMetadata()); - if (!this->indirect_computed) - { - this->indirect_cache->compute_indirect(command_buffer, frame); - this->indirect_computed = true; - } - - this->get_pass_timer()->begin_pass(command_buffer, "shadow"); - this->shadow_cache->compute_shadow(command_buffer, frame); - this->get_pass_timer()->end_pass(command_buffer); - this->get_pass_timer()->begin_pass(command_buffer, "left_eye"); this->eye_passes[0].render_pass->process(command_buffer, 0); this->get_pass_timer()->end_pass(command_buffer); @@ -142,8 +107,8 @@ bool NativeStereoForward::create_pipeline_layout() this->pipeline_layout->add(this->get_scene()->get_material_descriptor()); this->pipeline_layout->add(this->get_scene()->get_mesh_descriptor()); this->pipeline_layout->add(this->get_scene()->get_light_descriptor()); - this->pipeline_layout->add(this->shadow_cache->get_descriptor()); - this->pipeline_layout->add(this->indirect_cache->get_descriptor()); + this->pipeline_layout->add(this->get_application()->get_shadow_cache()->get_descriptor()); + this->pipeline_layout->add(this->get_application()->get_indirect_cache()->get_descriptor()); if (!this->pipeline_layout->create(this->get_device())) { @@ -304,8 +269,8 @@ void NativeStereoForward::pipeline_function(VkCommandBuffer command_buffer, Eye this->pipeline_layout->bind(command_buffer, this->get_stereo_transform()->get_descriptor_set(eye, frame_index), 0); this->pipeline_layout->bind(command_buffer, this->get_scene()->get_light_descriptor_set(frame_index), 3); - this->pipeline_layout->bind(command_buffer, this->shadow_cache->get_descriptor_set(), 4); - this->pipeline_layout->bind(command_buffer, this->indirect_cache->get_descriptor_set(), 5); + this->pipeline_layout->bind(command_buffer, this->get_application()->get_shadow_cache()->get_descriptor_set(), 4); + this->pipeline_layout->bind(command_buffer, this->get_application()->get_indirect_cache()->get_descriptor_set(), 5); const std::vector<SceneMaterial>& materials = this->get_scene()->get_materials(); diff --git a/src/strategy/native_stereo_forward.hpp b/src/strategy/native_stereo_forward.hpp index 8d43752f..96eff477 100644 --- a/src/strategy/native_stereo_forward.hpp +++ b/src/strategy/native_stereo_forward.hpp @@ -3,8 +3,6 @@ #include <array> #include "stereo_strategy.hpp" -#include "utility/shadow_cache.hpp" -#include "utility/indirect_cache.hpp" struct NativeStereoForwardPass { @@ -39,10 +37,6 @@ private: void pipeline_function(VkCommandBuffer command_buffer, Eye eye); private: - ShadowCache::Ptr shadow_cache; - IndirectCache::Ptr indirect_cache; - bool indirect_computed = false; - lava::pipeline_layout::ptr pipeline_layout; lava::attachment::ptr depth_attachment; lava::attachment::ptr color_attachment; diff --git a/src/utility/geometry_buffer.cpp b/src/utility/geometry_buffer.cpp index 2482ef4d..27ff6920 100644 --- a/src/utility/geometry_buffer.cpp +++ b/src/utility/geometry_buffer.cpp @@ -139,7 +139,7 @@ void GeometryBuffer::destroy() this->output_layout = VK_IMAGE_LAYOUT_UNDEFINED; } -void GeometryBuffer::apply_local_lighting(VkCommandBuffer command_buffer, lava::index frame, VkDescriptorSet per_frame_descriptor_set) +void GeometryBuffer::apply_lighting(VkCommandBuffer command_buffer, lava::index frame, VkDescriptorSet per_frame_descriptor_set) { this->frame = frame; this->pipeline_layout->bind(command_buffer, per_frame_descriptor_set, 2); diff --git a/src/utility/geometry_buffer.hpp b/src/utility/geometry_buffer.hpp index 735e3bd8..a8173f7b 100644 --- a/src/utility/geometry_buffer.hpp +++ b/src/utility/geometry_buffer.hpp @@ -1,20 +1,25 @@ /* - The geometry buffer is responsible for the allocation of the images of the geometry buffer and allows to compute and write the local lighting to a given output image. - During the creation of the geometry buffer, an output image has to be specified in which the local lighting will be written. + The geometry buffer is responsible for the allocation of the images of the geometry buffer and allows to compute and write the final lighting to a given output image. + During the creation of the geometry buffer, an output image has to be specified in which the final lighting will be written. After the geometry has been created successfully, the resources provided by the geometry buffer can be used to create a render pass in order to write into the geometry buffer. - Before calling the function apply_local_lighting(...) and computing the local lighting, it is neccessary to ensure that every writing process effecting the geometry buffer has been completed. + Before calling the function apply_lighting(...) and computing the final lighting, it is neccessary to ensure that every writing process effecting the geometry buffer has been completed. Such a synchronisation can be defined by adding a render pass dependency between the last and the extrenal subpass. - After the completion of apply_local_lighting(...) the local lighting can be read from the output image in a fragment shader without any additional synchronisations. - In order to also include shadows when executing apply_local_lighting(...), a shadow cache object has to be added to the create pareameters. + After the completion of apply_lighting(...) the final lighting can be read from the output image in a fragment shader without any additional synchronisations. + In order to also include shadows when executing apply_lighting(...), a shadow cache object has to be added to the create pareameters. + For additional indirect lighting, an indirect cache object can be added during the creation of the geometry buffer. Example: //Optional: Shadow Cache ShadowCache::Ptr shadow_cache = make_shadow_cache(); shadow_cache->create(get_scene(), ShadowCacheSettings()): + //Optional: Indirect Cache + IndirectCache::Ptr indirect_cache = make_indirect_cache(); + indirect_cache->create(get_scene(), IndirectCacheSettings()); + //Create render pass GeometryBuffer::Ptr geometry_buffer = make_geometry_buffer(); - geometry_buffer->create(output_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, get_stereo_transform()->get_descriptor(), get_scene(), Optional: shadow_cache); + geometry_buffer->create(output_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, get_stereo_transform()->get_descriptor(), get_scene(), Optional: shadow_cache, Optional: indirect_cache); lava::subpass_dependency::ptr subpass_dependency = lava::make_subpass_dependency(0, VK_SUBPASS_EXTERNAL); subpass_dependency->set_stage_mask(..., VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); @@ -46,7 +51,8 @@ render_pass->create({image_views}, ...); //During rendering - shadow_cache->compute_shadow(command_buffer, frame); //Optinal: Generate shadow maps + shadow_cache->compute_shadow(command_buffer, frame); //Optional: Generate shadow maps + indirect_cache->compute_indirect(command_buffer, frame); //Optional: Compute indirect lighting render_pass->process(command_buffer, 0); //Write to geometry buffer geometry_buffer->apply_local_lighting(command_buffer, per_frame_descriptor_set); //Compute local lighting and write it to the output image @@ -73,8 +79,8 @@ public: bool create(lava::image::ptr output_image, VkImageLayout output_layout, lava::descriptor::ptr per_frame_descriptor, Scene::Ptr scene, ShadowCache::Ptr shadow_cache = {}, IndirectCache::Ptr indirect_cache = {}); void destroy(); - // Apply local lighting based on the perspective defined by the per_frame_descriptor_set and write the results into the output image - void apply_local_lighting(VkCommandBuffer command_buffer, lava::index frame, VkDescriptorSet per_frame_descriptor_set); + // Apply lighting based on the perspective defined by the per_frame_descriptor_set and write the results into the output image + void apply_lighting(VkCommandBuffer command_buffer, lava::index frame, VkDescriptorSet per_frame_descriptor_set); // Images of the geometry buffer that can be used to create a render pass lava::image::ptr get_depth_image() const; diff --git a/src/utility/indirect_cache.cpp b/src/utility/indirect_cache.cpp index a5634a7d..a4faa39b 100644 --- a/src/utility/indirect_cache.cpp +++ b/src/utility/indirect_cache.cpp @@ -87,6 +87,11 @@ void IndirectCache::destroy() { lava::device_ptr device = this->scene->get_light_descriptor()->get_device(); + if (this->geometry_pipeline != nullptr) + { + this->geometry_pipeline->destroy(); + } + if (this->capture_pipeline != nullptr) { this->capture_pipeline->destroy(); @@ -102,6 +107,11 @@ void IndirectCache::destroy() this->propagation_pipeline->destroy(); } + if (this->geometry_pass != nullptr) + { + this->geometry_pass->destroy(); + } + if (this->capture_pass != nullptr) { this->capture_pass->destroy(); @@ -112,6 +122,11 @@ void IndirectCache::destroy() this->injection_pass->destroy(); } + if (this->geometry_layout != nullptr) + { + this->geometry_layout->destroy(); + } + if (this->capture_layout != nullptr) { this->capture_layout->destroy(); @@ -133,6 +148,12 @@ void IndirectCache::destroy() this->indirect_descriptor->destroy(); } + if (this->geometry_descriptor != nullptr) + { + this->geometry_descriptor->free(this->geometry_descriptor_set, this->descriptor_pool->get()); + this->geometry_descriptor->destroy(); + } + if (this->injection_descriptor != nullptr) { this->injection_descriptor->free(this->injection_descriptor_set, this->descriptor_pool->get()); @@ -172,25 +193,36 @@ void IndirectCache::destroy() } vkDestroySampler(device->get(), this->indirect_sampler, lava::memory::alloc()); + vkDestroySampler(device->get(), this->geometry_sampler, lava::memory::alloc()); vkDestroySampler(device->get(), this->injection_sampler, lava::memory::alloc()); - for (uint32_t index = 0; index < distribution_red_image.size(); index++) + for (uint32_t index = 0; index < this->distribution_red_image.size(); index++) { - vkDestroyImageView(device->get(), distribution_red_image_view[index], lava::memory::alloc()); - vkDestroyImageView(device->get(), distribution_green_image_view[index], lava::memory::alloc()); - vkDestroyImageView(device->get(), distribution_blue_image_view[index], lava::memory::alloc()); + vkDestroyImageView(device->get(), this->distribution_red_image_view[index], lava::memory::alloc()); + vkDestroyImageView(device->get(), this->distribution_green_image_view[index], lava::memory::alloc()); + vkDestroyImageView(device->get(), this->distribution_blue_image_view[index], lava::memory::alloc()); + + vkDestroyImageView(device->get(), this->distribution_red_image_array_view[index], lava::memory::alloc()); + vkDestroyImageView(device->get(), this->distribution_green_image_array_view[index], lava::memory::alloc()); + vkDestroyImageView(device->get(), this->distribution_blue_image_array_view[index], lava::memory::alloc()); + + vkDestroyImage(device->get(), this->distribution_red_image[index], lava::memory::alloc()); + vkDestroyImage(device->get(), this->distribution_green_image[index], lava::memory::alloc()); + vkDestroyImage(device->get(), this->distribution_blue_image[index], lava::memory::alloc()); - vkDestroyImageView(device->get(), distribution_red_image_array_view[index], lava::memory::alloc()); - vkDestroyImageView(device->get(), distribution_green_image_array_view[index], lava::memory::alloc()); - vkDestroyImageView(device->get(), distribution_blue_image_array_view[index], lava::memory::alloc()); + vmaFreeMemory(device->get_allocator()->get(), this->distribution_red_image_memory[index]); + vmaFreeMemory(device->get_allocator()->get(), this->distribution_green_image_memory[index]); + vmaFreeMemory(device->get_allocator()->get(), this->distribution_blue_image_memory[index]); + } + + for (uint32_t index = 0; index < this->distribution_geometry_image.size(); index++) + { + vkDestroyImageView(device->get(), this->distribution_geometry_image_view[index], lava::memory::alloc()); + vkDestroyImageView(device->get(), this->distribution_geometry_image_integer_view[index], lava::memory::alloc()); - vkDestroyImage(device->get(), distribution_red_image[index], lava::memory::alloc()); - vkDestroyImage(device->get(), distribution_green_image[index], lava::memory::alloc()); - vkDestroyImage(device->get(), distribution_blue_image[index], lava::memory::alloc()); + vkDestroyImage(device->get(), this->distribution_geometry_image[index], lava::memory::alloc()); - vmaFreeMemory(device->get_allocator()->get(), distribution_red_image_memory[index]); - vmaFreeMemory(device->get_allocator()->get(), distribution_green_image_memory[index]); - vmaFreeMemory(device->get_allocator()->get(), distribution_blue_image_memory[index]); + vmaFreeMemory(device->get_allocator()->get(), this->distribution_geometry_image_memory[index]); } } diff --git a/src/utility/indirect_cache.hpp b/src/utility/indirect_cache.hpp index 1b469cb2..1f5563eb 100644 --- a/src/utility/indirect_cache.hpp +++ b/src/utility/indirect_cache.hpp @@ -1,3 +1,36 @@ +/* + An indirect cache can be used in order to pre-compute indirect light transfer using light propagation volumes. + During the creation of the indirect cache it is possible to set the cell size that should be used for the propagation volumes with the help of the IndirectCacheSettings struct. + Before the indirect cache can be used, it is neccessary to call the function compute_indirect(...). + After that, the indirect cache can be used by ether adding it to a geometry buffer or by attaching the descriptor set of the indirect cache to a pipeline. + In order to use the indirect cache during forward shading, it is neccessary to bind the descriptor of the cache to the binding point that was specified in the fragment shader by the define INDIRECT_DESCRIPTOR_SET. + Example (Deferred): + + IndirectCache::Ptr indirect_cache = make_indirect_cache(); + indirect_cache->create(get_scene(), IndirectCacheSettings()); + + GeometryBuffer::Ptr geometry_buffer = make_geometry_buffer(); + geometry_buffer->create(output_image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, get_stereo_transform()->get_descriptor(), get_scene(), {}, indirect_cache); //Add the indirect cache to geometry buffer + + //During Rendering + indirect_cache->compute_indirect(command_buffer, frame); //Compute indirect lighting + + render_pass->process(command_buffer, 0); //Fill geometry buffer + geometry_buffer->apply_lighting(command_buffer, per_frame_descriptor_set); //Compute lighting with indirect lighting + + Example (Forward): + + IndirectCache::Ptr indirect_cache = make_indirect_cache(); + indirect_cache->create(get_scene(), IndirectCacheSettings()); + + pipeline_layout->add(indirect_cache->get_descriptor()); //Same binding point as INDIRECT_DESCRIPTOR_SET + + //During Rendering + indirect_cache->compute_indirect(command_buffer, frame); //Compute indirect lighting + + pipeline_layout->bind(command_buffer, indirect_cache->get_descriptor_set(), 42); //Same binding point as INDIRECT_DESCRIPTOR_SET +*/ + #pragma once #include <liblava/lava.hpp> #include <glm/glm.hpp> diff --git a/src/utility/shadow_cache.hpp b/src/utility/shadow_cache.hpp index 895bbe73..cab6af7e 100644 --- a/src/utility/shadow_cache.hpp +++ b/src/utility/shadow_cache.hpp @@ -16,7 +16,7 @@ shadow_cache->compute_shadow(command_buffer, frame); //Generate shadow maps render_pass->process(command_buffer, 0); //Fill geometry buffer - geometry_buffer->apply_local_lighting(command_buffer, per_frame_descriptor_set); //Compute local lighting with shadows + geometry_buffer->apply_lighting(command_buffer, per_frame_descriptor_set); //Compute lighting with shadows Example (Forward): @@ -40,7 +40,7 @@ struct ShadowCacheSettings { - uint32_t resolution = 1024; + uint32_t resolution = 2048; bool use_directional = true; bool use_spot = true; diff --git a/src/vr_application.cpp b/src/vr_application.cpp index 8ef1c8e3..f719dc9b 100644 --- a/src/vr_application.cpp +++ b/src/vr_application.cpp @@ -167,6 +167,16 @@ StereoTransform::Ptr VRApplication::get_stereo_transform() const return this->stereo_transform; } +ShadowCache::Ptr VRApplication::get_shadow_cache() const +{ + return this->shadow_cache; +} + +IndirectCache::Ptr VRApplication::get_indirect_cache() const +{ + return this->indirect_cache; +} + lava::device_ptr VRApplication::get_device() const { return this->app->device; @@ -419,6 +429,24 @@ bool VRApplication::on_create() return false; } + this->shadow_cache = make_shadow_cache(); + + if (!this->shadow_cache->create(this->scene, ShadowCacheSettings())) + { + lava::log()->error("Can't create shadow cache!"); + + return false; + } + + this->indirect_cache = make_indirect_cache(); + + if (!this->indirect_cache->create(this->scene, IndirectCacheSettings())) + { + lava::log()->error("Can't create indirect cache!"); + + return false; + } + this->frame_time = make_statistic("Frame Time", 128); return this->create_config(); @@ -434,6 +462,16 @@ void VRApplication::on_destroy() this->pass_timer->destroy(this->app->device); } + if (this->indirect_cache != nullptr) + { + this->indirect_cache->destroy(); + } + + if (this->shadow_cache != nullptr) + { + this->shadow_cache->destroy(); + } + if (this->stereo_transform != nullptr) { this->stereo_transform->destroy(); @@ -635,6 +673,14 @@ bool VRApplication::on_render(VkCommandBuffer command_buffer, lava::index frame) this->scene->write(frame); this->stereo_transform->write(frame); + if (!this->cache_filled) + { + this->shadow_cache->compute_shadow(command_buffer, frame); + this->indirect_cache->compute_indirect(command_buffer, frame); + + this->cache_filled = true; + } + this->begin_render(command_buffer, frame); StereoStrategy::Ptr strategy = this->get_stereo_strategy(); diff --git a/src/vr_application.hpp b/src/vr_application.hpp index a66273e3..5ff7ab62 100644 --- a/src/vr_application.hpp +++ b/src/vr_application.hpp @@ -18,6 +18,8 @@ #include "utility/pass_timer.hpp" #include "utility/stereo_transform.hpp" #include "utility/statistic.hpp" +#include "utility/shadow_cache.hpp" +#include "utility/indirect_cache.hpp" class VRApplication { @@ -41,6 +43,9 @@ public: FrameCapture::Ptr get_frame_capture() const; StereoTransform::Ptr get_stereo_transform() const; + ShadowCache::Ptr get_shadow_cache() const; + IndirectCache::Ptr get_indirect_cache() const; + lava::device_ptr get_device() const; lava::render_target::ptr get_target() const; @@ -83,6 +88,10 @@ private: FrameCapture::Ptr frame_capture; StereoTransform::Ptr stereo_transform; + ShadowCache::Ptr shadow_cache; + IndirectCache::Ptr indirect_cache; + bool cache_filled = false; + CommandParser command_parser; bool created = false; -- GitLab