float Script : STANDARDSGLOBAL < string UIWidget = "none"; string ScriptClass = "scene"; string ScriptOrder = "standard"; string ScriptOutput = "color"; string Script = "Technique=main;"; > = 0.8; float4 ClearColor < string UIWidget = "none"; // "color"; string UIName = "background"; > = {0,0,0,0.0}; float4 White < string UIWidget = "none"; > = {1,1,1,0.0}; float ClearDepth = 1.0; DECLARE_QUAD_TEX(WhiteMap,WhiteSampler,"A8B8G8R8") DECLARE_QUAD_TEX(SceneMap,SceneSampler,"A8B8G8R8") DECLARE_QUAD_TEX(BlurMap,BlurSampler,"A8B8G8R8") DECLARE_QUAD_TEX(GrayDepthMap,GrayDepthSampler,"A8B8G8R8") DECLARE_QUAD_DEPTH_BUFFER(DepthMap,"D24S8") /********* tweakables ********************/ float4x4 WorldViewProj : WorldViewProjection < string UIWidget="None"; >; float3 SurfColor < string UIWidget = "color"; string UIName = "Surface"; > = {1,.9,.8}; float4 AmbiColor < string UIWidget = "color"; string UIName = "Ambient"; > = {.1,.1,.2,0.0}; float4 LightPos : Position < string Object = "PointLight"; string Space = "World"; > = {100.0f, 100.0f, 100.0f, 0.0f}; float GeomInset < string UIWidget = "slider"; float UIMin = 0; float UIMax = 0.02; float UIStep = 0.001; string UIName = "Geometric Inset"; > = 0.003; float ShadowExtrudeDist < string UIName = "Shadow Volume Extrusion Distance"; string UIWidget = "slider"; float UIMin = 1.0; float UIMax = 100.0; float UIStep = 0.1; > = 100.0f; float Dens < string UIName = "Shadow Density"; string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 1.0; float UIStep = 0.001; > = 0.5f; float DThresh < string UIName = "Depth Threshhold"; string UIWidget = "slider"; float UIMin = 0.0; float UIMax = 0.3; float UIStep = 0.001; > = 0.2f; float Near < string UIName = "Depth Near"; string UIWidget = "slider"; float UIMin = 1.0; float UIMax = 10.0; float UIStep = 0.1; > = 0.2f; float Far < string UIName = "Depth Far"; string UIWidget = "slider"; float UIMin = 2.0; float UIMax = 20.0; float UIStep = 0.1; > = 20.0f; float Blur < string UIName = "Blur Width (in Pixels)"; string UIWidget = "slider"; float UIMin = 1.0; float UIMax = 4.0; float UIStep = 0.1; > = 1.5f; /************ structs and connections *****************************/ struct appdata { float4 Position : POSITION; float2 UV : TEXCOORD0; float3 Normal : NORMAL; }; /* data passed from vertex shader to pixel shader */ struct SimpleVertexColorOutput { float4 HPosition : POSITION; float4 diffCol : COLOR0; }; /*********** vertex shader ******/ SimpleVertexColorOutput extrudeVS( appdata IN) { SimpleVertexColorOutput OUT; // Create normalized vector from vertex to light float4 Lvec = normalize( IN.Position - LightPos ); // N dot L to decide if point should be moved away // from the light to extrude the volume float ldn = dot( -Lvec.xyz, IN.Normal.xyz ); ////////////////////////////////////////////////////////// // Inset the position along the normal vector direction // This moves the shadow volume points inside the model // slightly to minimize poping of shadowed areas as // each facet comes in and out of shadow. float4 inset_pos = float4(((IN.Position.xyz - (IN.Normal * GeomInset)).xyz),IN.Position.w); // scale the vector from light to vertex float4 extrusion_vec = Lvec * ShadowExtrudeDist; // if ldn < 0 then the vertex faces away from the light, so // move it. It will be moved along the direction from // light to vertex to extrude the shadow volume. // Consts_0512 = { 0.0f, 0.5f, 1.0f, 2.0f }; // So this does toggle = N dot L < 0 ? 1.0 : 0.0 float toggle = (float) (ldn < 0.0); // Move the back-facing shadow volume points float4 new_position = extrusion_vec*toggle + inset_pos; OUT.HPosition = mul( new_position, WorldViewProj); //////////////////////////////////////////////////////// OUT.diffCol = float4(IN.UV.xy,0,1); // OUT.TexCoord0 = IN.TexCoord0.xyyy; return( OUT ); } SimpleVertexColorOutput backingVS(appdata IN) { SimpleVertexColorOutput OUT; OUT.HPosition = mul(IN.Position, WorldViewProj); OUT.diffCol = AmbiColor; return( OUT ); } SimpleVertexColorOutput simpleVS( appdata IN) { SimpleVertexColorOutput OUT; float4 Lvec = normalize( IN.Position - LightPos ); float ldn = abs(dot(-Lvec.xyz, IN.Normal.xyz )); OUT.HPosition = mul( IN.Position, WorldViewProj ); OUT.diffCol = AmbiColor + float4((ldn*SurfColor),1); return( OUT ); } SimpleVertexColorOutput whiteVS( appdata IN) { SimpleVertexColorOutput OUT; float4 Lvec = normalize( IN.Position - LightPos ); float ldn = abs(dot(-Lvec.xyz, IN.Normal.xyz )); OUT.HPosition = mul( IN.Position, WorldViewProj ); OUT.diffCol = float4(1,1,1,1); return( OUT ); } SimpleVertexColorOutput deepGrayVS( appdata IN) { SimpleVertexColorOutput OUT; float4 Lvec = normalize( IN.Position - LightPos ); float ldn = abs(dot(-Lvec.xyz, IN.Normal.xyz )); float4 Ph = mul( IN.Position, WorldViewProj ); OUT.HPosition = Ph; float d = (Ph.z-Near)/(Far-Near); d = 1.0 - (DThresh + (1.0-DThresh)*abs(d)); OUT.diffCol = d.xxxx; return(OUT); } /// Blur //////////////////////////////////////// // // This is a very simple blur, four extra samples, one in each cardinal direction // struct BlurVertexOutput { QUAD_REAL4 Position : POSITION; QUAD_REAL2 NU : TEXCOORD0; QUAD_REAL2 CC : TEXCOORD1; QUAD_REAL2 PU : TEXCOORD2; QUAD_REAL2 NV : TEXCOORD3; QUAD_REAL2 PV : TEXCOORD4; }; BlurVertexOutput DepthBlurVS( QUAD_REAL3 Position : POSITION, QUAD_REAL3 TexCoord : TEXCOORD0 ) { BlurVertexOutput OUT=(BlurVertexOutput)0; QUAD_REAL2 center; OUT.Position = QUAD_REAL4(Position, 1); QUAD_REAL2 texelSize = QUAD_REAL2((1.0/QuadScreenSize.x),(1.0/QuadScreenSize.y)); QUAD_REAL2 blurSize = Blur * texelSize; // the NO_TEXEL_OFFSET macro is part of "Quad.fxh" #ifdef NO_TEXEL_OFFSET center = TexCoord.xy; #else /* NO_TEXEL_OFFSET */ QUAD_REAL2 off = QuadTexOffset * texelSize; QUAD_REAL2(QuadTexOffset/(QuadScreenSize.x),QuadTexOffset/(QuadScreenSize.y)); center = QUAD_REAL2(TexCoord.xy+off); #endif /* NO_TEXEL_OFFSET */ OUT.CC = center; OUT.NU = QUAD_REAL2(center.x-blurSize.x,center.y); OUT.PU = QUAD_REAL2(center.x+blurSize.x,center.y); OUT.NV = QUAD_REAL2(center.x,center.y-blurSize.y); OUT.PV = QUAD_REAL2(center.x,center.y+blurSize.y); return OUT; } // blur, but only if the beighboring pixels have about the same depth // (and thus are part of the same geometric entity) -- otherwise leave the // edge sharp QUAD_REAL4 DepthBlurPS(BlurVertexOutput IN) : COLOR { QUAD_REAL dcc = tex2D(GrayDepthSampler, IN.CC).x; QUAD_REAL scc = tex2D(WhiteSampler, IN.CC).x; QUAD_REAL dnu = tex2D(GrayDepthSampler, IN.NU).x; QUAD_REAL snu = tex2D(WhiteSampler, IN.NU).x; QUAD_REAL dpu = tex2D(GrayDepthSampler, IN.PU).x; QUAD_REAL spu = tex2D(WhiteSampler, IN.PU).x; QUAD_REAL dnv = tex2D(GrayDepthSampler, IN.NV).x; QUAD_REAL snv = tex2D(WhiteSampler, IN.NV).x; QUAD_REAL dpv = tex2D(GrayDepthSampler, IN.PV).x; QUAD_REAL spv = tex2D(WhiteSampler, IN.PV).x; float ac = 1.0; float as = scc; if ((dnu!=0)&&(abs(dnu-dcc)) < DThresh) { as += snu; ac += 1.0; } if ((dpu!=0)&&(abs(dpu-dcc)) < DThresh) { as += spu; ac += 1.0; } if ((dnv!=0)&&(abs(dnv-dcc)) < DThresh) { as += snv; ac += 1.0; } if ((dpv!=0)&&(abs(dpv-dcc)) < DThresh) { as += spv; ac += 1.0; } as = as / ac; as = 1.0 - (Dens*(1.0-as)); return float4(as.xxxx); } ///// final-output pixel mixer ////// QUAD_REAL4 shadowMixPS(QuadVertexOutput IN) : COLOR { QUAD_REAL4 scene = tex2D(SceneSampler, IN.UV); QUAD_REAL4 shad = tex2D(BlurSampler, IN.UV); return (shad*scene); } /*************** techniques *******************/ technique main < string Script = "Pass=DepthToGrayMap;" "Pass=ColorSceneToMap;" "Pass=StencilZPass;" "Pass=StencilBackPass;" "Pass=StencilFrontPass;" "Pass=DrawStencilShadowOnWhite;" "Pass=ScreenSpaceShadowBlur;" "Pass=FinalComposite;"; > { pass DepthToGrayMap < string Script = "RenderColorTarget0=GrayDepthMap;" "RenderDepthStencilTarget=DepthMap;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { VertexShader = compile vs_1_0 deepGrayVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; StencilEnable = false; } pass ColorSceneToMap < string Script = "RenderColorTarget0=SceneMap;" "RenderDepthStencilTarget=DepthMap;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=geometry;"; > { VertexShader = compile vs_1_0 simpleVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; StencilEnable = false; } pass StencilZPass < string Script = "RenderColorTarget0=WhiteMap;" "RenderDepthStencilTarget=DepthMap;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Stencil;" "Clear=Depth;" // no clear "Draw=geometry;"; > { VertexShader = compile vs_1_0 backingVS(); ZEnable = true; ZWriteEnable = true; CullMode = None; StencilEnable = false; } pass StencilBackPass < string Script = "RenderColorTarget0=WhiteMap;" "RenderDepthStencilTarget=DepthMap;" // no clear "Draw=geometry;"; > { VertexShader = compile vs_1_1 extrudeVS(); ZEnable = true; ZWriteEnable = true; ZFunc = lessequal; CullMode = CW; StencilEnable = True; StencilPass = Keep; StencilFail = Keep; StencilZFail = IncrSat; StencilFunc = Always; ColorWriteEnable = 0; } pass StencilFrontPass < string Script = "RenderColorTarget0=WhiteMap;" "RenderDepthStencilTarget=DepthMap;" // no clear "Draw=geometry;"; > { VertexShader = compile vs_1_1 extrudeVS(); ZEnable = true; ZWriteEnable = true; ZFunc = lessequal; CullMode = CCW; // TwoSidedStencilMode = false; // needed? StencilEnable = True; StencilPass = Keep; StencilFail = Keep; StencilZFail = DecrSat; StencilFunc = Always; ColorWriteEnable = 0; } pass DrawStencilShadowOnWhite < string Script = "RenderColorTarget0=WhiteMap;" "RenderDepthStencilTarget=DepthMap;" "ClearSetColor=ClearColor;" "Clear=Color;" "Draw=geometry;"; > { VertexShader = compile vs_1_1 whiteVS(); ZEnable = true; ZWriteEnable = true; ZFunc = lessequal; CullMode = None; StencilEnable = True; StencilPass = Keep; StencilZFail = Keep; StencilFail = Keep; StencilRef = 0; StencilFunc = Equal; } pass ScreenSpaceShadowBlur < string Script = "RenderColorTarget0=BlurMap;" "RenderDepthStencilTarget=DepthMap;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=buffer;"; > { VertexShader = compile vs_1_1 DepthBlurVS(); ZEnable = false; CullMode = None; StencilEnable = false; AlphaBlendEnable = false; PixelShader = compile ps_2_a DepthBlurPS(); } pass FinalComposite < string Script = "RenderColorTarget0=;" "RenderDepthStencilTarget=;" "ClearSetColor=ClearColor;" "ClearSetDepth=ClearDepth;" "Clear=Color;" "Clear=Depth;" "Draw=buffer;"; > { VertexShader = compile vs_1_1 ScreenQuadVS(); ZEnable = false; // ZWriteEnable = true; CullMode = None; StencilEnable = false; AlphaBlendEnable = false; PixelShader = compile ps_2_a shadowMixPS(); } } /********************************** 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 /// ]]>