ADD: CSM half-working

This commit is contained in:
2025-10-12 00:20:12 +09:00
parent b2fdcf5310
commit 26b7db9030
16 changed files with 297 additions and 105 deletions

View File

@@ -6,3 +6,14 @@ inline constexpr bool kUseValidationLayers = false;
#else
inline constexpr bool kUseValidationLayers = true;
#endif
// Shadow mapping configuration
inline constexpr int kShadowCascadeCount = 4;
// Maximum shadow distance for CSM in view-space units
inline constexpr float kShadowCSMFar = 50.0f;
// Shadow map resolution used for stabilization (texel snapping). Must match actual image size.
inline constexpr float kShadowMapResolution = 2048.0f;
// Extra XY expansion for cascade footprint (safety against FOV/aspect changes)
inline constexpr float kShadowCascadeRadiusScale = 1.15f;
// Additive XY margin in world units (light-space) beyond scaled radius
inline constexpr float kShadowCascadeRadiusMargin = 10.0f;

View File

@@ -1,10 +1,10 @@
#include <core/vk_descriptors.h>
void DescriptorLayoutBuilder::add_binding(uint32_t binding, VkDescriptorType type)
void DescriptorLayoutBuilder::add_binding(uint32_t binding, VkDescriptorType type, uint32_t count)
{
VkDescriptorSetLayoutBinding newbind{};
newbind.binding = binding;
newbind.descriptorCount = 1;
newbind.descriptorCount = count;
newbind.descriptorType = type;
bindings.push_back(newbind);

View File

@@ -7,7 +7,7 @@ struct DescriptorLayoutBuilder
{
std::vector<VkDescriptorSetLayoutBinding> bindings;
void add_binding(uint32_t binding, VkDescriptorType type);
void add_binding(uint32_t binding, VkDescriptorType type, uint32_t count = 1);
void clear();

View File

@@ -12,6 +12,8 @@
#include <chrono>
#include <thread>
#include <span>
#include <array>
#include "render/vk_pipelines.h"
#include <iostream>
@@ -31,6 +33,7 @@
#include "vk_resource.h"
#include "engine_context.h"
#include "core/vk_pipeline_manager.h"
#include "core/config.h"
VulkanEngine *loadedEngine = nullptr;
@@ -314,9 +317,14 @@ void VulkanEngine::draw()
RGImageHandle hGBufferAlbedo = _renderGraph->import_gbuffer_albedo();
RGImageHandle hSwapchain = _renderGraph->import_swapchain_image(swapchainImageIndex);
// Create a transient shadow depth target (fixed resolution for now)
// Create transient depth targets for cascaded shadow maps
const VkExtent2D shadowExtent{2048, 2048};
RGImageHandle hShadow = _renderGraph->create_depth_image("shadow.depth", shadowExtent, VK_FORMAT_D32_SFLOAT);
std::array<RGImageHandle, kShadowCascadeCount> hShadowCascades{};
for (int i = 0; i < kShadowCascadeCount; ++i)
{
std::string name = std::string("shadow.cascade.") + std::to_string(i);
hShadowCascades[i] = _renderGraph->create_depth_image(name.c_str(), shadowExtent, VK_FORMAT_D32_SFLOAT);
}
_resourceManager->register_upload_pass(*_renderGraph, get_current_frame());
@@ -331,7 +339,7 @@ void VulkanEngine::draw()
}
if (auto *shadow = _renderPassManager->getPass<ShadowPass>())
{
shadow->register_graph(_renderGraph.get(), hShadow, shadowExtent);
shadow->register_graph(_renderGraph.get(), std::span<RGImageHandle>(hShadowCascades.data(), hShadowCascades.size()), shadowExtent);
}
if (auto *geometry = _renderPassManager->getPass<GeometryPass>())
{
@@ -339,7 +347,8 @@ void VulkanEngine::draw()
}
if (auto *lighting = _renderPassManager->getPass<LightingPass>())
{
lighting->register_graph(_renderGraph.get(), hDraw, hGBufferPosition, hGBufferNormal, hGBufferAlbedo, hShadow);
lighting->register_graph(_renderGraph.get(), hDraw, hGBufferPosition, hGBufferNormal, hGBufferAlbedo,
std::span<RGImageHandle>(hShadowCascades.data(), hShadowCascades.size()));
}
if (auto *transparent = _renderPassManager->getPass<TransparentPass>())
{

View File

@@ -28,6 +28,15 @@ void SamplerManager::init(DeviceManager *deviceManager)
sampl.magFilter = VK_FILTER_LINEAR;
sampl.minFilter = VK_FILTER_LINEAR;
vkCreateSampler(_deviceManager->device(), &sampl, nullptr, &_defaultSamplerLinear);
// Shadow linear clamp sampler (border=white)
VkSamplerCreateInfo sh = sampl;
sh.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
sh.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
sh.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
sh.compareEnable = VK_FALSE; // manual PCF
sh.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
vkCreateSampler(_deviceManager->device(), &sh, nullptr, &_shadowLinearClamp);
}
void SamplerManager::cleanup()
@@ -44,4 +53,9 @@ void SamplerManager::cleanup()
vkDestroySampler(_deviceManager->device(), _defaultSamplerLinear, nullptr);
_defaultSamplerLinear = VK_NULL_HANDLE;
}
if (_shadowLinearClamp)
{
vkDestroySampler(_deviceManager->device(), _shadowLinearClamp, nullptr);
_shadowLinearClamp = VK_NULL_HANDLE;
}
}

View File

@@ -13,10 +13,11 @@ public:
VkSampler defaultLinear() const { return _defaultSamplerLinear; }
VkSampler defaultNearest() const { return _defaultSamplerNearest; }
VkSampler shadowLinearClamp() const { return _shadowLinearClamp; }
private:
DeviceManager *_deviceManager = nullptr;
VkSampler _defaultSamplerLinear = VK_NULL_HANDLE;
VkSampler _defaultSamplerNearest = VK_NULL_HANDLE;
VkSampler _shadowLinearClamp = VK_NULL_HANDLE;
};

View File

@@ -71,10 +71,14 @@ struct GPUSceneData {
glm::mat4 view;
glm::mat4 proj;
glm::mat4 viewproj;
glm::mat4 lightViewProj;
glm::mat4 lightViewProj; // legacy single-shadow; kept for transition
glm::vec4 ambientColor;
glm::vec4 sunlightDirection; // w for sun power
glm::vec4 sunlightColor;
// CSM data (unused by current shaders until wired)
glm::mat4 lightViewProjCascades[4];
glm::vec4 cascadeSplitsView;
};
enum class MaterialPass :uint8_t {