shaders/ShadowMapping/Shaders/ShadowMapPS.cg

shaders/ShadowMapping/Shaders/ShadowMapPS.cg
/***************************************************************************************
Autodesk(R) Open Reality(R) Samples
(C) 2009 Autodesk, Inc. and/or its licensors
All rights reserved.
AUTODESK SOFTWARE LICENSE AGREEMENT
Autodesk, Inc. licenses this Software to you only upon the condition that
you accept all of the terms contained in the Software License Agreement ("Agreement")
that is embedded in or that is delivered with this Software. By selecting
the "I ACCEPT" button at the end of the Agreement or by copying, installing,
uploading, accessing or using all or any portion of the Software you agree
to enter into the Agreement. A contract is then formed between Autodesk and
either you personally, if you acquire the Software for yourself, or the company
or other legal entity for which you are acquiring the software.
AUTODESK, INC., MAKES NO WARRANTY, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR
PURPOSE REGARDING THESE MATERIALS, AND MAKES SUCH MATERIALS AVAILABLE SOLELY ON AN
"AS-IS" BASIS.
IN NO EVENT SHALL AUTODESK, INC., BE LIABLE TO ANYONE FOR SPECIAL, COLLATERAL,
INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF PURCHASE
OR USE OF THESE MATERIALS. THE SOLE AND EXCLUSIVE LIABILITY TO AUTODESK, INC.,
REGARDLESS OF THE FORM OF ACTION, SHALL NOT EXCEED THE PURCHASE PRICE OF THE
MATERIALS DESCRIBED HEREIN.
Autodesk, Inc., reserves the right to revise and improve its products as it sees fit.
Autodesk and Open Reality are registered trademarks or trademarks of Autodesk, Inc.,
in the U.S.A. and/or other countries. All other brand names, product names, or
trademarks belong to their respective holders.
GOVERNMENT USE
Use, duplication, or disclosure by the U.S. Government is subject to restrictions as
set forth in FAR 12.212 (Commercial Computer Software-Restricted Rights) and
DFAR 227.7202 (Rights in Technical Data and Computer Software), as applicable.
Manufacturer is Autodesk, Inc., 10 Duke Street, Montreal, Quebec, Canada, H3C 2L7.
***************************************************************************************/
// MAX_LIGHT_COUNT should be defined at compilation of the Cg
// ENABLE_SHADOWS should be defined in order to enable shadows
uniform float4 MaterialEmission;
uniform float4 MaterialAmbient;
uniform float4 MaterialDiffuse;
uniform float4 MaterialSpecular;
uniform float4 GlobalAmbientLight;
// Lighting data
uniform int LightCount;
uniform float4 LightPositions[MAX_LIGHT_COUNT];
uniform float4 LightDirections[MAX_LIGHT_COUNT];
uniform float4 LightColors[MAX_LIGHT_COUNT];
uniform float4 LightAttenuations[MAX_LIGHT_COUNT];
// For specular ..
uniform float3 EyePosition;
// Texture stuff.
sampler2D ColorTexture;
sampler2D NormalMap;
uniform int ColorTextureValid;
uniform int NormalMapValid;
// Shadow
#ifdef ENABLE_SHADOWS
sampler2D ShadowMap;
uniform int ShadowCaster;
uniform int ShadowMapSize;
uniform int ShadowPCFKernelSize;
uniform float ShadowPCFKernelStep;
#endif
struct PixelIn
{
float3 Normal : TEXCOORD0;
float4 WorldPos : TEXCOORD1;
float3 UVColor : TEXCOORD2;
float3 UVNormal : TEXCOORD3;
float3 Tangent : TEXCOORD4;
float3 Binormal : TEXCOORD5;
#ifdef ENABLE_SHADOWS
float4 Shadow : TEXCOORD6;
#endif
};
struct PixelOut
{
float4 color : COLOR0;
};
#ifdef ENABLE_SHADOWS
float TestShadow(float shadowModifier, float3 coord)
{
if( tex2D( ShadowMap, coord.xy ).r < coord.z )
shadowModifier += 1.0f;
return shadowModifier;
}
float ComputePCFLine(float shadowModifier, float3 coord)
{
for( int i = 0; i < ShadowPCFKernelSize; ++i )
{
shadowModifier = TestShadow(shadowModifier, coord);
coord.x += ShadowPCFKernelStep;
}
return shadowModifier;
}
float ComputePCF(float3 coord)
{
coord.xy -= float2(float(ShadowPCFKernelSize / 2) * ShadowPCFKernelStep);
float shadowModifier = 0.0f;
for( int y = 0; y < ShadowPCFKernelSize; ++y )
{
shadowModifier = ComputePCFLine(shadowModifier, coord);
coord.y += ShadowPCFKernelStep;
}
return shadowModifier / float(ShadowPCFKernelSize * ShadowPCFKernelSize);
}
float ComputePCF3x3Line(float shadowModifier, float mapScale, float x, float y, float depth)
{
shadowModifier = TestShadow(shadowModifier, float3(x - mapScale, y, depth));
shadowModifier = TestShadow(shadowModifier, float3(x , y, depth));
shadowModifier = TestShadow(shadowModifier, float3(x + mapScale, y, depth));
return shadowModifier;
}
float ComputePCF3x3(float3 coord)
{
const float kMapScale = 1.0f / ShadowMapSize;
float shadowModifier = 0.0f;
shadowModifier = ComputePCF3x3Line(shadowModifier, kMapScale, coord.x, coord.y - kMapScale, coord.z);
shadowModifier = ComputePCF3x3Line(shadowModifier, kMapScale, coord.x, coord.y , coord.z);
shadowModifier = ComputePCF3x3Line(shadowModifier, kMapScale, coord.x, coord.y + kMapScale, coord.z);
return shadowModifier / 9.0f;
}
float ComputeShadow(float4 shadow)
{
// Do shadow calculation, with a pcf to get a smoother shadow ....
return 1.0f - ComputePCF((shadow.xyz / shadow.w) * 0.5f + float3(0.5f));
}
#endif
float3 ComputeLight( int index, float3 fposition, float3 fnormal, float3x3 fTangentMat
#ifdef ENABLE_SHADOWS
, float4 shadow
#endif
)
{
// First step is simple n dot l
// Get the light direction accordingly
// position - lightpos for point/spot
// or direction for directionals
float3 lightDiff = fposition.xyz - LightPositions[index].xyz;
float3 lightDir;
if( LightColors[index].w > 0.0f )
{
lightDir = normalize( lightDiff );
}
else
{
lightDir = normalize( LightDirections[index].xyz );
}
if ( NormalMapValid )
{
lightDir = mul(fTangentMat, lightDir);
}
// N dot L
float ndotl = saturate( dot( fnormal, -lightDir ) );
// Diffuse contribution
float3 diffuse = MaterialDiffuse.xyz * LightColors[index].xyz * ndotl;
// Specular contribution
float3 eyeVec = normalize( EyePosition - fposition );
if ( NormalMapValid )
{
eyeVec = mul(fTangentMat, eyeVec);
}
float3 halfVec = (eyeVec - lightDir)/2.0f; // view + light
float3 specular = MaterialSpecular.xyz * pow( saturate( dot( fnormal, halfVec ) ), MaterialSpecular.w );
// Ok, calculate attenuation
float d = length( lightDiff );
float attenuation = LightAttenuations[index].w/( LightAttenuations[index].x + d*(LightAttenuations[index].y + d*LightAttenuations[index].z));
// And last but not least, figure out the spot factor ...
float spotFactor = 1.0f;
if( LightPositions[index].w )
{
float3 spotLigthDir = LightDirections[index].xyz;
if ( NormalMapValid )
{
spotLigthDir = mul(fTangentMat, spotLigthDir);
}
spotFactor = saturate( (dot( -lightDir, -spotLigthDir ) - LightDirections[index].w) / (1 - LightDirections[index].w) );
}
#ifdef ENABLE_SHADOWS
if ( index == ShadowCaster )
{
float shade = ComputeShadow(shadow);
float dimming = 0.1f;
diffuse *= dimming + (1.0f - dimming) * shade;
specular *= shade;
}
#endif
return saturate( ( spotFactor * ( attenuation * ( diffuse + specular ) ) ) );
}
PixelOut main(PixelIn In)
{
PixelOut Out;
// Setup color
float4 color;
// Set the alpha from the diffuse material.
color.w = MaterialDiffuse.w;
// Ok .. start with emissive contribution from material
color.xyz = MaterialEmission.xyz;
// Now do ambient lighting
color.xyz += MaterialAmbient.xyz * GlobalAmbientLight.xyz;
// Okay, do all of the lights
if ( LightCount )
{
float3 position = In.WorldPos.xyz;
// Read normal in and setup normal map stuff
float3 normal = normalize(In.Normal);
float3x3 tangentMatrix;
if ( NormalMapValid )
{
// Create tangent space matrix
tangentMatrix = float3x3( normalize(In.Tangent.xyz),
normalize(In.Binormal.xyz),
normal );
normal = (tex2D( NormalMap, In.UVNormal ).xyz - float3(0.5f,0.5f,0.5f)) * float3(2.0f,2.0f,2.0f);
}
for( int i = 0; i < MAX_LIGHT_COUNT; i++ )
{
if ( i < LightCount )
{
float3 light = ComputeLight( i, position, normal, tangentMatrix
#ifdef ENABLE_SHADOWS
, In.Shadow
#endif
);
color.xyz += light;
}
}
color.xyz = saturate( color.xyz );
}
else
{
// No light? Set the color from the diffuse material.
color.xyz += MaterialDiffuse.xyz;
}
color.xyz = saturate( color.xyz );
// Get texture contribution color
if( ColorTextureValid )
{
//color *= tex2D( ColorTexture, In.UVColor );
}
// Return calculated color
Out.color = color;
return Out;
}