Отображение теней с неверными результатами (HLSL, Shader model 3.0)

(Извините за мой плохой английский.)

Я новичок в Stack Overflow и пишу приложение для 3D-игр с компилятором MS Visual C ++ 2015, Direct3D 9 и HLSL (Shader model 3.0).

Я реализовал логику отложенного рендеринга с 4 целевыми текстурами рендеринга. Я сохранил значения глубины пикселей в целевой текстуре рендеринга и создал карту теней. Вот результаты. (Все сетки имеют черный цвет, потому что сетки имеют небольшой размер и расположены близко к камере. Значение расстояния в дальней плоскости равно 1000.0f.)

Текстура глубины и карта теней.

Я визуализировал полноэкранный четырехугольник с шейдерами наложения теней и вывел тени с красным цветом, чтобы убедиться, что шейдер работает правильно. Но, похоже, шейдеры выдают неверные результаты. Вывод текстуры карты теней повторяется на поверхностях сетки.

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 для карты теней имеет неправильные значения, но я не могу понять, в чем реальная проблема.

Большое спасибо за любую помощь.

РЕДАКТИРОВАТЬ: я обновил коды шейдеров. Я решил использовать линейную глубину пространства обзора и подтвердил, что положение в мире имеет правильное значение. Я действительно не понимаю, почему значения координат карты теней имеют неправильные значения ...


person FooBarBazQux    schedule 02.08.2016    source источник


Ответы (2)


Похоже, вы действительно ошиблись. Поищите в Google «Shadow Acne», и вы найдете ответ на свою проблему. Также проблемой может быть разрешение карты теней.

person 00noize00    schedule 03.08.2016
comment
Нет, это не моя проблема. Текстура карты теней повторяется на поверхностях сетки в зависимости от положения и угла камеры. Кажется, я должен показать вам видео с реальным результатом. - person FooBarBazQux; 03.08.2016

Я нашел решение.

Первая проблема заключалась в том, что текстура целевой рендеринга имела неправильный формат текстуры. Я должен был использовать 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» - это расстояние в дальней плоскости до усеченного края камеры. Я все еще пытаюсь понять, зачем это нужно.

person FooBarBazQux    schedule 19.08.2016