gpt4 book ai didi

c++ - DirectX 将像素世界位置转换为阴影贴图位置会产生奇怪的平铺结果

转载 作者:行者123 更新时间:2023-11-30 05:23:15 25 4
gpt4 key购买 nike

一段时间以来,我一直在尝试将屏幕空间像素(由延迟 HLSL 着色器提供)转换为光空间。结果令我感到惊讶,因为我的光照渲染似乎平铺了深度缓冲区。

重要的是,场景相机(或眼睛)和从同一位置开始渲染的光线。

首先,我使用以下代码提取像素的世界位置:

float3 eye = Eye;
float4 position = {
IN.texCoord.x * 2 - 1,
(1 - IN.texCoord.y) * 2 - 1,
zbuffer.r,
1
};
float4 hposition = mul(position, EyeViewProjectionInverse);
position = float4(hposition.xyz / hposition.w, hposition.w);
float3 eyeDirection = normalize(eye - position.xyz);

结果似乎是正确的,因为将 XYZ 位置渲染为 RGB 分别产生了这个(显然正确的)结果:

Correctly rendered XYZ

红色组件似乎在向右移动时正确输出 X,蓝色组件显示 Z 向前移动。 Y 因子看起来也正确,因为地面略低于 Y 轴。

接下来(为了确保我不会发疯),我决定输出原始深度缓冲区。通常,我将深度缓冲区保存在名为 DepthMap 的 Texture2D 中,作为输入传递给着色器。然而,在这种情况下,我尝试通过将其偏移回正确位置并将其乘以眼睛的 View 投影矩阵来撤消像素变换:

float4 cpos = mul(position, EyeViewProjection);
cpos.xyz = cpos.xyz / cpos.w;
cpos.x = cpos.x * 0.5f + 0.5f;
cpos.y = 1 - (cpos.y * 0.5f + 0.5f);
float camera_depth = pow(DepthMap.Sample(Sampler, cpos.xy).r, 100); // Power 100 just to visualize the map since scales are really tiny
return float4(camera_depth, camera_depth, camera_depth, 1);

这也会产生正确的结果(尽管我不能 100% 确定 Z 值)。另请注意,我已将结果设为指数级以更好地可视化深度信息(尝试实时比较时不会这样做):

Reinterpreting XYZ back to ZBuffer space

所以理论上,我可以使用相同的代码通过乘以光的 View 投影矩阵将该像素世界位置转换为光空间。正确的?这是我尝试过的:

float4 lpos = mul(position, ShadowLightViewProjection[0]);
lpos.xyz = lpos.xyz / lpos.w;
lpos.x = lpos.x * 0.5f + 0.5f;
lpos.y = 1 - (lpos.y * 0.5f + 0.5f);
float shadow_map_depth = pow(ShadowLightMap[0].Sample(Sampler, lpos.xy).r, 100); // Power 100 just to visualize the map since scales are really tiny
return float4(shadow_map_depth, shadow_map_depth, shadow_map_depth, 1);

结果如下:

Broken light space

另一个更好地展示它是如何映射到世界的:

Broken light space #2

我不明白这是怎么回事。看起来它可能与投影矩阵有关,但我的数学不太好,无法确定发生了什么。这绝对不是光照贴图的宽度/高度,因为我尝试了多种贴图尺寸,并且投影矩阵是使用 FOV 和纵横比计算的,从来没有输入过宽度/高度。

最后,这里有一些 C++ 代码显示了我的透视矩阵(用于眼睛和光线)是如何计算的:

    const auto ys = std::tan((T)1.57079632679f - (fov / (T)2.0));
const auto xs = ys / aspect;
const auto& zf = view_far;
const auto& zn = view_near;
const auto zfn = zf - zn;

row1(xs, 0, 0, 0);
row2(0, ys, 0, 0);
row3(0, 0, zf / zfn, 1);
row4(0, 0, -zn * zf / zfn, 0);
return *this;

我在这里完全不知所措。任何指导或建议将不胜感激!

编辑 - 我还忘了提到平铺图像是颠倒的,就好像 y 翻转破坏了它一样。这对我来说很奇怪,因为它需要正确地回到眼睛纹理空间。

最佳答案

我在这里和那里做了一些调整和修复。最终,我最大的问题是意外的转置矩阵。矩阵如何转置有点复杂,但这就是翻转的原因。我还更改为 D32 深度缓冲区(虽然我不确定是否有帮助)并确保任何位置除以它们的 W 影响所有组件(包括 W)。

所以代码如下:hposition.xyz = hposition.xyz/hposition.w变成了这样:hposition = hposition/hposition.w

经过所有这些调整后,它开始看起来更像一个阴影贴图。

哦,转置矩阵是光的 ViewProjection。

关于c++ - DirectX 将像素世界位置转换为阴影贴图位置会产生奇怪的平铺结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39284114/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com