- 场景剔除从 [主|阴影] 两视图扩展为 [主|级联0|级联1|级联2] 四视图: 每级联只画自己盒内的 batch,消除原先 3× 全量阴影 draw 的浪费 - 实例数组拼接为四段,batch.first 加段基址保持段内连续; ViewScratch 分桶收集复用容量,稳态零堆分配 - ComputeCascades 沿光方向扩展级联深度范围(pad=30)——切片盒外 caster(高树/城墙)投影进级联的影子不会被剔除裁掉,per-cascade 剔除正确性的前提;只扩 z 不缩 XY,分辨率不受影响 - 遥测 shadow 计数 = 各级联求和 - SunTemple 1056 mesh 全量加载,validation 零警告
113 lines
5.0 KiB
C++
113 lines
5.0 KiB
C++
//
|
||
// Created by atdunbg on 2026/9/23.
|
||
//
|
||
|
||
#include <Engine/Renderer/Passes/ShadowPass.h>
|
||
#include <Engine/Renderer/Vertex.h>
|
||
#include <Engine/Renderer/Mesh.h>
|
||
|
||
#include <array>
|
||
|
||
namespace Engine::Passes
|
||
{
|
||
void ShadowPass::Register(RG::RenderGraph& rg)
|
||
{
|
||
// 所有渲染体都写入每个级联,不做实体级开关——castShadow 应由
|
||
// 材质/实体数据驱动剔除,而非 pass 逻辑特判。
|
||
// (每级联独立剔除是后续优化点:shadowView 细分为 per-cascade 列表)
|
||
rg.AddPass("Shadow", [this](RG::RenderGraphContext& ctx) {
|
||
const vk::CommandBuffer cmd = ctx.cmd;
|
||
|
||
for (u32 c = 0; c < kMaxCascades; ++c) {
|
||
vk::RenderingAttachmentInfo depthAttachment;
|
||
depthAttachment.setImageView(ctx.View(m_ShadowMaps[c]))
|
||
.setImageLayout(vk::ImageLayout::eDepthAttachmentOptimal)
|
||
.setLoadOp(vk::AttachmentLoadOp::eClear)
|
||
.setStoreOp(vk::AttachmentStoreOp::eStore)
|
||
.setClearValue(vk::ClearValue(
|
||
vk::ClearDepthStencilValue(1.0f, 0)));
|
||
|
||
vk::RenderingInfo renderingInfo;
|
||
renderingInfo.setRenderArea({{0, 0}, {kCascadeRes, kCascadeRes}})
|
||
.setLayerCount(1)
|
||
.setPDepthAttachment(&depthAttachment);
|
||
|
||
cmd.beginRendering(renderingInfo);
|
||
|
||
std::array<vk::ShaderStageFlagBits, 2> stages = {
|
||
vk::ShaderStageFlagBits::eVertex,
|
||
vk::ShaderStageFlagBits::eFragment
|
||
};
|
||
std::array<vk::ShaderEXT, 2> shaders = {m_Gpu.shadowVert, m_Gpu.shadowFrag};
|
||
cmd.bindShadersEXT(stages, shaders);
|
||
|
||
// ---- 动态状态(depth-only)----
|
||
cmd.setRasterizerDiscardEnable(VK_FALSE);
|
||
|
||
cmd.setDepthTestEnable(VK_TRUE);
|
||
cmd.setDepthWriteEnable(VK_TRUE);
|
||
cmd.setDepthCompareOp(vk::CompareOp::eLess);
|
||
cmd.setDepthBoundsTestEnable(VK_FALSE);
|
||
|
||
cmd.setStencilTestEnable(VK_FALSE);
|
||
// 深度 bias 压平 shadow acne(NDC 量级)
|
||
cmd.setDepthBiasEnable(VK_TRUE);
|
||
cmd.setDepthBias(0.0025f, 0.0f, 0.003f);
|
||
cmd.setPolygonModeEXT(vk::PolygonMode::eFill);
|
||
cmd.setCullMode(vk::CullModeFlagBits::eNone);
|
||
cmd.setFrontFace(vk::FrontFace::eCounterClockwise);
|
||
cmd.setPrimitiveTopology(vk::PrimitiveTopology::eTriangleList);
|
||
cmd.setPrimitiveRestartEnable(VK_FALSE);
|
||
|
||
auto binding = Vertex::GetBindingDescription();
|
||
auto attributes = Vertex::GetAttributeDescriptions();
|
||
cmd.setVertexInputEXT(binding, attributes);
|
||
|
||
cmd.setRasterizationSamplesEXT(vk::SampleCountFlagBits::e1);
|
||
vk::SampleMask sampleMask = 0xFFFFFFFF;
|
||
cmd.setSampleMaskEXT(vk::SampleCountFlagBits::e1, sampleMask);
|
||
cmd.setAlphaToCoverageEnableEXT(VK_FALSE);
|
||
cmd.setAlphaToOneEnableEXT(VK_FALSE);
|
||
|
||
vk::Viewport viewport(0.0f, 0.0f,
|
||
static_cast<float>(kCascadeRes),
|
||
static_cast<float>(kCascadeRes),
|
||
0.0f, 1.0f);
|
||
cmd.setViewportWithCount(viewport);
|
||
|
||
vk::Rect2D scissor({0, 0}, {kCascadeRes, kCascadeRes});
|
||
cmd.setScissorWithCount(scissor);
|
||
|
||
// ---- 绘制:GPUDriven——与 Forward 共用实例数据,但用
|
||
// 光源视锥剔除后的 batch(相机外实体仍投影子)----
|
||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
|
||
m_Gpu.shadowLayout, 0,
|
||
m_Gpu.uboSets[ctx.frame.frameSlot], {});
|
||
|
||
// stage 必须覆盖 layout range 声明的全部 stage(VUID-01796)
|
||
// 每级联 push 各自的光空间 VP
|
||
cmd.pushConstants(m_Gpu.shadowLayout,
|
||
vk::ShaderStageFlagBits::eVertex |
|
||
vk::ShaderStageFlagBits::eFragment,
|
||
0, sizeof(glm::mat4),
|
||
&m_Frame.ubo.lightSpace[c]);
|
||
|
||
for (const auto& batch : m_Frame.shadowCascades[c].batches) {
|
||
batch.mesh->Draw(cmd, batch.count, batch.first);
|
||
}
|
||
|
||
cmd.endRendering();
|
||
}
|
||
})
|
||
.Write(m_ShadowMaps[0], RG::ResourceUse::DepthAttachment)
|
||
.Write(m_ShadowMaps[1], RG::ResourceUse::DepthAttachment)
|
||
.Write(m_ShadowMaps[2], RG::ResourceUse::DepthAttachment);
|
||
}
|
||
|
||
void ShadowPass::OnTargetsRebuilt(RG::RenderGraph& rg)
|
||
{
|
||
m_Gpu.BindShadowMaps(rg, m_ShadowMaps);
|
||
}
|
||
|
||
} // namespace Engine::Passes
|