为什么sPos.z需要在阴影映射中获得texcoord

时间:2018-01-30 04:11:10

标签: directx shader shadow hlsl vertex-shader

为什么在这里使用sPos.z来获得tescoord?

Out.shadowCrd.x = 0.5 * (sPos.z + sPos.x);
Out.shadowCrd.y = 0.5 * (sPos.z - sPos.y);
Out.shadowCrd.z = 0;
Out.shadowCrd.w = sPos.z;

这是一个着色器,可以在“游戏编程和艺术家的着色器”中实现阴影映射。

第一遍在光照空间渲染深度纹理。(光是照相机,朝向原点观察)

第二遍获得深度并计算阴影。

在这些代码之前,模型已经转换为光照空间。

然后应该计算texcoord以读取深度纹理。

但我无法理解计算texcoord的算法。为什么sPos.z会在这里?

这是第二遍

的整个顶点着色器
float distanceScale;
float4 lightPos;
float4 view_position;
float4x4 view_proj_matrix;
float4x4 proj_matrix;
float time_0_X;
struct VS_OUTPUT 
{
    float4 Pos:       POSITION;
    float3 normal:    TEXCOORD0;
    float3 lightVec : TEXCOORD1;
    float3 viewVec:   TEXCOORD2;
    float4 shadowCrd: TEXCOORD3;
};

VS_OUTPUT vs_main(float4 inPos: POSITION, float3 inNormal: NORMAL)
{
       VS_OUTPUT Out;

       // Animate the light position.
       float3 lightPos;
       lightPos.x = cos(1.321 * time_0_X);
       lightPos.z = sin(0.923 * time_0_X);
       lightPos.xz = 100 * normalize(lightPos.xz);
       lightPos.y = 100;

       // Project the object's position
       Out.Pos = mul(view_proj_matrix, inPos);

       // World-space lighting
       Out.normal = inNormal;
       Out.lightVec = distanceScale * (lightPos - inPos.xyz);
       Out.viewVec = view_position - inPos.xyz;

       // Create view vectors for the light, looking at (0,0,0)
       float3 dirZ = -normalize(lightPos);
       float3 up = float3(0,0,1);
       float3 dirX = cross(up, dirZ);
       float3 dirY = cross(dirZ, dirX);

       // Transform into light's view space.
       float4 pos;
       inPos.xyz -= lightPos;
       pos.x = dot(dirX, inPos);
       pos.y = dot(dirY, inPos);
       pos.z = dot(dirZ, inPos);
       pos.w = 1;

       // Project it into light space to determine she shadow
       // map position
       float4 sPos = mul(proj_matrix, pos);

       // Use projective texturing to map the position of each fragment
       // to its corresponding texel in the shadow map.
       sPos.z += 10;
       Out.shadowCrd.x = 0.5 * (sPos.z + sPos.x);
       Out.shadowCrd.y = 0.5 * (sPos.z - sPos.y);
       Out.shadowCrd.z = 0;
       Out.shadowCrd.w = sPos.z;

       return Out;
    }

Pixel Shader:

  float shadowBias;
  float backProjectionCut;
  float Ka;
  float Kd;
  float Ks;
  float4 modelColor;
  sampler ShadowMap;
  sampler SpotLight;
  float4 ps_main(
     float3 inNormal: TEXCOORD0, 
     float3 lightVec: TEXCOORD1, 
     float3 viewVec: TEXCOORD2, 
     float4 shadowCrd: TEXCOORD3) : COLOR 
  {
     // Normalize the normal
     inNormal = normalize(inNormal);

     // Radial distance and normalize light vector
     float depth = length(lightVec);
     lightVec /= depth;

     // Standard lighting
     float diffuse = saturate(dot(lightVec, inNormal));
     float specular = pow(saturate(
                          dot(reflect(-normalize(viewVec), inNormal), lightVec)), 
                      16);

     // The depth of the fragment closest to the light
     float shadowMap = tex2Dproj(ShadowMap, shadowCrd);

     // A spot image of the spotlight
     float spotLight = tex2Dproj(SpotLight, shadowCrd);

     // If the depth is larger than the stored depth, this fragment
     // is not the closest to the light, that is we are in shadow.
     // Otherwise, we're lit. Add a bias to avoid precision issues.
     float shadow = (depth < shadowMap + shadowBias);

     // Cut back-projection, that is, make sure we don't lit
     // anything behind the light.
     shadow *= (shadowCrd.w > backProjectionCut);

     // Modulate with spotlight image
     shadow *= spotLight;

     // Shadow any light contribution except ambient
     return Ka * modelColor + 
            (Kd * diffuse * modelColor + Ks * specular) * shadow;
  }

0 个答案:

没有答案