Hello,
I am trying to use Frank Luna's great, great shader book to render terrain with billboarded trees that are alpha tested, but also use shadow maps to draw some nice, leafy shadows under the trees. It's an age old problem, and one I am unable to find a solution for after googling for a few days. At least now I've narrowed it down to alpha test and not alpha blend, but still not working. What I think should show as alpha blended shadows on the terrain instead turns up as solid black rectangles.
void ShadowMapDemo::drawShadowMap()
{
mShadowMap->beginScene();
HR(gd3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0));
HR(mFX->SetTechnique(mhBuildShadowMapTech));
UINT numPasses = 0;
HR(mFX->Begin(&numPasses, 0));
HR(mFX->BeginPass(0));
// Draw scene mesh.
HR(mFX->SetMatrix(mhLightWVP, &(mSceneWorld*mLightVP)));
HR(mFX->CommitChanges());
for(UINT j = 0; j < mSceneMtrls.size(); ++j)
{
for(UINT j = 0; j < mSceneMtrls.size(); ++j)
{
HR(mSceneMesh->DrawSubset(j));
}
}
// Draw car mesh. (substituted w/ a tree with trunk and billboard leaves/branches)
HR(mFX->SetMatrix(mhLightWVP, &(mCarWorld*mLightVP)));
HR(mFX->CommitChanges());
HR(gd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, true));
HR(gd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL));
HR(gd3dDevice->SetRenderState(D3DRS_ALPHAREF, 200));
for(UINT j = 0; j < mCarMtrls.size(); ++j)
{
for(UINT j = 0; j < mCarMtrls.size(); ++j)
{
HR(mCarMesh->DrawSubset(j));
}
}
HR(gd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false));
HR(mFX->EndPass());
HR(mFX->End());
mShadowMap->endScene();
}
Here is the .fx file
//=============================================================================
// LightShadow.fx by Frank Luna (C) 2004 All Rights Reserved.
//
// Does lighting and shadowing with shadow maps.
//=============================================================================
uniform extern float4x4 gLightWVP;
static const float SHADOW_EPSILON = 0.00005f;
static const float SMAP_SIZE = 512.0f;
void BuildShadowMapVS(float3 posL : POSITION0,
out float4 posH : POSITION0,
out float2 depth : TEXCOORD0)
{
// Render from light's perspective.
posH = mul(float4(posL, 1.0f), gLightWVP);
// 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 ambient;
float4 diffuse;
float4 spec;
float specPower;
};
struct SpotLight
{
float4 ambient;
float4 diffuse;
float4 spec;
float3 posW;
float3 dirW;
float spotPower;
};
uniform extern float4x4 gWorld;
uniform extern float4x4 gWVP;
uniform extern Mtrl gMtrl;
uniform extern SpotLight gLight;
uniform extern float3 gEyePosW;
uniform extern texture gTex;
uniform extern texture gShadowMap;
sampler TexS = sampler_state
{
Texture = <gTex>;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};
sampler ShadowMapS = sampler_state
{
Texture = <gShadowMap>;
MinFilter = POINT;
MagFilter = POINT;
MipFilter = POINT;
AddressU = CLAMP;
AddressV = CLAMP;
};
void LightShadowVS(float3 posL : POSITION0,
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(float4(posL, 1.0f), gWVP);
// Transform vertex position to world space.
oPosW = mul(float4(posL, 1.0f), gWorld).xyz;
// Transform normal to world space (assume no non-uniform scaling).
oNormalW = mul(float4(normalL, 0.0f), gWorld).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(float4(posL, 1.0f), gLightWVP);
}
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(gLight.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), gMtrl.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*(gMtrl.spec*gLight.spec).rgb;
float3 diffuse = s*(gMtrl.diffuse*gLight.diffuse.rgb);
float3 ambient = gMtrl.ambient*gLight.ambient;
// Compute spotlight coefficient.
float spot = pow(max( dot(-lightVecW, gLight.dirW), 0.0f), gLight.spotPower);
// Sample decal map.
float4 texColor = tex2D(TexS, 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 );
// 2x2 percentage closest filter.
float dx = 1.0f / SMAP_SIZE;
float s0 = (tex2D(ShadowMapS, projTex.xy).r + SHADOW_EPSILON < depth) ? 0.0f : 1.0f;
float s1 = (tex2D(ShadowMapS, projTex.xy + float2(dx, 0.0f)).r + SHADOW_EPSILON < depth) ? 0.0f : 1.0f;
float s2 = (tex2D(ShadowMapS, projTex.xy + float2(0.0f, dx)).r + SHADOW_EPSILON < depth) ? 0.0f : 1.0f;
float s3 = (tex2D(ShadowMapS, projTex.xy + float2(dx, dx)).r + SHADOW_EPSILON < depth) ? 0.0f : 1.0f;
float shadowCoeff = lerp( lerp( s0, s1, lerps.x ),
lerp( s2, s3, lerps.x ),
lerps.y );
// Light/Texture pixel. Note that shadow coefficient only affects diffuse/spec.
float3 litColor = spot*ambient*texColor.rgb + spot*shadowCoeff*(diffuse*texColor.rgb + spec);
return float4(litColor, gMtrl.diffuse.a*texColor.a);
}
technique LightShadowTech
{
pass P0
{
// Specify the vertex and pixel shader associated with this pass.
vertexShader = compile vs_2_0 LightShadowVS();
pixelShader = compile ps_2_0 LightShadowPS();
}
}
The tree draws fine with alpha blended leaves...it's the shadow that shows up as the quad based billboard. I know I have to do some type of test...maybe in the shader. Not too sure. Anyone know how to do this?