fix: 阴影采样器 CompareOp 反转(诊断残留 eGreater)+ 移除截图调试设施
根因:shadow sampler 停留在诊断期的 eGreater——比较语义全反, 全场 shade 被压到 0.3 变暗,唯独真影区 lit=1 反而全亮, 即"影子比环境亮、像光源"的现象。修回 eLess 后影子正常。 顺带清理:第 60 帧截图管线(HDRColor/ShadowMap0 → BMP)、 CPU 投影诊断日志、GetCaptureTarget 及 TRANSFER_SRC extraUsage。
This commit is contained in:
@@ -212,13 +212,6 @@ namespace Engine::RG {
|
|||||||
// 注意:物理镜像按槽位各一份,槽位变化/重编译后必须重新获取。
|
// 注意:物理镜像按槽位各一份,槽位变化/重编译后必须重新获取。
|
||||||
vk::ImageView GetPhysicalView(TextureHandle h, u32 frameSlot) const;
|
vk::ImageView GetPhysicalView(TextureHandle h, u32 frameSlot) const;
|
||||||
|
|
||||||
// 调试/截图:取物理 image + 静息布局(帧尾 barrier 恢复用)。
|
|
||||||
// imported 资源返回 false(无物理实例)
|
|
||||||
bool GetCaptureTarget(TextureHandle h, u32 frameSlot,
|
|
||||||
vk::Image& outImage, vk::Extent2D& outExtent,
|
|
||||||
vk::Format& outFormat,
|
|
||||||
vk::ImageLayout& outResting) const;
|
|
||||||
|
|
||||||
// 帧历史槽位 = 上一帧使用的槽位:(slot - 1 + F) mod F
|
// 帧历史槽位 = 上一帧使用的槽位:(slot - 1 + F) mod F
|
||||||
u32 HistorySlot(u32 frameSlot) const {
|
u32 HistorySlot(u32 frameSlot) const {
|
||||||
return (frameSlot + m_FramesInFlight - 1) % m_FramesInFlight;
|
return (frameSlot + m_FramesInFlight - 1) % m_FramesInFlight;
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ namespace Engine {
|
|||||||
void BuildGraph(); // 声明 RG 资源 + 注册 pass 对象
|
void BuildGraph(); // 声明 RG 资源 + 注册 pass 对象
|
||||||
void HandleResize();
|
void HandleResize();
|
||||||
void ReadGpuTimes(u32 frameSlot);
|
void ReadGpuTimes(u32 frameSlot);
|
||||||
void CaptureFrame(); // 调试截图(一次性,写 capture.bmp)
|
|
||||||
|
|
||||||
Window& m_Window;
|
Window& m_Window;
|
||||||
|
|
||||||
@@ -155,11 +154,6 @@ namespace Engine {
|
|||||||
|
|
||||||
vk::Extent2D m_Extent{};
|
vk::Extent2D m_Extent{};
|
||||||
u32 m_CurrentFrame = 0;
|
u32 m_CurrentFrame = 0;
|
||||||
|
|
||||||
// 调试截图(一次性):第 60 帧把 TAAColor(HDR)落成 capture.bmp
|
|
||||||
u32 m_FrameCounter = 0;
|
|
||||||
bool m_Captured = false;
|
|
||||||
MemoryAllocator::Allocation m_CaptureAlloc{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Engine
|
} // namespace Engine
|
||||||
|
|||||||
@@ -694,24 +694,6 @@ namespace Engine::RG {
|
|||||||
return entry.physical[frameSlot]->view;
|
return entry.physical[frameSlot]->view;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderGraph::GetCaptureTarget(TextureHandle h, u32 frameSlot,
|
|
||||||
vk::Image& outImage, vk::Extent2D& outExtent,
|
|
||||||
vk::Format& outFormat,
|
|
||||||
vk::ImageLayout& outResting) const
|
|
||||||
{
|
|
||||||
const auto& entry = GetEntry(h);
|
|
||||||
if (entry.imported || frameSlot >= entry.physical.size() ||
|
|
||||||
!entry.physical[frameSlot]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto& phys = *entry.physical[frameSlot];
|
|
||||||
outImage = phys.image;
|
|
||||||
outExtent = phys.extent;
|
|
||||||
outFormat = phys.format;
|
|
||||||
outResting = entry.restingLayout;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderGraph::SetQueryPool(vk::QueryPool pool, u32 queriesPerFrame)
|
void RenderGraph::SetQueryPool(vk::QueryPool pool, u32 queriesPerFrame)
|
||||||
{
|
{
|
||||||
m_QueryPool = pool;
|
m_QueryPool = pool;
|
||||||
|
|||||||
@@ -116,7 +116,8 @@ namespace Engine::Passes
|
|||||||
.setBorderColor(vk::BorderColor::eFloatOpaqueWhite)
|
.setBorderColor(vk::BorderColor::eFloatOpaqueWhite)
|
||||||
.setUnnormalizedCoordinates(VK_FALSE)
|
.setUnnormalizedCoordinates(VK_FALSE)
|
||||||
.setCompareEnable(VK_TRUE)
|
.setCompareEnable(VK_TRUE)
|
||||||
.setCompareOp(vk::CompareOp::eGreater); // 【诊断】方向对照
|
// ref < stored → lit=1:片元比遮挡物近即被照亮
|
||||||
|
.setCompareOp(vk::CompareOp::eLess);
|
||||||
shadowSampler = device.GetDevice().createSampler(shadowSamplerInfo);
|
shadowSampler = device.GetDevice().createSampler(shadowSamplerInfo);
|
||||||
|
|
||||||
// per-slot 描述符分配 + Set0 绑定(buffer 句柄全程稳定,不用重绑)
|
// per-slot 描述符分配 + Set0 绑定(buffer 句柄全程稳定,不用重绑)
|
||||||
|
|||||||
@@ -42,83 +42,9 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <bit>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
namespace Engine
|
namespace Engine
|
||||||
{
|
{
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// fp16 → f32(截图用,规范路径足够)
|
|
||||||
f32 HalfToFloat(u16 h)
|
|
||||||
{
|
|
||||||
const u32 sign = (h & 0x8000u) << 16u;
|
|
||||||
const u32 exp = (h >> 10u) & 0x1Fu;
|
|
||||||
const u32 man = h & 0x3FFu;
|
|
||||||
u32 bits;
|
|
||||||
if (exp == 0) {
|
|
||||||
if (man == 0) return std::bit_cast<f32>(sign);
|
|
||||||
u32 e = 127 - 15 + 1;
|
|
||||||
u32 m = man;
|
|
||||||
while (!(m & 0x400u)) { m <<= 1u; --e; }
|
|
||||||
bits = sign | (e << 23u) | ((m & 0x3FFu) << 13u);
|
|
||||||
} else if (exp == 31) {
|
|
||||||
bits = sign | 0x7F800000u | (man << 13u);
|
|
||||||
} else {
|
|
||||||
bits = sign | ((exp - 15u + 127u) << 23u) | (man << 13u);
|
|
||||||
}
|
|
||||||
return std::bit_cast<f32>(bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RGBA16F 线性数据 → 24bpp BMP(行倒序;depthMode 读 f32 深度)
|
|
||||||
void WriteHdrBMP(const std::string& path, const void* data,
|
|
||||||
u32 w, u32 h, bool depthMode = false)
|
|
||||||
{
|
|
||||||
const auto* src = static_cast<const u16*>(data);
|
|
||||||
const u32 rowBytes = w * 3u;
|
|
||||||
const u32 pad = (4u - rowBytes % 4u) % 4u;
|
|
||||||
const u32 stride = rowBytes + pad;
|
|
||||||
const u32 size = 54u + stride * h;
|
|
||||||
|
|
||||||
std::vector<u8> bmp(size, 0);
|
|
||||||
auto put = [&bmp](u32 off, u32 v, u32 n) {
|
|
||||||
for (u32 i = 0; i < n; ++i)
|
|
||||||
bmp[off + i] = static_cast<u8>((v >> (8u * i)) & 0xFFu);
|
|
||||||
};
|
|
||||||
bmp[0] = 'B'; bmp[1] = 'M';
|
|
||||||
put(2, size, 4); put(10, 54, 4); put(14, 40, 4);
|
|
||||||
put(18, w, 4); put(22, h, 4); put(26, 1, 2); put(28, 24, 2);
|
|
||||||
put(34, stride * h, 4);
|
|
||||||
|
|
||||||
for (u32 y = 0; y < h; ++y) {
|
|
||||||
const u32 dstRow = h - 1 - y; // BMP 底行在前
|
|
||||||
for (u32 x = 0; x < w; ++x) {
|
|
||||||
const u16* px = src + (static_cast<size_t>(y) * w + x) * 4;
|
|
||||||
const u32 off = 54u + dstRow * stride + x * 3u;
|
|
||||||
for (u32 c = 0; c < 3; ++c) {
|
|
||||||
f32 v;
|
|
||||||
if (depthMode) {
|
|
||||||
// D32 buffer:f32 深度,反相显示(近=白)
|
|
||||||
v = 1.0f - reinterpret_cast<const f32*>(
|
|
||||||
data)[static_cast<size_t>(y) * w + x];
|
|
||||||
} else {
|
|
||||||
v = HalfToFloat(px[c]) * 0.6f; // 匹配默认 exposure
|
|
||||||
// ACES 近似(与 TonemapPass 同族),还原屏幕观感
|
|
||||||
v = (v * (2.51f * v + 0.03f)) /
|
|
||||||
(v * (2.43f * v + 0.59f) + 0.14f);
|
|
||||||
v = glm::pow(glm::clamp(v, 0.0f, 1.0f),
|
|
||||||
1.0f / 2.2f);
|
|
||||||
}
|
|
||||||
bmp[off + c] = static_cast<u8>(v * 255.0f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ofstream file(path, std::ios::binary);
|
|
||||||
file.write(reinterpret_cast<const char*>(bmp.data()),
|
|
||||||
static_cast<std::streamsize>(bmp.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Renderer::Renderer(Window& window)
|
Renderer::Renderer(Window& window)
|
||||||
: m_Window(window)
|
: m_Window(window)
|
||||||
{
|
{
|
||||||
@@ -178,19 +104,15 @@ namespace Engine
|
|||||||
m_SceneGpu->textureSetLayout);
|
m_SceneGpu->textureSetLayout);
|
||||||
|
|
||||||
// 8. RenderGraph:资源声明 + pass 注册 + 首次编译
|
// 8. RenderGraph:资源声明 + pass 注册 + 首次编译
|
||||||
ENGINE_INFO("[diag] BuildGraph begin");
|
|
||||||
m_PostParams = CreateScope<Passes::PostProcessParams>();
|
m_PostParams = CreateScope<Passes::PostProcessParams>();
|
||||||
BuildGraph();
|
BuildGraph();
|
||||||
ENGINE_INFO("[diag] BuildGraph done");
|
|
||||||
|
|
||||||
// 首次编译后物理镜像就位:各 pass 绑定自己的输入描述符
|
// 首次编译后物理镜像就位:各 pass 绑定自己的输入描述符
|
||||||
for (auto& pass : m_Passes) {
|
for (auto& pass : m_Passes) {
|
||||||
pass->OnTargetsRebuilt(*m_RenderGraph);
|
pass->OnTargetsRebuilt(*m_RenderGraph);
|
||||||
}
|
}
|
||||||
ENGINE_INFO("[diag] targets rebuilt");
|
|
||||||
// 环境辐照度绑定(view 全程稳定,绑一次)
|
// 环境辐照度绑定(view 全程稳定,绑一次)
|
||||||
m_SceneGpu->BindEnvironment(*m_Environment);
|
m_SceneGpu->BindEnvironment(*m_Environment);
|
||||||
ENGINE_INFO("[diag] environment bound");
|
|
||||||
|
|
||||||
// 9. GPU timestamp:每 pass 两枚(前后),按帧槽位分区
|
// 9. GPU timestamp:每 pass 两枚(前后),按帧槽位分区
|
||||||
m_QueriesPerFrame = static_cast<u32>(m_RenderGraph->GetPassCount()) * 2;
|
m_QueriesPerFrame = static_cast<u32>(m_RenderGraph->GetPassCount()) * 2;
|
||||||
@@ -290,11 +212,9 @@ namespace Engine
|
|||||||
|
|
||||||
// HDR 颜色图:Forward 的输出(线性光照值 + 抖动),TAA 显式完成
|
// HDR 颜色图:Forward 的输出(线性光照值 + 抖动),TAA 显式完成
|
||||||
// 时域累积后写入 TAAColor(对齐 UE/Unity 管线)
|
// 时域累积后写入 TAAColor(对齐 UE/Unity 管线)
|
||||||
// extraUsage:调试截图需要 TRANSFER_SRC(第 60 帧 copy 到 buffer)
|
|
||||||
m_HDRColor = m_RenderGraph->CreateTexture(
|
m_HDRColor = m_RenderGraph->CreateTexture(
|
||||||
"HDRColor",
|
"HDRColor",
|
||||||
RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat, 0, 0, 1.0f,
|
RG::TextureDesc{vk::Format::eR16G16B16A16Sfloat});
|
||||||
vk::ImageUsageFlagBits::eTransferSrc});
|
|
||||||
|
|
||||||
// velocity:clip 空间运动向量(TAA 反推历史像素位置)
|
// velocity:clip 空间运动向量(TAA 反推历史像素位置)
|
||||||
m_Velocity = m_RenderGraph->CreateTexture(
|
m_Velocity = m_RenderGraph->CreateTexture(
|
||||||
@@ -472,68 +392,6 @@ namespace Engine
|
|||||||
|
|
||||||
m_RenderGraph->Execute(frameCtx);
|
m_RenderGraph->Execute(frameCtx);
|
||||||
|
|
||||||
// 调试截图:帧尾把 TAAColor 拷进 host buffer(一次)
|
|
||||||
++m_FrameCounter;
|
|
||||||
const bool doCapture = !m_Captured && m_FrameCounter == 60;
|
|
||||||
vk::Image capImage{};
|
|
||||||
vk::Extent2D capExtent{};
|
|
||||||
vk::Format capFormat{};
|
|
||||||
vk::ImageLayout capResting{};
|
|
||||||
if (doCapture &&
|
|
||||||
m_RenderGraph->GetCaptureTarget(m_HDRColor, frameSlot,
|
|
||||||
capImage, capExtent, capFormat, capResting)) {
|
|
||||||
const vk::DeviceSize capBytes = static_cast<vk::DeviceSize>(
|
|
||||||
capExtent.width) * capExtent.height * 8; // RGBA16F
|
|
||||||
const bool capDepth = capFormat == vk::Format::eD32Sfloat;
|
|
||||||
|
|
||||||
m_CaptureAlloc = m_Allocator->CreateBuffer(
|
|
||||||
capBytes,
|
|
||||||
vk::BufferUsageFlagBits::eTransferDst,
|
|
||||||
vk::MemoryPropertyFlagBits::eHostVisible |
|
|
||||||
vk::MemoryPropertyFlagBits::eHostCoherent);
|
|
||||||
|
|
||||||
// resting → TRANSFER_SRC → 拷贝 → 恢复 resting
|
|
||||||
const vk::ImageAspectFlagBits capAspect =
|
|
||||||
capDepth ? vk::ImageAspectFlagBits::eDepth
|
|
||||||
: vk::ImageAspectFlagBits::eColor;
|
|
||||||
vk::ImageMemoryBarrier2 toSrc;
|
|
||||||
toSrc.setSrcStageMask(vk::PipelineStageFlagBits2::eAllCommands)
|
|
||||||
.setSrcAccessMask(vk::AccessFlagBits2::eMemoryWrite)
|
|
||||||
.setDstStageMask(vk::PipelineStageFlagBits2::eTransfer)
|
|
||||||
.setDstAccessMask(vk::AccessFlagBits2::eTransferRead)
|
|
||||||
.setOldLayout(capResting)
|
|
||||||
.setNewLayout(vk::ImageLayout::eTransferSrcOptimal)
|
|
||||||
.setImage(capImage)
|
|
||||||
.setSubresourceRange({capAspect, 0, 1, 0, 1});
|
|
||||||
frameCtx.cmd.pipelineBarrier2(
|
|
||||||
vk::DependencyInfo{}.setImageMemoryBarriers(toSrc));
|
|
||||||
|
|
||||||
vk::BufferImageCopy capRegion;
|
|
||||||
capRegion.setBufferOffset(0)
|
|
||||||
.setBufferRowLength(0)
|
|
||||||
.setBufferImageHeight(0)
|
|
||||||
.setImageSubresource({capAspect, 0, 0, 1})
|
|
||||||
.setImageOffset({0, 0, 0})
|
|
||||||
.setImageExtent({capExtent.width, capExtent.height, 1});
|
|
||||||
frameCtx.cmd.copyImageToBuffer(
|
|
||||||
capImage, vk::ImageLayout::eTransferSrcOptimal,
|
|
||||||
m_CaptureAlloc.Buffer, capRegion);
|
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 back;
|
|
||||||
back.setSrcStageMask(vk::PipelineStageFlagBits2::eTransfer)
|
|
||||||
.setSrcAccessMask(vk::AccessFlagBits2::eTransferRead)
|
|
||||||
.setDstStageMask(vk::PipelineStageFlagBits2::eAllCommands)
|
|
||||||
.setDstAccessMask(vk::AccessFlagBits2::eMemoryRead |
|
|
||||||
vk::AccessFlagBits2::eMemoryWrite)
|
|
||||||
.setOldLayout(vk::ImageLayout::eTransferSrcOptimal)
|
|
||||||
.setNewLayout(capResting)
|
|
||||||
.setImage(capImage)
|
|
||||||
.setSubresourceRange({vk::ImageAspectFlagBits::eColor,
|
|
||||||
0, 1, 0, 1});
|
|
||||||
frameCtx.cmd.pipelineBarrier2(
|
|
||||||
vk::DependencyInfo{}.setImageMemoryBarriers(back));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_CommandManager->EndFrame(frameSlot);
|
m_CommandManager->EndFrame(frameSlot);
|
||||||
|
|
||||||
// 5. 提交
|
// 5. 提交
|
||||||
@@ -577,21 +435,6 @@ namespace Engine
|
|||||||
HandleResize();
|
HandleResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试截图落盘:等 fence(copy 已提交完成)→ fp16 → BMP
|
|
||||||
if (doCapture) {
|
|
||||||
// 诊断截图落盘:等 fence(copy 已提交完成)→ BMP(返回值仅超时标志)
|
|
||||||
(void)m_Device->GetDevice().waitForFences(
|
|
||||||
m_SyncManager->GetFrameFence(frameSlot), VK_TRUE,
|
|
||||||
UINT64_MAX);
|
|
||||||
WriteHdrBMP("capture.bmp", m_CaptureAlloc.MappedPtr,
|
|
||||||
capExtent.width, capExtent.height, false);
|
|
||||||
m_Allocator->Destroy(m_CaptureAlloc);
|
|
||||||
m_Captured = true;
|
|
||||||
ENGINE_INFO("Debug capture written: capture.bmp (HDRColor) "
|
|
||||||
"shadowInstances={}",
|
|
||||||
m_SceneRenderer->GetShadowInstanceCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_CurrentFrame = (m_CurrentFrame + 1) % kMaxFramesInFlight;
|
m_CurrentFrame = (m_CurrentFrame + 1) % kMaxFramesInFlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ void main() {
|
|||||||
vec3 F0 = mix(vec3(0.04), albedo, metallic); // 电介质基准反射率 4%
|
vec3 F0 = mix(vec3(0.04), albedo, metallic); // 电介质基准反射率 4%
|
||||||
|
|
||||||
vec3 Lo = vec3(0.0);
|
vec3 Lo = vec3(0.0);
|
||||||
float shade0 = 1.0f; // 【诊断】阴影系数可视化用
|
float shade0 = 1.0f; // 第 0 盏光的阴影因子(环境光同步衰减用)
|
||||||
|
|
||||||
for (int i = 0; i < MAX_LIGHTS; ++i) {
|
for (int i = 0; i < MAX_LIGHTS; ++i) {
|
||||||
// 按类型分支:方向光无衰减;点光方向指向光源 + 平方距离衰减
|
// 按类型分支:方向光无衰减;点光方向指向光源 + 平方距离衰减
|
||||||
@@ -213,8 +213,6 @@ void main() {
|
|||||||
vec3 ambient = (diffuse + specular) * ubo.ambientColor.rgb
|
vec3 ambient = (diffuse + specular) * ubo.ambientColor.rgb
|
||||||
* mix(0.4, 1.0, shade0); // 阴影区环境同步衰减(简化遮蔽)
|
* mix(0.4, 1.0, shade0); // 阴影区环境同步衰减(简化遮蔽)
|
||||||
|
|
||||||
vec3 color = ambient + Lo + emissive;
|
outColor = vec4(ambient + Lo + emissive, 1.0);
|
||||||
|
|
||||||
outColor = vec4(color, 1.0);
|
|
||||||
outVelocity = fragVelocity;
|
outVelocity = fragVelocity;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user