diff --git a/res/dpr/utility/indirect_library.glsl b/res/dpr/utility/indirect_library.glsl index 85f3b14bbeaae476eab09fb7b85da37c9c7cb378..6d439a61dfa11d8e83aa0993b4606a348d70d514 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 62cb6356d50c35477e1741b89377d9d9f616184b..8ed550f60eaf449524420c47eff444b64486cc93 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 8b474bc7e9ab23af6ab284d6ac766c0368563ab1..89eb1e0b3f25333e134e7b5c442083e85640c0c9 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 6b9635ecb57a373fb0e8d68e95313a541b9f97ae..c96b6fbe4cf2b13095daf0b2ccfba7e892445a68 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 afb9be602191bbe55ecabf370bbbba366c2d679e..aa2b1d2583499b93e8c773c63db83cf944623e25 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 c597d223efa85804690c0460c032815b0f0d0aba..81e53c6194532f1cee97699903154bcdc30cee71 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 1bad6edf476267abf96b8a977405467fe6336737..d891225c0fbc349a36efabe708bb063a0c312e42 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 df8c17dc57d6a757897622eebfceaa10e31c9fff..0c5c48c22d5014f138ad599a064625da822180f5 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 5b00e4b1008ce423d517ce5f9c69e1fb7faf61dc..41b2e4ed9fe767f841bd1fc9b91dfb6838f8b800 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 8d43752f27a79ab12063b84fd97856632e5e399f..96eff477a852419d29bb6767bf109d93d7698877 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 2482ef4d192740d799de857c43bde4c06bfc45df..27ff69206ced121be6a6f4d0eadbfdc4d893bfb7 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 735e3bd86316c5516b02a08318fa9da4e3fe91da..a8173f7b2396ac5f76b5598cd376dff2d4c78b43 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 a5634a7d118296cfb0b0498179680e20a9881785..a4faa39bedd29ffee48492e66a91e8ea89652099 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 1b469cb2546d0a693522d95676283e4c38f980a0..1f5563eb04e9fa4f5f50d9f0b32b2dc2c2a9724c 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 895bbe73fa6e2bbb2220f745b90f156e0ef758d2..cab6af7e537731e0c99a7037244e07a29935cfce 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 8ef1c8e3b9ca58a905dca1f9a08bfe775fb481d5..f719dc9be530dc91a264bc5f0e74b8d970219666 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 a66273e357a903703b8312fb9be4c788ed9fd7c1..5ff7ab6275800a475f67cd4a956a6e8950cebd46 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;