我在这个问题上花了很长时间,终于意识到我需要认真的帮助...
所以基本上我想在Monogame中通过我的项目实现适当的阴影。为此,我使用了多个教程(主要针对旧的XNA)在HLSL中编写了一个延迟的dhader。 问题是,尽管我的照明和阴影可以用作聚光灯,但场景中的光非常依赖于我的相机,如您在图像中看到的:https://imgur.com/a/TU7y0bs
我尝试了许多不同的方法来解决此问题:
我正在使用
new RenderTarget2D(device,
Width, Height, false, SurfaceFormat.Vector2, DepthFormat.Depth24Stencil8)
从灯光角度存储深度。
我使用此PixelShader函数计算阴影: 请注意,我希望将来将此着色器调整为点光源-这就是为什么我直接使用length(LightPos-PixelPos)的原因。 SpotLight.fx-PixelShader
float4 PS(VSO input) : SV_TARGET0
{
// Fancy Lighting equations
input.ScreenPosition.xy /= input.ScreenPosition.w;
float2 UV = 0.5f * (float2(input.ScreenPosition.x, -input.ScreenPosition.y) + 1) - float2(1.0f / GBufferTextureSize.xy);
// Sample Depth from DepthMap
float Depth = DepthMap.Sample(SampleTypeClamp, UV).x;
// Getting the PixelPosition in WorldSpace
float4 Position = 1.0f;
Position.xy = input.ScreenPosition.xy;
Position.z = Depth;
// Transform Position to WorldSpace
Position = mul(Position, InverseViewProjection);
Position /= Position.w;
float4 LightScreenPos = mul(Position, LightViewProjection);
LightScreenPos /= LightScreenPos.w;
// Calculate Projected UV from Light POV -> ScreenPos is in [-1;1] Space
float2 LightUV = 0.5f * (float2(LightScreenPos.x, -LightScreenPos.y) + 1.0f);
float lightDepth = ShadowMap.Sample(SampleDot, LightUV).r;
// Linear depth model
float closestDepth = lightDepth * LightFarplane; // Depth is stored in [0, 1]; bring it to [0, farplane]
float currentDepth = length(LightPosition.xyz - Position.xyz) - DepthBias;
ShadowFactor = step(currentDepth, closestDepth); // closestDepth > currentDepth -> Occluded, Shadow.
float4 phong = Phong(...);
return ShadowFactor * phong;
}
LightViewProjection只是light.View * light.Projection
InverseViewProjection为Matrix.Invert(camera.View * Camera.Projection)
Phong()是我用来最终确定照明的函数
lightDepthMap仅存储length(lightPos - Position)
我希望图片中显示的伪像也能够使代码适应点光源。
这可能是我从屏幕空间检索世界位置并且深度达到低分辨率的方式有问题吗?
非常感谢您的帮助!
---更新---
我更改了“ Lighting”着色器,以显示存储在shadowMap中的距离与在Pixelshader中当场计算的距离之间的差:
float4 PixelShaderFct(...) : SV_TARGET0
{
// Get Depth from Texture
float4 Position = 1.0f;
Position.xy = input.ScreenPosition.xy;
Position.z = Depth;
Position = mul(Position, InverseViewProjection);
Position /= Position.w;
float4 LightScreenPos = mul(Position, LightViewProjection);
LightScreenPos /= LightScreenPos.w;
// Calculate Projected UV from Light POV -> ScreenPos is in [-1;1] Space
float2 LUV = 0.5f * (float2(LightScreenPos.x, -LightScreenPos.y) + 1.0f);
float lightZ = ShadowMap.Sample(SampleDot, LUV).r;
float Attenuation = AttenuationMap.Sample(SampleType, LUV).r;
float ShadowFactor = 1;
// Linear depth model; lightZ stores (LightPos - Pos)/LightFarPlane
float closestDepth = lightZ * LightFarPlane;
float currentDepth = length(LightPosition.xyz - Position.xyz) -DepthBias;
return (closestDepth - currentDepth);
}
因为我基本上是在输出Length-(Length-Bias),所以人们期望使用“ DepthBias”作为其颜色的图像。但这不是我要到达这里的结果:
基于这个结果,我假设我遇到了精度问题(考虑到我使用[0.1,50]的近平面和远平面,我发现这很奇怪),或者方式有问题我正在从我的DepthMap中恢复给定像素的worldPosition。
答案 0 :(得分:0)
我终于找到了解决方案,如果有人偶然发现同一问题,我将其发布在这里:
我使用的教程是XNA / DX9的。但是,在以DX10 +为目标时,需要做一点微小的改变:
在XNA / DX9中,UV坐标未与实际像素对齐,需要对齐。这就是index($0,"SEARCH")==1
中- float2(1.0f / GBufferTextureSize.xy);
的目的。在DX10及更高版本中不需要此功能,这将导致我遇到的问题。
解决方案:
用于全屏四边形的UV坐标:
对于XNA / DX9:
float2 UV = 0.5f * (float2(input.ScreenPosition.x, -input.ScreenPosition.y) + 1) - float2(1.0f / GBufferTextureSize.xy);
对于Monogame / DX10 +
input.ScreenPosition.xy /= input.ScreenPosition.w;
float2 UV = 0.5f * (float2(input.ScreenPosition.x, -input.ScreenPosition.y) + 1) - float2(1.0f / GBufferTextureSize.xy);