Я уже довольно долго бьюсь об этой проблеме и наконец-то осознал, что мне нужна серьезная помощь ...
Так что в основном я хотел внедрить подходящие тени в свой проект, который я пишу в Monogame.Для этого я написал отложенный дхадер в HLSL, используя несколько учебных пособий, в основном для старой XNA.Проблема в том, что, хотя мое освещение и тень работают на прожектор, свет на полу моей сцены очень зависит от моей камеры, как вы можете видеть на изображениях: https://imgur.com/a/TU7y0bs
Я пробовал многоразные вещи, чтобы решить эту проблему:
- Больший DepthBias будет расширять радиус "без тени" с массивным панорамированием Питера, и описанная проблема не будет решена вообще.
- OneВ статье предлагалось использовать экспоненциальную карту теней, но мне совсем не понравились результаты, поскольку легкое кровотечение было невыносимым, а тени меньшего размера (например, за факелом у стены) не рендерились.
- Я переключил свой GBuffer DepthMap на 1-z / w, чтобы получить больше точности, но это также не решило проблему.
Я использую
new RenderTarget2D(device,
Width, Height, false, SurfaceFormat.Vector2, DepthFormat.Depth24Stencil8)
для храненияглубина с точки зрения освещения.
Я вычисляю тень, используя эту функцию PixelShader: обратите внимание, что я хочу адаптировать этот шейдер к точечному освещению в будущем - вот почему я симслой с использованием длины (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)
Мне бы хотелось, чтобы этот артефакт, показанный на фотографиях, также мог адаптировать код к точечным источникам света.
Может ли это быть проблемой с тем, как я получаю положение в мире из экранного пространства имоя глубина достигла низкого разрешения?
Помощь очень важна!
--- Обновление ---
Я изменил свой шейдер освещения, чтобы отобразить разницу между расстояниемхранится в 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.,Но это не тот результат, который я получаю:
https://imgur.com/a/4PXLH7s
Исходя из этого, я предполагаю, что либо у меня есть проблемы с точностью (что я нахожу странным,учитывая, что я работаю с ближними и дальними плоскостями [0.1, 50]), или что-то не так с тем, как я восстанавливаю worldPosition данного пикселя из моей карты глубины.