1+ #include " ShadowMapping.hpp"
2+
3+ #include " VulkanRenderer.hpp"
4+
5+ namespace reactor
6+ {
7+
8+ ShadowMapping::ShadowMapping (VulkanRenderer& renderer, uint32_t resolution)
9+ : m_renderer(renderer), m_resolution(resolution), m_shadowMapView(VK_NULL_HANDLE),
10+ m_shadowMapSampler (VK_NULL_HANDLE)
11+ {
12+ createResources ();
13+ createDescriptors ();
14+ createPipeline ();
15+ }
16+
17+ ShadowMapping::~ShadowMapping ()
18+ {
19+ // if you own any Vulkan handles directly, clean them up here
20+
21+ auto device = m_renderer.device ();
22+ device.destroyImageView (m_shadowMapView);
23+ device.destroySampler (m_shadowMapSampler);
24+ }
25+
26+ void ShadowMapping::createResources ()
27+ {
28+ auto device = m_renderer.device ();
29+ auto & allocator = m_renderer.allocator ();
30+
31+ vk::ImageCreateInfo imageInfo = {};
32+ imageInfo.imageType = vk::ImageType::e2D;
33+ imageInfo.format = vk::Format::eD32Sfloat;
34+ imageInfo.extent = vk::Extent3D{m_resolution, m_resolution, 1 };
35+ imageInfo.mipLevels = 1 ;
36+ imageInfo.arrayLayers = 1 ;
37+ imageInfo.samples = vk::SampleCountFlagBits::e1 ;
38+ imageInfo.tiling = vk::ImageTiling::eOptimal;
39+ imageInfo.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment | vk::ImageUsageFlagBits::eSampled;
40+ imageInfo.sharingMode = vk::SharingMode::eExclusive;
41+ imageInfo.initialLayout = vk::ImageLayout::eUndefined;
42+
43+ VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_GPU_ONLY;
44+
45+ m_shadowMap = std::make_unique<Image>(allocator, imageInfo, memoryUsage);
46+
47+ // 2. Create image view
48+ vk::ImageViewCreateInfo viewInfo{};
49+ viewInfo.image = m_shadowMap->get ();
50+ viewInfo.viewType = vk::ImageViewType::e2D;
51+ viewInfo.format = vk::Format::eD32Sfloat;
52+ viewInfo.subresourceRange .aspectMask = vk::ImageAspectFlagBits::eDepth;
53+ viewInfo.subresourceRange .baseMipLevel = 0 ;
54+ viewInfo.subresourceRange .levelCount = 1 ;
55+ viewInfo.subresourceRange .baseArrayLayer = 0 ;
56+ viewInfo.subresourceRange .layerCount = 1 ;
57+
58+ m_shadowMapView = device.createImageView (viewInfo);
59+
60+ // 3. Create sampler
61+ vk::SamplerCreateInfo samplerInfo{};
62+ samplerInfo.magFilter = vk::Filter::eLinear;
63+ samplerInfo.minFilter = vk::Filter::eLinear;
64+ samplerInfo.mipmapMode = vk::SamplerMipmapMode::eNearest;
65+ samplerInfo.addressModeU = vk::SamplerAddressMode::eClampToBorder;
66+ samplerInfo.addressModeV = vk::SamplerAddressMode::eClampToBorder;
67+ samplerInfo.addressModeW = vk::SamplerAddressMode::eClampToBorder;
68+ samplerInfo.borderColor = vk::BorderColor::eFloatOpaqueWhite;
69+ samplerInfo.compareEnable = VK_TRUE;
70+ samplerInfo.compareOp = vk::CompareOp::eLessOrEqual;
71+
72+ m_shadowMapSampler = device.createSampler (samplerInfo);
73+
74+ const size_t frameCount = 2 ;
75+ m_mvpBuffer.clear ();
76+ m_mvpBuffer.reserve (frameCount);
77+ for (size_t i = 0 ; i < frameCount; ++i)
78+ {
79+ m_mvpBuffer.push_back (std::make_unique<Buffer>(m_renderer.allocator (), sizeof (glm::mat4), vk::BufferUsageFlagBits::eUniformBuffer, VMA_MEMORY_USAGE_AUTO, " MVP Buffer" ));
80+ }
81+ }
82+
83+ void ShadowMapping::createPipeline ()
84+ {
85+ spdlog::info (" Creating shadow mapping pipeline" );
86+
87+ auto device = m_renderer.device ();
88+
89+ std::vector<vk::DescriptorSetLayout> setLayouts;
90+ if (m_descriptors)
91+ {
92+ setLayouts.push_back (m_descriptors->getLayout ());
93+ }
94+
95+ Pipeline::Builder builder (device);
96+
97+ builder
98+ .setVertexShader (" ../resources/shaders/triangle.vert.spv" )
99+ // No fragment shader, we only want depth output
100+ .setVertexInputFromVertex ()
101+ .setDepthAttachment (vk::Format::eD32Sfloat, true ) // depth test and write enabled
102+ .setDescriptorSetLayouts (setLayouts)
103+ .setMultisample (4 )
104+ .setFrontFace (vk::FrontFace::eClockwise) // Match main geometry pipeline
105+ .addPushContantRange (vk::ShaderStageFlagBits::eVertex, 0 , sizeof (glm::mat4));
106+
107+ m_depthPassPipeline = builder.build ();
108+ }
109+
110+ void ShadowMapping::createDescriptors ()
111+ {
112+ spdlog::info (" Creating shadow mapping descriptors" );
113+ vk::Device device = m_renderer.device ();
114+ size_t framesInFlight = 2 ;
115+
116+ // Descriptor set bindings: UBO for light's MVP
117+ std::vector<vk::DescriptorSetLayoutBinding> bindings = {
118+ { 0 , vk::DescriptorType::eUniformBuffer, 1 , vk::ShaderStageFlagBits::eVertex }
119+ // Add more if you want—for example for a sampler or shadow map
120+ };
121+
122+ // Use your DescriptorSet abstraction to handle layout & Vulkan allocation
123+ m_descriptors = std::make_unique<DescriptorSet>(device, m_renderer.descriptorPool (), framesInFlight, bindings);
124+
125+ // Now update each descriptor set with the corresponding per-frame UBO
126+ for (size_t i = 0 ; i < framesInFlight; ++i)
127+ {
128+ vk::DescriptorBufferInfo uboInfo{};
129+ uboInfo.buffer = m_mvpBuffer[i]->getHandle ();
130+ uboInfo.offset = 0 ;
131+ uboInfo.range = sizeof (glm::mat4);
132+
133+ vk::WriteDescriptorSet writes{};
134+ writes.dstSet = m_descriptors->get (i);
135+ writes.dstBinding = 0 ;
136+ writes.dstArrayElement = 0 ;
137+ writes.descriptorType = vk::DescriptorType::eUniformBuffer;
138+ writes.descriptorCount = 1 ;
139+ writes.pBufferInfo = &uboInfo;
140+
141+ m_descriptors->updateSet ({writes});
142+ }
143+
144+ }
145+
146+ } // namespace reactor
0 commit comments