Jump to content


Shadow Map Shader problem


3 replies to this topic

#1 Sikozu

    New Member

  • Members
  • Pip
  • 5 posts

Posted 22 February 2009 - 11:13 PM

Hello!

I have a problem with my shader, it compiles and works and is pretty on pixel shader 3, but fails on 2!

This is the shader:

float4x4 World;

float4x4 View;

float4x4 Projection;

float4x4 LightView;

float4x4 LightProjection;


static const float SHADOW_EPSILON = 0.00005f;

static float SMAP_SIZE = 2048.0f;


void BuildShadowMapVS(float4 posL : POSITION,

                      out float4 posH : POSITION0,

                      out float2 depth : TEXCOORD0)

{

	// Render from light's perspective.

	float4x4 Transform;

	Transform = mul(World, LightView);

	Transform = mul(Transform, LightProjection);

	posH = mul(posL, Transform);

	

	// Propagate z- and w-coordinates.

	depth = posH.zw;

}


float4 BuildShadowMapPS(float2 depth : TEXCOORD0) : COLOR

{

	// Each pixel in the shadow map stores the pixel depth from the 

	// light source in normalized device coordinates.

	return depth.x / depth.y; // z / w

}


technique BuildShadowMapTech

{

	pass P0

	{

		vertexShader = compile vs_2_0 BuildShadowMapVS();

        pixelShader  = compile ps_2_0 BuildShadowMapPS();

	}

}


struct Mtrl

{

	float4 diffuse;

	float4 ambient;

	float4 spec;

	float4 Emissive;

	float  specPower;

};


struct SpotLight

{

	float4 ambient;

	float4 diffuse;

	float4 spec;

	float3 posW;

	float3 dirW;  

	float  spotPower;

};


//uniform extern float4x4  gWVP;

Mtrl      Material;

SpotLight gSpotLight;

float3    gEyePosW;

texture   gTex0;

texture   gShadowMap;

 

sampler Tex0S = sampler_state

{

	Texture = <gTex0>;

	MinFilter = Anisotropic;

	MagFilter = LINEAR;

	MipFilter = LINEAR;

	MaxAnisotropy = 8;

	AddressU  = WRAP; 

    AddressV  = WRAP;

};


sampler ShadowMapS = sampler_state

{

	Texture = <gShadowMap>;

	MinFilter = POINT;

	MagFilter = POINT;

	MipFilter = POINT;

	AddressU  = CLAMP; 

    AddressV  = CLAMP;

};


void LightShadowVS(float4 posL         : POSITION,

                   float3 normalL      : NORMAL0,

                   float2 tex0         : TEXCOORD0,

                   out float4 oPosH    : POSITION0,

                   out float3 oPosW    : TEXCOORD0,

                   out float3 oNormalW : TEXCOORD1,

                   out float3 oToEyeW  : TEXCOORD2,

                   out float2 oTex0    : TEXCOORD3,

                   out float4 oProjTex : TEXCOORD4)

{

	// Transform to homogeneous clip space.

	oPosH = mul(posL, mul(mul(World, View), Projection));

	

	// Transform vertex position to world space.

	oPosW = mul(posL, World).xyz;

	

	// Transform normal to world space (assume no non-uniform scaling).

	oNormalW = mul(float4(normalL, 0.0f), World).xyz;

	

	// Compute the unit vector from the vertex to the eye.

	oToEyeW = gEyePosW - oPosW;

	

	// Pass on texture coords to PS

	oTex0 = tex0;

	

	// Generate projective texture coordinates.

	oProjTex = mul(posL, mul(mul(World, LightView), LightProjection));

}


float4 LightShadowPS(float3 posW    : TEXCOORD0,

                     float3 normalW : TEXCOORD1,

                     float3 toEyeW  : TEXCOORD2,

                     float2 tex0    : TEXCOORD3,

                     float4 projTex : TEXCOORD4) : COLOR

