| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "lib/escher/renderer/shadow_map_renderer.h" |
| |
| #include "lib/escher/impl/command_buffer.h" |
| #include "lib/escher/impl/image_cache.h" |
| #include "lib/escher/impl/model_data.h" |
| #include "lib/escher/impl/model_display_list.h" |
| #include "lib/escher/impl/model_renderer.h" |
| #include "lib/escher/impl/model_shadow_map_pass.h" |
| #include "lib/escher/impl/vulkan_utils.h" |
| #include "lib/escher/math/rotations.h" |
| #include "lib/escher/scene/stage.h" |
| #include "lib/escher/util/image_utils.h" |
| #include "lib/escher/vk/framebuffer.h" |
| #include "lib/escher/vk/image.h" |
| |
| namespace escher { |
| |
| ShadowMapRendererPtr ShadowMapRenderer::New( |
| EscherWeakPtr escher, const impl::ModelDataPtr& model_data, |
| const impl::ModelRendererPtr& model_renderer) { |
| auto* resource_recycler = escher->resource_recycler(); |
| constexpr vk::Format kShadowMapFormat = vk::Format::eR16Unorm; |
| vk::Format depth_format = ESCHER_CHECKED_VK_RESULT( |
| impl::GetSupportedDepthStencilFormat(escher->vk_physical_device())); |
| return fxl::MakeRefCounted<ShadowMapRenderer>( |
| std::move(escher), kShadowMapFormat, depth_format, model_data, |
| model_renderer, |
| fxl::MakeRefCounted<impl::ModelShadowMapPass>( |
| resource_recycler, model_data, kShadowMapFormat, depth_format, |
| /* sample_count= */ 1)); |
| } |
| |
| ShadowMapRenderer::ShadowMapRenderer( |
| EscherWeakPtr weak_escher, vk::Format shadow_map_format, |
| vk::Format depth_format, const impl::ModelDataPtr& model_data, |
| const impl::ModelRendererPtr& model_renderer, |
| const impl::ModelRenderPassPtr& model_render_pass) |
| : Renderer(std::move(weak_escher)), |
| shadow_map_format_(shadow_map_format), |
| depth_format_(depth_format), |
| model_data_(model_data), |
| model_renderer_(model_renderer), |
| shadow_map_pass_(model_render_pass), |
| clear_values_( |
| {vk::ClearColorValue(std::array<float, 4>{{0.f, 0.f, 0.f, 1.f}}), |
| vk::ClearDepthStencilValue(1.f, 0.f)}) {} |
| |
| ShadowMapRenderer::~ShadowMapRenderer() { escher()->Cleanup(); } |
| |
| ShadowMapPtr ShadowMapRenderer::GenerateDirectionalShadowMap( |
| const FramePtr& frame, const Stage& stage, const Model& model, |
| const glm::vec3& direction, const glm::vec3& light_color) { |
| auto command_buffer = frame->command_buffer(); |
| auto camera = |
| Camera::NewForDirectionalShadowMap(stage.viewing_volume(), direction); |
| Stage shadow_stage; |
| ComputeShadowStageFromSceneStage(stage, shadow_stage); |
| |
| auto width = static_cast<uint32_t>(shadow_stage.width()); |
| auto height = static_cast<uint32_t>(shadow_stage.height()); |
| auto color_image = GetTransitionedColorImage(command_buffer, width, height); |
| auto depth_image = GetTransitionedDepthImage(command_buffer, width, height); |
| DrawShadowPass(command_buffer, shadow_stage, model, camera, color_image, |
| depth_image); |
| frame->AddTimestamp("generated shadow map"); |
| return SubmitPartialFrameAndBuildShadowMap<ShadowMap>( |
| frame, camera, color_image, light_color); |
| } |
| |
| ImagePtr ShadowMapRenderer::GetTransitionedColorImage( |
| impl::CommandBuffer* command_buffer, uint32_t width, uint32_t height) { |
| ImageInfo info; |
| info.format = shadow_map_format_; |
| info.width = width; |
| info.height = height; |
| info.sample_count = 1; |
| info.usage = vk::ImageUsageFlagBits::eColorAttachment | |
| vk::ImageUsageFlagBits::eSampled | |
| vk::ImageUsageFlagBits::eTransferSrc | |
| vk::ImageUsageFlagBits::eStorage; |
| auto color_image = escher()->image_cache()->NewImage(info); |
| command_buffer->TransitionImageLayout( |
| color_image, vk::ImageLayout::eUndefined, |
| vk::ImageLayout::eColorAttachmentOptimal); |
| return color_image; |
| } |
| |
| ImagePtr ShadowMapRenderer::GetTransitionedDepthImage( |
| impl::CommandBuffer* command_buffer, uint32_t width, uint32_t height) { |
| auto depth_image = |
| image_utils::NewDepthImage(escher()->image_cache(), depth_format_, width, |
| height, vk::ImageUsageFlags()); |
| command_buffer->TransitionImageLayout( |
| depth_image, vk::ImageLayout::eUndefined, |
| vk::ImageLayout::eDepthStencilAttachmentOptimal); |
| return depth_image; |
| } |
| |
| void ShadowMapRenderer::DrawShadowPass(impl::CommandBuffer* command_buffer, |
| const Stage& shadow_stage, |
| const Model& model, const Camera& camera, |
| ImagePtr& color_image, |
| ImagePtr& depth_image) { |
| auto fb = fxl::MakeRefCounted<Framebuffer>(escher(), color_image, depth_image, |
| shadow_map_pass_->vk()); |
| auto display_list = model_renderer_->CreateDisplayList( |
| shadow_stage, model, camera, shadow_map_pass_, |
| impl::ModelDisplayListFlag::kNull, 1.f, TexturePtr(), mat4(1.f), |
| vec3(0.f), vec3(0.f), command_buffer); |
| |
| command_buffer->KeepAlive(fb); |
| command_buffer->KeepAlive(display_list); |
| |
| command_buffer->BeginRenderPass( |
| shadow_map_pass_, fb, clear_values_, |
| camera.viewport().vk_rect_2d(fb->width(), fb->height())); |
| model_renderer_->Draw(shadow_stage, display_list, command_buffer, |
| camera.viewport()); |
| command_buffer->EndRenderPass(); |
| } |
| |
| void ShadowMapRenderer::ComputeShadowStageFromSceneStage( |
| const Stage& scene_stage, Stage& shadow_stage) { |
| uint32_t shadow_size = static_cast<uint32_t>( |
| .75f * std::max(scene_stage.width(), scene_stage.height())); |
| shadow_stage.set_viewing_volume(escher::ViewingVolume( |
| shadow_size, shadow_size, scene_stage.viewing_volume().top(), |
| scene_stage.viewing_volume().bottom())); |
| shadow_stage.set_key_light(scene_stage.key_light()); |
| shadow_stage.set_fill_light(scene_stage.fill_light()); |
| } |
| |
| } // namespace escher |