阴影映射结果错误(HLSL,Shader model 3.0)

时间:2016-08-02 18:17:52

标签: visual-c++ hlsl directx-9 shadow-mapping

(抱歉我的英语不好。)

我是Stack Overflow的新手,用MS Visual C ++ 2015编译器,Direct3D 9和HLSL(Shader model 3.0)编写3D游戏应用程序。

我实现了一个带有4个渲染目标纹理的延迟渲染逻辑。 我在渲染目标纹理中存储了像素的深度值,并创建了阴影贴图。结果如下。 (所有网格都有黑色,因为网格尺寸较小,靠近相机。远平面距离值为1000.0f。)

The depth texture and the shadow map.

我使用阴影贴图着色器渲染全屏四边形,并输出红色阴影以确认着色器工作正常。 但是,着色器似乎输出了错误的结果。阴影贴图纹理输出在网格曲面上重复。

https://www.youtube.com/watch?v=1URGgoCR6Zc

这是用于绘制四边形的阴影贴图顶点着色器。

struct VsInput {
   float4 position : POSITION0;
};

struct VsOutput {
   float4 position : POSITION0;
   float4 cameraViewRay : TEXCOORD0;
};

float4x4 matInverseCameraViewProjection;
float4 cameraWorldPosition;
float farDistance;

VsOutput vs_main(VsInput input) {
   VsOutput output = (VsOutput)0;

   output.position = input.position;

   output.cameraViewRay = mul(float4(input.position.xy, 1.0f, 1.0f) * farDistance, matInverseCameraViewProjection);
   output.cameraViewRay /= output.cameraViewRay.w;
   output.cameraViewRay.xyz -= cameraWorldPosition.xyz;

   return output;
}

这是阴影贴图像素着色器绘制四边形。

struct PsInput {
   float2 screenPosition : VPOS;
   float4 viewRay : TEXCOORD0;
};

struct PsOutput {
   float4 color : COLOR0;
};

texture depthMap;
texture shadowMap;

sampler depthMapSampler = sampler_state {
    Texture = (depthMap);
    AddressU = CLAMP;
    AddressV = CLAMP;
    MagFilter = POINT;
    MinFilter = POINT;
    MipFilter = POINT;
};

sampler shadowMapSampler = sampler_state {
    Texture = (shadowMap);
    AddressU = CLAMP;
    AddressV = CLAMP;
    MagFilter = POINT;
    MinFilter = POINT;
    MipFilter = POINT;
};

//float4x4 matCameraView;
float4x4 matLightView;
float4x4 matLightProjection;
float4 cameraWorldPosition;
float4 lightWorldPosition;
float2 halfPixel;
float epsilon;
float farDistance;

PsOutput ps_main(PsInput input) {
   PsOutput output = (PsOutput)0;
   output.color.a = 1.0f;

   //Reconstruct the world position using the view-space linear depth value.
   float2 textureUv = input.screenPosition * halfPixel * 2.0f - halfPixel;
   float viewDepth = tex2D(depthMapSampler, textureUv).r;
   float3 eye = input.viewRay.xyz * viewDepth;
   float4 worldPosition = float4((eye + cameraWorldPosition.xyz), 1.0f);

   //Test if the reconstructed world position has right coordinate values.
   //output.color = mul(worldPosition, matCameraView).z / farDistance;

   float4 positionInLightView = mul(worldPosition, matLightView);
   float lightDepth = positionInLightView.z / farDistance;
   float4 positionInLightProjection = mul(positionInLightView, matLightProjection);
   positionInLightProjection /= positionInLightProjection.w;

   //If-statement doesn't work???
   float condition = positionInLightProjection.x >= -1.0f;
   condition *= positionInLightProjection.x <= 1.0f;
   condition *= positionInLightProjection.y >= -1.0f;
   condition *= positionInLightProjection.y <= 1.0f;
   condition *= positionInLightProjection.z >= 0.0f;
   condition *= positionInLightProjection.z <= 1.0f;
   condition *= positionInLightProjection.w > 0.0f;

   float2 shadowMapUv = float2(
      positionInLightProjection.x * 0.5f + 0.5f,
      -positionInLightProjection.y * 0.5f + 0.5f
   );

   //If-statement doesn't work???
   float condition2 = shadowMapUv.x >= 0.0f;
   condition2 *= shadowMapUv.x <= 1.0f;
   condition2 *= shadowMapUv.y >= 0.0f;
   condition2 *= shadowMapUv.y <= 1.0f;

   float viewDepthInShadowMap = tex2D(
      shadowMapSampler,
      shadowMapUv
   ).r;
   output.color.r = lightDepth > viewDepthInShadowMap + epsilon;
   output.color.r *= condition;
   output.color.r *= condition2;

   return output;
}

似乎阴影贴图的uv有一些错误的值,但我无法弄清楚真正的问题是什么。

非常感谢您的帮助。

编辑:我已更新着色器代码。我决定使用视空间线性深度并确认世界位置具有正确的价值。我真的不明白为什么阴影贴图坐标值有错误的值...

2 个答案:

答案 0 :(得分:0)

看起来你似乎使用了错误的偏见。谷歌“阴影痤疮”你应该找到你的问题的答案。阴影贴图的分辨率也可能是个问题。

答案 1 :(得分:0)

我找到了解决方案。

第一个问题是渲染目标纹理的纹理格式错误。我应该使用D3DFMT_R32F。 (我使用过D3DFMT_A8R8G8B8。)

我在阴影贴图像素着色器中添加了这些线条。

//Reconstruct the world position using the view-space linear depth value.
float2 textureUv = input.screenPosition * halfPixel * 2.0f - halfPixel;
float4 viewPosition = float4(input.viewRay.xyz * tex2D(depthMapSampler, textureUv).r, 1.0f);
float4 worldPosition = mul(viewPosition, matInverseCameraView);

...

//If-statement doesn't work???
float condition = positionInLightProjection.x >= -1.0f;
condition *= positionInLightProjection.x <= 1.0f;
condition *= positionInLightProjection.y >= -1.0f;
condition *= positionInLightProjection.y <= 1.0f;
condition *= positionInLightProjection.z >= 0.0f;
condition *= positionInLightProjection.z <= 1.0f;
condition *= viewPosition.z < farDistance;

最后一行是关键,解决了我的第二个问题。 'farDistance'是相机平截头体的远平面距离。我仍在努力理解为什么需要这样做。