{

	// Interpolated normals can become unnormal--so normalize.

	normalW = normalize(normalW);

	toEyeW  = normalize(toEyeW);

	

	// Light vector is from pixel to spotlight position.

	float3 lightVecW = normalize(gSpotLight.posW - posW);

	

	// Compute the reflection vector.

	float3 r = reflect(-lightVecW, normalW);

	

	// Determine how much (if any) specular light makes it into the eye.

	float t  = pow(max(dot(r, toEyeW), 0.0f), Material.specPower);

	

	// Determine the diffuse light intensity that strikes the vertex.

	float s = max(dot(lightVecW, normalW), 0.0f);

	

	// Compute the ambient, diffuse and specular terms separately. 

	float3 spec = t*(Material.spec*gSpotLight.spec).rgb;

	float3 diffuse = s*(Material.diffuse*gSpotLight.diffuse.rgb);

	float3 ambient = Material.ambient*gSpotLight.ambient;

	

	// Compute spotlight coefficient.

	float spot = pow(max( dot(-lightVecW, gSpotLight.dirW), 0.0f), gSpotLight.spotPower);

	

	// Sample decal map.

	float4 texColor = tex2D(Tex0S, tex0); 

	

	// Project the texture coords and scale/offset to [0, 1].

	projTex.xy /= projTex.w;            

	projTex.x =  0.5f*projTex.x + 0.5f; 

	projTex.y = -0.5f*projTex.y + 0.5f;

	

	// Compute pixel depth for shadowing.

	float depth = projTex.z / projTex.w;

 

	// Transform to texel space

    float2 texelpos = SMAP_SIZE * projTex.xy;

        

    // Determine the lerp amounts.           

    float2 lerps = frac( texelpos );

    

    // 3x3 percentage closest filter.

    float dx = 1.0f / SMAP_SIZE;

    float2 vTexCoords[9];

    

    // Sample each of them checking whether the pixel under test is shadowed or not

   vTexCoords[0] = projTex;

   vTexCoords[1] = projTex + float2( -dx, 0.0f );

   vTexCoords[2] = projTex + float2( dx, 0.0f );

   vTexCoords[3] = projTex + float2( 0.0f, dx );

   vTexCoords[4] = projTex + float2( 0.0f, -dx );

   vTexCoords[5] = projTex + float2( dx, dx );

   vTexCoords[6] = projTex + float2( -dx, dx );

   vTexCoords[7] = projTex + float2( dx, -dx );

   vTexCoords[8] = projTex + float2( -dx,  -dx);

	

	

	

   float fShadowTerms[9];

   float fShadowTerm = 0.0f;

   int count = 0;

   for( int i = 0; i < 9; i++ )

   {

      float A = tex2D(ShadowMapS , vTexCoords[i] ).r;


      // Texel is shadowed

      fShadowTerms[i] = (A + SHADOW_EPSILON < depth) ? 0.0f : 1.0f;

      fShadowTerm += fShadowTerms[i];

   }

   // Get the average

   fShadowTerm /= 9.0f;

   


   

   // Light/Texture pixel.  Note that shadow coefficient only affects diffuse/spec.

	float3 litColor = spot*ambient*texColor.rgb + spot*fShadowTerm*(diffuse*texColor.rgb + spec);

	

	return float4(litColor, Material.diffuse.a*texColor.a);

}


technique LightShadowTech

{

    pass P0

    {

        // Specify the vertex and pixel shader associated with this pass.

        vertexShader = compile vs_3_0 LightShadowVS();

        pixelShader  = compile ps_3_0 LightShadowPS();

    }

}


Now, I know the problem is related to this bit:
float fShadowTerms[9];
float fShadowTerm = 0.0f;
int count = 0;
for( int i = 0; i < 9; i++ )
{
float A = tex2D(ShadowMapS , vTexCoords[i] ).r;

// Texel is shadowed
fShadowTerms[i] = (A + SHADOW_EPSILON < depth) ? 0.0f : 1.0f;
fShadowTerm += fShadowTerms[i];
}
// Get the average
fShadowTerm /= 9.0f;

On shader 2, it fails to compile of the loop goes beyond 5!

Hopefully someone can find what is wrong :)
thanks!

#2 imerso

    Senior Member

  • Members
  • PipPipPipPip
  • 426 posts
  • LocationBrasil

Posted 23 February 2009 - 01:36 AM

Seems like it reaches the number of instructions limit of shader model 2. As far as I know, the loop will always be unrolled under PS2, that is the reason you quickly reach instructions limit when using loops.

#3 Sikozu

    New Member

  • Members
  • Pip
  • 5 posts

Posted 23 February 2009 - 04:21 AM

Always? what if I render it to a quad and do 3v3 in another technique?
Or any way to make it work in the same technique?

#4 RodgerBorland

    New Member

  • Members
  • Pip
  • 2 posts

Posted 23 February 2009 - 06:51 AM

yes SM 2.0 does not support dynamic branching, it will always unroll. yes it will work as you suggested or you could use deferred shadowing if you really need 3x3 samples. otherwise since it fails at i=5, just use 2x2 pcf for SM2.





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users