// when DEBUG_VIEW is defined, texture using the RGB portion of the // shadow pass, to verify that projection is correct //#define DEBUG_VIEW float Script : STANDARDSGLOBAL < string UIWidget = "none"; string ScriptClass = "scene"; string ScriptOrder = "standard"; string ScriptOutput = "color"; string Script = "Technique=Main;"; > = 0.8; // version # float4 ClearColor < string UIWidget = "color"; string UIName = "background"; > = {0,0,0,0.0}; float ClearDepth = 1.0; float4 ShadowClearColor < string UIWidget = "none"; > = {1,1,1,0.0}; /************* "UN-TWEAKABLES," TRACKED BY CPU APPLICATION **************/ float4x4 WorldITXf : WorldInverseTranspose ; float4x4 WorldViewProjXf : WorldViewProjection ; float4x4 WorldXf : World ; float4x4 ViewIXf : ViewInverse ; float4x4 ViewITXf : ViewInverseTranspose ; DECLARE_SHADOW_XFORMS("light0",LampViewXf,LampProjXf,ShadowViewProjXf) DECLARE_SHADOW_BIAS DECLARE_SHADOW_MAPS(ColorShadMap,ColorShadSampler,ShadDepthTarget,ShadDepthSampler) /////////////////////////////////////////////////////////////// /// TWEAKABLES //////////////////////////////////////////////// /////////////////////////////////////////////////////////////// ////////////////////////////////////////////// spot light float3 SpotLightPos : POSITION < string UIName = "Light Posistion"; string Object = "SpotLight"; string Space = "World"; > = {-1.0f, 1.0f, 0.0f}; float3 SpotLightColor : Diffuse < string UIName = "Lamp"; string Object = "SpotLight"; string UIWidget = "Color"; > = {0.8f, 1.0f, 0.4f}; float SpotLightIntensity < string UIName = "Light Intensity"; string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 12; float UIStep = 0.1; > = 1; ////////////////////////////////////////////// ambient light float3 AmbiLightColor : Ambient < string UIName = "Ambient"; > = {0.07f, 0.07f, 0.07f}; ////////////////////////////////////////////// surface attributes float3 SurfColor : Diffuse < string UIName = "Surface"; string UIWidget = "Color"; > = {1.0f, 0.7f, 0.3f}; float Kd < string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 1.5; float UIStep = 0.01; string UIName = "Diffuse"; > = 1.0; float Ks < string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 1.5; float UIStep = 0.01; string UIName = "Specular"; > = 1.0; float SpecExpon : SpecularPower < string UIWidget = "slider"; float UIMin = 1.0; float UIMax = 128.0; float UIStep = 1.0; string UIName = "Specular power"; > = 12.0; //////////////////////////////////////////////////////////////////////////// /// SHADER CODE BEGINS ///////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /*********************************************************/ /*********** pixel shader ********************************/ /*********************************************************/ float4 useShadowPS(ShadowingVertexOutput IN) : COLOR { #ifdef DEBUG_VIEW return tex2Dproj(ColorShadSampler,IN.LProj); // show the RGB render instead #else /*!DEBUG_VIEW */ // // shading... // float3 Nn = normalize(IN.WNormal); float3 Vn = normalize(IN.WView); float falloff = 1.0 / dot(IN.LightVec,IN.LightVec); float3 Ln = normalize(IN.LightVec); float3 Hn = normalize(Vn + Ln); float hdn = dot(Hn,Nn); float ldn = dot(Ln,Nn); float4 litVec = lit(ldn,hdn,SpecExpon); ldn = litVec.y * SpotLightIntensity; float3 ambiContrib = SurfColor * AmbiLightColor; float3 diffContrib = SurfColor*(Kd*ldn * SpotLightColor); float3 specContrib = ((ldn * litVec.z * Ks) * SpotLightColor); float3 result = diffContrib + specContrib; // // shadowing..... // float4 shadowed = tex2Dproj(ShadDepthSampler,IN.LProj); // float cone = tex2Dproj(SpotSamp,IN.LProj); return float4((falloff*shadowed.x*result)+ambiContrib,1); #endif /*!DEBUG_VIEW */ } //////////////////////////////////////////////////////////////////// /// TECHNIQUES ///////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// technique Main < string Script = "Pass=MakeShadow;" "Pass=UseShadow;"; > { pass MakeShadow < string Script = "RenderColorTarget0=ColorShadMap;" "RenderDepthStencilTarget=ShadDepthTarget;" "RenderPort=light0;" "ClearSetColor=ShadowClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { VertexShader = compile vs_2_0 shadowGenVS(WorldXf,WorldITXf,ShadowViewProjXf); ZEnable = true; ZWriteEnable = true; ZFunc = LessEqual; CullMode = None; // no pixel shader } pass UseShadow < string Script = "RenderColorTarget0=;" "RenderDepthStencilTarget=;" "RenderPort=;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { //VertexShader = compile vs_2_0 mainCamVS(); VertexShader = compile vs_2_0 shadowUseVS(WorldXf,WorldITXf, WorldViewProjXf, ShadowViewProjXf,ViewIXf,ShadBiasXf, SpotLightPos); ZEnable = true; ZWriteEnable = true; ZFunc = LessEqual; CullMode = None; PixelShader = compile ps_2_a useShadowPS(); } } /***************************** eof ***/ ]]>; \ sampler SampName = sampler_state { \ texture = ; \ AddressU = AddrMode; \ AddressV = AddrMode; \ MipFilter = LINEAR; \ MinFilter = LINEAR; \ MagFilter = LINEAR; \ }; // // Simple 2D File Textures // // example usage: FILE_TEXTURE_2D(GlowMap,GlowSampler,"myfile.dds") // #define FILE_TEXTURE_2D(TextureName,SamplerName,Diskfile) FILE_TEXTURE_2D_MODAL(TextureName,SamplerName,(Diskfile),WRAP) // // Use this variation of DECLARE_QUAD_TEX() if you want a *scaled* render target // // example usage: DECLARE_SIZED_QUAD_TEX(GlowMap,GlowSampler,"A8R8G8B8",1.0) #define DECLARE_SIZED_QUAD_TEX(TexName,SampName,PixFmt,Multiple) texture TexName : RENDERCOLORTARGET < \ float2 ViewPortRatio = {Multiple,Multiple}; \ int MipLevels = 1; \ string Format = PixFmt ; \ string UIWidget = "None"; \ >; \ sampler SampName = sampler_state { \ texture = ; \ AddressU = CLAMP; \ AddressV = CLAMP; \ MipFilter = POINT; \ MinFilter = LINEAR; \ MagFilter = LINEAR; \ }; // // Use this macro to easily declare typical color render targets // // example usage: DECLARE_QUAD_TEX(ObjMap,ObjSampler,"A8R8G8B8") #define DECLARE_QUAD_TEX(TextureName,SamplerName,PixelFormat) DECLARE_SIZED_QUAD_TEX(TextureName,SamplerName,(PixelFormat),1.0) // // Use this macro to easily declare variable-sized depth render targets // // example usage: DECLARE_SIZED_QUAD_DEPTH_BUFFER(DepthMap,"D24S8",0.5) #define DECLARE_SIZED_QUAD_DEPTH_BUFFER(TextureName,PixelFormat,Multiple) texture TextureName : RENDERDEPTHSTENCILTARGET < \ float2 ViewPortRatio = {Multiple,Multiple}; \ string Format = (PixelFormat); \ string UIWidget = "None"; \ >; // // Use this macro to easily declare typical depth render targets // // example usage: DECLARE_QUAD_DEPTH_BUFFER(DepthMap,"D24S8") #define DECLARE_QUAD_DEPTH_BUFFER(TexName,PixFmt) DECLARE_SIZED_QUAD_DEPTH_BUFFER(TexName,PixFmt,1.0) // // declare exact-sized arbitrary texture // // example usage: DECLARE_SIZED_TEX(BlahMap,BlahSampler,"R32F",128,1) #define DECLARE_SIZED_TEX(Tex,Samp,Fmt,Wd,Ht) texture Tex : RENDERCOLORTARGET < \ float2 Dimensions = { Wd, Ht }; \ string Format = Fmt ; \ string UIWidget = "None"; \ int miplevels=1;\ >; \ sampler Samp = sampler_state { \ texture = ; \ AddressU = CLAMP; \ AddressV = CLAMP; \ MipFilter = NONE; \ MinFilter = LINEAR; \ MagFilter = LINEAR; \ }; // // declare exact-sized square texture, as for shadow maps // // example usage: DECLARE_SQUARE_QUAD_TEX(ShadMap,ShadObjSampler,"A16R16G16B16F",512) #define DECLARE_SQUARE_QUAD_TEX(TexName,SampName,PixFmt,Size) DECLARE_SIZED_TEX(TexName,SampName,(PixFmt),Size,Size) // // likewise for shadow depth targets // // example usage: DECLARE_SQUARE_QUAD_DEPTH_BUFFER(ShadDepth,"D24S8",512) #define DECLARE_SQUARE_QUAD_DEPTH_BUFFER(TextureName,PixelFormat,Size) texture TextureName : RENDERDEPTHSTENCILTARGET < \ float2 Dimensions = { Size, Size }; \ string Format = (PixelFormat) ; \ string UIWidget = "None"; \ >; //////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////// Utility Functions //////// //////////////////////////////////////////////////////////////////////////// // // Scale inputs for use with texture-based lookup tables. A value ranging from zero to one needs // a slight scaling and offset to be sure to point at the centers of the first and last pixels // of that lookup texture. Pass the integer size of the table in TableSize // For now we'll assume that all tables are 1D, square, or cube-shaped -- all axes of equal size // // Cost of this operation for pixel shaders: two const-register // entries and a MAD (one cycle) QUAD_REAL scale_lookup(QUAD_REAL Value,const QUAD_REAL TableSize) { QUAD_REAL scale = ((TableSize - 1.0)/TableSize); QUAD_REAL shift = (0.5 / TableSize); return (scale*Value + shift); } QUAD_REAL2 scale_lookup(QUAD_REAL2 Value,const QUAD_REAL TableSize) { QUAD_REAL scale = ((TableSize - 1.0)/TableSize); QUAD_REAL shift = (0.5 / TableSize); return (scale.xx*Value + shift.xx); } QUAD_REAL3 scale_lookup(QUAD_REAL3 Value,const QUAD_REAL TableSize) { QUAD_REAL scale = ((TableSize - 1.0)/TableSize); QUAD_REAL shift = (0.5 / TableSize); return (scale.xxx*Value + shift.xxx); } // pre-multiply and un-pre-mutliply functions. The precision // of thse operatoions is often limited to 8-bit so don't // always count on them! // The macro value of NV_ALPHA_EPSILON, if defined, is used to // avoid IEEE "NaN" values that may occur when erroneously // dividing by a zero alpha (thanks to Pete Warden @ Apple // Computer for the suggestion in GPU GEMS II) // multiply color by alpha to turn an un-premultipied // pixel value into a premultiplied one QUAD_REAL4 premultiply(QUAD_REAL4 C) { return QUAD_REAL4((C.w*C.xyz),C.w); } #define NV_ALPHA_EPSILON 0.0001 // given a premultiplied pixel color, try to undo the premultiplication. // beware of precision errors QUAD_REAL4 unpremultiply(QUAD_REAL4 C) { #ifdef NV_ALPHA_EPSILON QUAD_REAL a = C.w + NV_ALPHA_EPSILON; return QUAD_REAL4((C.xyz / a),C.w); #else /* ! NV_ALPHA_EPSILON */ return QUAD_REAL4((C.xyz / C.w),C.w); #endif /* ! NV_ALPHA_EPSILON */ } ///////////////////////////////////////////////////////////////////////////////////// // Structure Declaration //////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// struct QuadVertexOutput { QUAD_REAL4 Position : POSITION; QUAD_REAL2 UV : TEXCOORD0; }; ///////////////////////////////////////////////////////////////////////////////////// // Hidden tweakables declared by this .fxh file ///////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////// #ifndef NO_TEXEL_OFFSET #ifdef TWEAKABLE_TEXEL_OFFSET QUAD_REAL QuadTexOffset = 0.5; #else /* !TWEAKABLE_TEXEL_OFFSET */ QUAD_REAL QuadTexOffset < string UIWidget="None"; > = 0.5; #endif /* !TWEAKABLE_TEXEL_OFFSET */ QUAD_REAL2 QuadScreenSize : VIEWPORTPIXELSIZE < string UIWidget="None"; >; #endif /* NO_TEXEL_OFFSET */ //////////////////////////////////////////////////////////// ////////////////////////////////// vertex shaders ////////// //////////////////////////////////////////////////////////// QuadVertexOutput ScreenQuadVS( QUAD_REAL3 Position : POSITION, QUAD_REAL3 TexCoord : TEXCOORD0 ) { QuadVertexOutput OUT; OUT.Position = QUAD_REAL4(Position, 1); #ifdef NO_TEXEL_OFFSET OUT.UV = TexCoord.xy; #else /* NO_TEXEL_OFFSET */ QUAD_REAL2 off = QUAD_REAL2(QuadTexOffset/(QuadScreenSize.x),QuadTexOffset/(QuadScreenSize.y)); OUT.UV = QUAD_REAL2(TexCoord.xy+off); #endif /* NO_TEXEL_OFFSET */ return OUT; } ////////////////////////////////////////////////////// ////////////////////////////////// pixel shaders ///// ////////////////////////////////////////////////////// // add glow on top of model QUAD_REAL4 TexQuadPS(QuadVertexOutput IN,uniform sampler2D InputSampler) : COLOR { QUAD_REAL4 texCol = tex2D(InputSampler, IN.UV); return texCol; } QUAD_REAL4 TexQuadBiasPS(QuadVertexOutput IN,uniform sampler2D InputSampler,QUAD_REAL TBias) : COLOR { QUAD_REAL4 texCol = tex2Dbias(InputSampler, QUAD_REAL4(IN.UV,0,TBias)); return texCol; } ////////////////////////////////////////////////////////////////// /// Macros to define passes within Techniques //////////////////// ////////////////////////////////////////////////////////////////// // older HLSL syntax #define TEX_TECH(TechName,SamplerName) technique TechName { \ pass TexturePass { \ VertexShader = compile vs_2_0 ScreenQuadVS(); \ AlphaBlendEnable = false; ZEnable = false; \ PixelShader = compile ps_2_a TexQuadPS(SamplerName); } } #define TEX_BLEND_TECH(TechName,SamplerName) technique TechName { \ pass TexturePass { \ VertexShader = compile vs_2_0 ScreenQuadVS(); \ ZEnable = false; AlphaBlendEnable = true; \ SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; \ PixelShader = compile ps_2_a TexQuadPS(SamplerName); } } // newer HLSL syntax #define TEX_TECH2(TechName,SamplerName,TargName) technique TechName { \ pass TexturePass < \ string ScriptFunction = "RenderColorTarget0=" (TargName) ";" \ "DrawInternal=Buffer;"; \ > { \ VertexShader = compile vs_2_0 ScreenQuadVS(); \ AlphaBlendEnable = false; ZEnable = false; \ PixelShader = compile ps_2_a TexQuadPS(SamplerName); } } #define TEX_BLEND_TECH2(TechName,SamplerName) technique TechName { \ pass TexturePass < \ string ScriptFunction = "RenderColorTarget0=" (TargName) ";" \ "DrawInternal=Buffer;"; \ > { \ VertexShader = compile vs_2_0 ScreenQuadVS(); \ ZEnable = false; AlphaBlendEnable = true; \ SrcBlend = SrcAlpha; DestBlend = InvSrcAlpha; \ PixelShader = compile ps_2_a TexQuadPS(SamplerName); } } #endif /* _QUAD_FXH */ ////////////// eof /// ]]> ////////////////////////////////////////////// // CONSTANTS ///////////////////////////////// ////////////////////////////////////////////// // Some user-assignable macros -- define their values before including // "shadowMap.fxh" to override these defaults #ifndef SHADOW_SIZE #define SHADOW_SIZE 512 #endif /* !SHADOW_SIZE */ // other formats include "D24X8_SHADOWMAP" and "D16_SHADOWMAP" #ifndef SHADOW_FORMAT #define SHADOW_FORMAT "D24S8_SHADOWMAP" #endif /* SHADOW_FORMAT */ #ifndef MAX_SHADOW_BIAS #define MAX_SHADOW_BIAS 0.00015 #endif /* !MAX_SHADOW_BIAS */ // Define BLACK_SHADOW_PASS before including "shadowMap.fxh" for a SLIGHTLY faster generation // of the "throwaway" RGB buffer created when generating depth maps // #define BLACK_SHADOW_PASS ////////////////////////////////////////////////////// //// VM FUNCTIONS //////////////////////////////////// ////////////////////////////////////////////////////// // #define SHAD_BIT_DEPTH 16 /* only significant for DirectX8 */ float4x4 make_bias_mat(float BiasVal) { float fTexWidth = SHADOW_SIZE; float fTexHeight = SHADOW_SIZE; // float fZScale = pow(2.0,((float)SHAD_BIT_DEPTH))-1.0; // dx8 float fZScale = 1.0; //dx9 float fOffsetX = 0.5f + (0.5f / fTexWidth); float fOffsetY = 0.5f + (0.5f / fTexHeight); float4x4 result = float4x4(0.5f, 0.0f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f, 0.0f, 0.0f, 0.0f, fZScale, 0.0f, fOffsetX, fOffsetY, -BiasVal, 1.0f ); return result; } ////////////////////////////////////////////////////// // DECLARATION MACROS //////////////////////////////// ////////////////////////////////////////////////////// // // Create standard biasing tweakable slider, and create a // static global bias transofrm at the same time // Typical usage: SHADOW_XFORMS("light0",L0ViewXf,L0ProjXf,L0VPXf) // #define DECLARE_SHADOW_BIAS float ShadBias < string UIWidget = "slider"; \ float UIMin = 0; float UIMax = MAX_SHADOW_BIAS; float UIStep = 0.00001; \ string UIName = "Shadow Bias"; > = 0.0001; \ static float4x4 ShadBiasXf = make_bias_mat(ShadBias); // // Declare standard setup for lamp transofrms using "frustrum." // Typical usage: SHADOW_XFORMS("light0",L0ViewXf,L0ProjXf,L0VPXf) // #define DECLARE_SHADOW_XFORMS(LampName,LampView,LampProj,LampViewProj) \ float4x4 LampView : View < string frustum = (LampName); >; \ float4x4 LampProj : Projection < string frustum = (LampName); >; \ static float4x4 LampViewProj = mul(LampView,LampProj); // // Declare standard square_sized shadow map targets. // Typical use: DECLARE_SHADOW_MAPS(ColorShadMap,ColorShadSampler,ShadDepthTarget,ShadDepthSampler) // #define DECLARE_SHADOW_MAPS(CTex,CSamp,DTex,DSamp) \ texture CTex : RENDERCOLORTARGET < float2 Dimensions = {SHADOW_SIZE,SHADOW_SIZE}; \ string Format = "x8b8g8r8" ; string UIWidget = "None"; >; \ sampler CSamp = sampler_state { texture = ; \ AddressU = CLAMP; AddressV = CLAMP; \ MipFilter = NONE; MinFilter = LINEAR; MagFilter = LINEAR; }; \ texture DTex : RENDERDEPTHSTENCILTARGET < float2 Dimensions = {SHADOW_SIZE,SHADOW_SIZE}; \ string format = (SHADOW_FORMAT); string UIWidget = "None"; >; \ sampler DSamp = sampler_state { texture = ; \ AddressU = CLAMP; AddressV = CLAMP; \ MipFilter = NONE; MinFilter = LINEAR; MagFilter = LINEAR; }; ///////////////////////////////////////////////////////// // Structures /////////////////////////////////////////// ///////////////////////////////////////////////////////// /* data from application vertex buffer */ struct ShadowAppData { float3 Position : POSITION; float4 UV : TEXCOORD0; // provided for potential use float4 Normal : NORMAL; // ignored if BLACK_SHADOW_PASS }; // Connector from vertex (no pixel shader needed) for simple shadow struct ShadowVertexOutput { float4 HPosition : POSITION; float4 diff : COLOR0; }; // // Connector from vertex to pixel shader for typical usage. The // "LProj" member is the crucial one for shadow mapping. // struct ShadowingVertexOutput { float4 HPosition : POSITION; float2 UV : TEXCOORD0; float3 LightVec : TEXCOORD1; float3 WNormal : TEXCOORD2; float3 WView : TEXCOORD3; float4 LProj : TEXCOORD4; // current position in light-projection space }; ///////////////////////////////////////////////////////// // Vertex Shaders /////////////////////////////////////// ///////////////////////////////////////////////////////// // // Use this vertex shader for GENERATING shadows. It needs to know some transforms // from your scene, pass them as uniform aguments in the technique like so: // VertexShader = compile vs_2_0 shadowGenVS(WorldXf,WorldITXf,ShadowViewProjXf); // Note that a color is returned because DirectX requires you to render an RGB value in // addition to the depth map. If BLACK_SHADOW_PASS is defined this will just be black, // otherwise it will encode the object-space normal as a color, which can be useful // for debugging. Either way, no pixel shader is required for the shadow-generation pass. // ShadowVertexOutput shadowGenVS(ShadowAppData IN, uniform float4x4 WorldXform, uniform float4x4 WorldITXform, uniform float4x4 ShadowVPXform) { ShadowVertexOutput OUT = (ShadowVertexOutput)0; float4 Po = float4(IN.Position.xyz,(float)1.0); // object coordinates float4 Pw = mul(Po,WorldXform); // "P" in world coordinates float4 Pl = mul(Pw,ShadowVPXform); // "P" in light coords OUT.HPosition = Pl; // screen clipspace coords #ifndef BLACK_SHADOW_PASS // shading this just for amusement in the texture pane float4 N = mul(IN.Normal,WorldITXform); // world coords N = normalize(N); OUT.diff = 0.5 + 0.5 * N; #else /* !BLACK_SHADOW_PASS */ OUT.diff = float4(0,0,0,1); #endif /* !BLACK_SHADOW_PASS */ return OUT; } // // A typical vertex shader for USING shadows. It needs to know some transforms // from your scene, pass them as uniform aguments in the technique like so: // VertexShader = compile vs_2_0 // shadowUseVS(WorldXf,WorldITXf,WorldViewProjXf, // ShadowViewProjXf,ViewIXf,ShadBiasXf, LightPosition); // Note that a color is returned because DirectX requires you to render an RGB value in // addition to the depth map. If BLACK_SHADOW_PASS is defined this will just be black, // otherwise it will encode the object-space normal as a color, which can be useful // for debugging. Either way, no pixel shader is required for the shadow-generation pass. // ShadowingVertexOutput shadowUseVS(ShadowAppData IN, uniform float4x4 WorldXform, uniform float4x4 WorldITXform, uniform float4x4 WVPXform, uniform float4x4 ShadowVPXform, uniform float4x4 ViewIXform, uniform float4x4 BiasXform, uniform float3 LightPosition) { ShadowingVertexOutput OUT = (ShadowingVertexOutput)0; OUT.WNormal = mul(IN.Normal,WorldITXform).xyz; // world coords float4 Po = float4(IN.Position.xyz,(float)1.0); // "P" in object coordinates float4 Pw = mul(Po,WorldXform); // "P" in world coordinates float4 Pl = mul(Pw,ShadowVPXform); // "P" in light coords //OUT.LProj = Pl; // ...for pixel-shader shadow calcs OUT.LProj = mul(Pl,BiasXform); // bias to make texcoord // OUT.WView = normalize(ViewIXform[3].xyz - Pw.xyz); // world coords OUT.HPosition = mul(Po,WVPXform); // screen clipspace coords OUT.UV = IN.UV.xy; // pass-thru OUT.LightVec = LightPosition - Pw.xyz; // world coords return OUT; } #if 0 // // TYPICAL USAGE: This code matches shadRPortHW.fx // /*********************************************************/ /*********** pixel shader ********************************/ /*********************************************************/ // // Typical pixel shader that uses ShadowVertexOutput data -- all you need for the shadow // is one tex2Dproj() call! // // In this shader, when DEBUG_VIEW is defined, show the RGB portion of the // shadow pass, to verify that projection is correct float4 useShadowPS(ShadowingVertexOutput IN) : COLOR { #ifdef DEBUG_VIEW return tex2Dproj(ColorShadSampler,IN.LProj); // show the RGB render instead #else /*!DEBUG_VIEW */ // // shading... // float3 Nn = normalize(IN.WNormal); float3 Vn = normalize(IN.WView); float falloff = 1.0 / dot(IN.LightVec,IN.LightVec); float3 Ln = normalize(IN.LightVec); float3 Hn = normalize(Vn + Ln); float hdn = dot(Hn,Nn); float ldn = dot(Ln,Nn); float4 litVec = lit(ldn,hdn,SpecExpon); ldn = litVec.y * SpotLightIntensity; float cone = normalize(IN.LProj.xyz).z; cone = max((float)0,((cone-CosSpotAng)/(((float)1.0)-CosSpotAng))); float3 ambiContrib = SurfColor * AmbiLightColor; float3 diffContrib = SurfColor*(Kd*ldn * SpotLightColor); float3 specContrib = ((ldn * litVec.z * Ks) * SpotLightColor); float3 result = diffContrib + specContrib; // // shadowing..... // float4 shadowed = tex2Dproj(ShadDepthSampler,IN.LProj); return float4((cone*falloff*shadowed.x*result)+ambiContrib,1); #endif /*!DEBUG_VIEW */ } //////////////////////////////////////////////////////////////////// /// TECHNIQUES ///////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// technique Main < string Script = "Pass=MakeShadow;" "Pass=UseShadow;"; > { pass MakeShadow < string Script = "RenderColorTarget0=ColorShadMap;" "RenderDepthStencilTarget=ShadDepthTarget;" "RenderPort=light0;" "ClearSetColor=ShadowClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { VertexShader = compile vs_2_0 shadCamVS(); ZEnable = true; ZWriteEnable = true; ZFunc = LessEqual; CullMode = None; // no pixel shader } pass UseShadow < string Script = "RenderColorTarget0=;" "RenderDepthStencilTarget=;" "RenderPort=;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { VertexShader = compile vs_2_0 mainCamVS(); ZEnable = true; ZWriteEnable = true; ZFunc = LessEqual; CullMode = None; PixelShader = compile ps_2_a useShadowPS(); } } #endif /* ZERO */ #endif /* _SHADOWMAP_FXH */ /***************************** eof ***/ ]]>