/*********************************************************************NVMH3**** Copyright NVIDIA Corporation 2005 TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED *AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. Perceptually-correct soft shadows, based on a three-step process: 1. Find relevant blockers 2. Estimate penumbra sizes 3. Perform variable-sized percentage-closer filtering For more information, please see the "Percentage-Closer Soft Shadows" talk from GDC 2005. The talk is available at http://developer.nvidia.com/object/gdc_2005_presentations.html $Date: 2005/03/03 $ $Author: Randima (Randy) Fernando $ ******************************************************************************/ // for machines that support FP16 buffers.... #define HAS_FP16 #include "Quad.fxh" half Script : STANDARDSGLOBAL < string UIWidget = "none"; string ScriptClass = "scene"; string ScriptOrder = "postprocess"; string ScriptOutput = "color"; string Script = "Technique=Main;"; > = 0.8; // version # half4 ClearColor < string UIWidget = "color"; string UIName = "background"; > = {0,0,0,0.0}; half ClearDepth = 1.0; #ifdef HAS_FP16 #define FAR 1000.0f #else #define FAR 1.0f #endif half4 ShadowClearColor < string UIWidget = "none"; > = {FAR,FAR,FAR,0.0}; texture floorTexture < string ResourceName = "floor.dds"; >; sampler floorSampler = sampler_state { texture = ; MagFilter = Linear; MinFilter = Linear; MipFilter = Linear; }; /************* "UN-TWEAKABLES," TRACKED BY CPU APPLICATION **************/ half4x4 WorldITXf : WorldInverseTranspose ; half4x4 WorldViewProjXf : WorldViewProjection ; half4x4 WorldXf : World ; half4x4 ViewIXf : ViewInverse ; half4x4 WorldViewITXf : WorldViewInverseTranspose ; half4x4 WorldViewXf : WorldView ; half4x4 ViewXf : View ; half4x4 ViewITXf : ViewInverseTranspose ; half4x4 LampViewXf : View < //string UIWidget="None"; string frustum = "light0"; >; half4x4 LampProjXf : Projection < //string UIWidget="None"; string frustum = "light0"; >; /////////////////////////////////////////////////////////////// /// TWEAKABLES //////////////////////////////////////////////// /////////////////////////////////////////////////////////////// ////////////////////////////////////////////// spot light half3 SpotLightPos : POSITION < string UIName = "Light Posistion"; string Object = "SpotLight"; string Space = "World"; > = {-1.0f, 1.0f, 0.0f}; half3 SpotLightColor : Diffuse < string UIName = "Lamp"; string Object = "SpotLight"; string UIWidget = "Color"; > = {0.8f, 1.0f, 0.4f}; // Parameters for the algorithm half lightSize < string UIWidget = "slider"; half UIMin = 0.010; half UIMax = 0.100; half UIStep = 0.001; string UIName = "Light Size"; > = 0.05f; half ShadBias < string UIWidget = "slider"; half UIMin = 0.0; half UIMax = 10.3; half UIStep = 0.0001; string UIName = "Shadow Bias"; > = 0.01; half sceneScale < string UIWidget = "slider"; half UIMin = 0.1; half UIMax = 100.0; half UIStep = 0.1; string UIName = "Near Plane Factor"; > = 1.0f; // General lighting parameters half SpotLightIntensity < string UIName = "Light Intensity"; string UIWidget = "slider"; half UIMin = 0.0; half UIMax = 2; half UIStep = 0.1; > = 1; half SpotLightCone < string UIWidget = "slider"; half UIMin = 0.0; half UIMax = 90.5; half UIStep = 0.1; string UIName = "Cone Angle"; > = 45.0f; ////////////////////////////////////////////// ambient light half3 AmbiLightColor : Ambient < string UIName = "Ambient"; > = {0.07f, 0.07f, 0.07f}; /////////////// Shadow and Aiming Parameters ////////////////////////////////////////////// surface half3 SurfColor : Diffuse < string UIName = "Surface"; string UIWidget = "Color"; > = {1.0f, 0.7f, 0.3f}; half Kd < string UIWidget = "slider"; half UIMin = 0.0; half UIMax = 1.5; half UIStep = 0.01; string UIName = "Diffuse"; > = 1.0; half Ks < string UIWidget = "slider"; half UIMin = 0.0; half UIMax = 1.5; half UIStep = 0.01; string UIName = "Specular"; > = 1.0; half SpecExpon : SpecularPower < string UIWidget = "slider"; half UIMin = 1.0; half UIMax = 128.0; half UIStep = 1.0; string UIName = "Specular power"; > = 12.0; //////////////////////////////////////////////////////// /// TEXTURES /////////////////////////////////////////// //////////////////////////////////////////////////////// #define SHADOW_SIZE 1024 //#ifdef HAS_FP16 //#define SHADOW_FMT "a16b16g16r16f" #define SHADOW_FMT "r32f" //#else /* !HAS_FP16 */ //#define SHADOW_FMT "a8b8g8r8" //#endif /* !HAS_FP16 */ texture ShadMap : RENDERCOLORTARGET < half2 Dimensions = { SHADOW_SIZE, SHADOW_SIZE }; string Format = (SHADOW_FMT) ; string UIWidget = "None"; >; sampler ShadSampler = sampler_state { texture = ; AddressU = CLAMP; AddressV = CLAMP; MipFilter = NONE; MinFilter = POINT; MagFilter = POINT; }; texture ShadDepthTarget : RENDERDEPTHSTENCILTARGET < half2 Dimensions = { SHADOW_SIZE, SHADOW_SIZE }; string format = "D24S8"; string UIWidget = "None"; >; ///////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// SHADER CODE BEGINS ///////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /* data from application vertex buffer */ struct ShadowAppData { half3 Position : POSITION; half4 UV : TEXCOORD0; half4 Normal : NORMAL; }; // Connector from vertex to pixel shader struct ShadowVertexOutput { half4 HPosition : POSITION; half2 UV : TEXCOORD0; half3 LightVec : TEXCOORD1; half3 WNormal : TEXCOORD2; half3 WView : TEXCOORD3; half4 LP : TEXCOORD4; // current position in light-projection space half2 shadowMapUV : TEXCOORD5; }; // Connector from vertex to pixel shader struct JustShadowVertexOutput { half4 HPosition : POSITION; half4 LP : TEXCOORD0; // current position in light-projection space }; //////////////////////////////////////////////////////////////////////////////// /// Vertex Shaders ///////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// JustShadowVertexOutput shadVS(ShadowAppData IN, uniform half4x4 ShadowViewProjXf // typically created from aimShadowProjXf() ) { JustShadowVertexOutput OUT = (JustShadowVertexOutput)0; half4 Po = half4(IN.Position.xyz,(half)1.0); // object coordinates half4 Pw = mul(Po,WorldXf); // "P" in world coordinates half4 Pl = mul(Pw,ShadowViewProjXf); // "P" in light coords OUT.LP = Pl; // view coords (also lightspace projection coords in this case) OUT.HPosition = Pl; // screen clipspace coords return OUT; } // from scene camera POV ShadowVertexOutput mainCamVS(ShadowAppData IN, uniform half4x4 ShadowViewProjXf) { ShadowVertexOutput OUT = (ShadowVertexOutput)0; OUT.WNormal = mul(IN.Normal,WorldITXf).xyz; // world coords half4 Po = half4(IN.Position.xyz,(half)1.0); // "P" in object coordinates half4 Pw = mul(Po,WorldXf); // "P" in world coordinates half4 Pl = mul(Pw,ShadowViewProjXf); // "P" in light coords Pl.z -= ShadBias; // factor in bias here to save pixel shader work OUT.LP = Pl; // ...for pixel-shader shadow calcs OUT.WView = normalize(ViewIXf[3].xyz - Pw.xyz); // world coords OUT.HPosition = mul(Po,WorldViewProjXf); // screen clipspace coords OUT.UV = IN.UV.xy; // pass-thru OUT.LightVec = SpotLightPos - Pw.xyz; // world coords OUT.shadowMapUV = half2(.5,-.5)*(Pl.xy)/Pl.w + half2(.5,.5); return OUT; } /*********************************************************/ /*********** pixel shader ********************************/ /*********************************************************/ half4 shadPS(JustShadowVertexOutput IN) : COLOR { return half4(IN.LP.zzz,1); } // ------------------------------------- // STEP 1: Search for potential blockers // ------------------------------------- half findBlocker(half2 uv, half4 LP, uniform sampler ShadowMap, uniform half bias, half searchWidth, half numSamples) { // divide filter width by number of samples to use half stepSize = 2 * searchWidth / numSamples; // compute starting point uv coordinates for search uv = uv - half2(searchWidth, searchWidth); // reset sum to zero half blockerSum = 0; half receiver = LP.z; half blockerCount = 0; // iterate through search region and add up depth values for (int i=0; i 0.01) penumbra = 0.01; shadowed = PCF_Filter(uv, IN.LP, ShadSampler, ShadBias, penumbra, samples); // If no blocker was found, just return 1.0 // since the point isn't occluded if (blocker == 0) shadowed = 1.0; shadowed = max(shadowed, 0.25); // Visualize lighting and shadows half4 floorColor = tex2D(floorSampler, IN.UV*2); //return shadowed; return float4((shadowed*result*floorColor),1); } //////////////////////////////////////////////////////////////////// /// TECHNIQUES ///////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// technique Main < string Script = "Pass=MakeShadow;" "Pass=UseShadow;"; > { pass MakeShadow < string Script = "RenderColorTarget0=ShadMap;" "RenderDepthStencilTarget=ShadDepthTarget;" "RenderPort=light0;" "ClearSetColor=ShadowClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { VertexShader = compile vs_3_0 shadVS(mul(LampViewXf,LampProjXf)); ZEnable = true; ZWriteEnable = true; ZFunc = LessEqual; CullMode = None; PixelShader = compile ps_3_0 shadPS(); } pass UseShadow < string Script = "RenderColorTarget0=;" "RenderDepthStencilTarget=;" "RenderPort=;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { VertexShader = compile vs_3_0 mainCamVS(mul(LampViewXf,LampProjXf)); ZEnable = true; ZWriteEnable = true; ZFunc = LessEqual; CullMode = None; PixelShader = compile ps_3_0 useShadowPS(cos(radians(SpotLightCone))); } } /***************************** eof ***/