/********************************************************************************************

Shader Model 3 Rendering System for FPS Creator

by Mark Blosser

email: mjblosser@gmail.com

website: www.mjblosser.com

-------------------------------------------------------------------

Description:

Shader for segments. Uses lightmapping and normal/spec.

Performs parallax occlusion mapping using the cone-step method.

INVERTED heightmap stored in normal map alpha channel.

Conemap stored in normal map blue channel.

Requires D2/I/N textures. All textures must be in texturebank folder.

*********************************************************************************************/

/**************MATRICES & UNTWEAKABLES *****************************************************/

// shadow mapping

matrix m_mShadow;

float4 m_vCascadeOffset[8];

float4 m_vCascadeScale[8];

int m_nCascadeLevels;

int m_iPCFBlurForLoopStart; // For loop begin value. For a 5x5 Kernal this would be -2.

int m_iPCFBlurForLoopEnd; // For loop end value. For a 5x5 kernel this would be 3.

float m_fMinBorderPadding;

float m_fMaxBorderPadding;

float m_fShadowBiasFromGUI; // A shadow map offset to deal with self shadow artifacts.

float m_fShadowPartitionSize;

float m_fCascadeBlendArea; // Amount to overlap when blending between cascades.

float m_fTexelSize;

float m_fNativeTexelSizeInX;

//float4 m_fCascadeFrustumsEyeSpaceDepthsFloat[2]; // The values along Z that seperate the cascades.

//float4 m_fCascadeFrustumsEyeSpaceDepthsFloat4[8]; // the values along Z that separte the cascades.

float m_fCascadeFrustumsEyeSpaceDepths[8];

float3 m_vLightDir;

float4x4 World : World;

float4x4 WorldInverse : WorldInverse;

float4x4 WorldIT : WorldInverseTranspose;

float4x4 WorldView : WorldView;

float4x4 WorldViewProjection : WorldViewProjection;

float4x4 View : View;

float4x4 ViewInverse : ViewInverse;

float4x4 ViewIT : ViewInverseTranspose;

float4x4 ViewProjection : ViewProjection;

float4x4 Projection : Projection;

float4x4 boneMatrix[60] : BoneMatrixPalette;

float4 eyePos : CameraPosition;

float time : Time;

float sintime : SinTime;

/**************VALUES PROVIDED FROM FPSC - NON TWEAKABLE**************************************/

float4 clipPlane : ClipPlane; //cliplane for water plane

float4 LightSource // SUN LOCATION

< string UIType = "Fixed Light Source";

> = {2500.0f,2500.0f,50000.0f, 1.0f};

float4 AmbiColor : Ambient

< string UIName = "AmbiColor";

> = {0.2f, 0.2f, 0.3f, 0.0f};

float4 AmbiColorOverride //need to divide by 255 in shader

< string UIName = "AmbiColorOverride";

> = {255.0f, 255.0f, 255.0f, 255.0f};

float4 SurfColor : Diffuse

< string UIName = "SurfColor";

> = {1.0f, 1.0f, 1.0f, 1.0f};

//Supports dynamic lights (using CalcLighting function)

float4 g_lights_pos0;

float4 g_lights_pos1;

float4 g_lights_pos2;

float4 g_lights_pos3;

float4 g_lights_atten0;

float4 g_lights_atten1;

float4 g_lights_atten2;

float4 g_lights_atten3;

float4 g_lights_diffuse0;

float4 g_lights_diffuse1;

float4 g_lights_diffuse2;

float4 g_lights_diffuse3;

//SpotFlash Values from FPSC

float4 SpotFlashPos; //SpotFlashPos.w is carrying the spotflash fadeout value

float4 SpotFlashColor; //remember this has not been divided by 255 before being sent from FPSC (I should fix this)

float SpotFlashRange //fixed value that FPSC uses

< string UIName = "SpotFlash Range";

> = {600.00};

//WATER Fog Color

float4 FogColor : Diffuse

< string UIName = "Fog Color";

> = {0.0f, 0.0f, 0.0f, 0.0000001f};

//HUD Fog Color

float4 HudFogColor : Diffuse

< string UIName = "Hud Fog Color";

> = {0.0f, 0.0f, 0.0f, 0.0000001f};

//HUD Fog Distances (near,far,0,0)

float4 HudFogDist : Diffuse

< string UIName = "Hud Fog Dist";

> = {1.0f, 0.0f, 0.0f, 0.0000001f};

//Shader Variables pulled from FPI scripting

float4 ShaderVariables : ShaderVariables

< string UIName = "Shader Variables";

> = {1.0f, 1.0f, 1.0f, 1.0f};

/***************TEXTURES AND SAMPLERS***************************************************/

//For lightmapped ojbects (Lightmap, D, I, N)

texture LightMap : DiffuseMap

<

string Name = "LM.tga";

string type = "2D";

>;

texture DiffuseMap : DiffuseMap

<

string Name = "D.tga";

string type = "2D";

>;

texture NormalMap : DiffuseMap

<

string Name = "N.tga";

string type = "2D";

>;

texture DepthMapTX1 : DiffuseMap

<

string Name = "DEPTH1.tga";

string type = "2D";

>;

texture DepthMapTX2 : DiffuseMap

<

string Name = "DEPTH1.tga";

string type = "2D";

>;

texture DepthMapTX3 : DiffuseMap

<

string Name = "DEPTH1.tga";

string type = "2D";

>;

texture DepthMapTX4 : DiffuseMap

<

string Name = "DEPTH1.tga";

string type = "2D";

>;

//Lightmap texture

sampler2D LightmapSampler = sampler_state

{

Texture = <LightMap>;

MipFilter = LINEAR;

MinFilter = ANISOTROPIC;

MagFilter = LINEAR;

};

//Diffuse Texture _D

sampler2D DiffuseSampler = sampler_state

{

Texture = <DiffuseMap>;

MipFilter = LINEAR;

MinFilter = ANISOTROPIC;

MagFilter = LINEAR;

};

//Effect Texture _N (could be anything here - ill,spec,normal)

sampler2D NormalSampler = sampler_state

{

Texture = <NormalMap>;

MipFilter = LINEAR;

MinFilter = ANISOTROPIC;

MagFilter = LINEAR;

};

//DepthMapForShadow (generated in app)

sampler2D DepthMap1 = sampler_state

{

Texture = <DepthMapTX1>;

};

sampler2D DepthMap2 = sampler_state

{

Texture = <DepthMapTX2>;

};

sampler2D DepthMap3 = sampler_state

{

Texture = <DepthMapTX3>;

};

sampler2D DepthMap4 = sampler_state

{

Texture = <DepthMapTX4>;

};

/************* DATA STRUCTS **************/

// structures for shadow map depth pass

struct IN_Depth

{

float4 Pos:POSITION;

};

struct OUT_Depth

{

float4 OPos:POSITION;

};

// structures for final render

struct appdata

{

float4 Position : POSITION;

float2 UV0 : TEXCOORD0;

float2 UV1 : TEXCOORD1;

float4 Normal : NORMAL;

};

/*data passed to pixel shader*/

struct vertexOutput

{

float4 Position : POSITION;

float2 TexCoord : TEXCOORD0;

float2 TexCoordLM : TEXCOORD1;

float3 LightVec : TEXCOORD2;

float3 WorldNormal : TEXCOORD3;

float4 WPos : TEXCOORD4;

float WaterFog : TEXCOORD5;

float clip : TEXCOORD6;

float4 vTexShadow : TEXCOORD7;

float4 vInterpPos : TEXCOORD8;

float vDepth : TEXCOORD9;

};

/****** helper functions for shadow mapping*****/

void ComputeCoordinatesTransform( in int iCascadeIndex,

in float4 InterpolatedPosition ,

in out float4 vShadowTexCoord ,

in out float4 vShadowTexCoordViewSpace )

{

// Now that we know the correct map, we can transform the world space position of the current fragment

vShadowTexCoord = vShadowTexCoordViewSpace * m_vCascadeScale[iCascadeIndex];

vShadowTexCoord += m_vCascadeOffset[iCascadeIndex];

vShadowTexCoord.x *= m_fShadowPartitionSize; // precomputed (float)iCascadeIndex / (float)CASCADE_CNT

vShadowTexCoord.x += (m_fShadowPartitionSize * (float)iCascadeIndex );

}

void CalculateRightAndUpTexelDepthDeltas ( in float3 vShadowTexDDX,

in float3 vShadowTexDDY,

out float fUpTextDepthWeight,

out float fRightTextDepthWeight )

{

// This function calculates the screen space depth for shadow space texels

// We use the derivatives in X and Y to create a transformation matrix. Because these derivives give us the

// transformation from screen space to shadow space, we need the inverse matrix to take us from shadow space

// to screen space. This new matrix will allow us to map shadow map texels to screen space. This will allow

// us to find the screen space depth of a corresponding depth pixel.

// This is not a perfect solution as it assumes the underlying geometry of the scene is a plane. A more

// accureate way of finding the actual depth would be to do a deferred rendering approach and actually

// sample the depth (ca-ching dudes!)

// Using an offset, or using variance shadow maps is a better approach to reducing these artifacts in most cases.

float2x2 matScreentoShadow = float2x2( vShadowTexDDX.xy, vShadowTexDDY.xy );

float fDeterminant = determinant ( matScreentoShadow );

float fInvDeterminant = 1.0f / fDeterminant;

float2x2 matShadowToScreen = float2x2 (

matScreentoShadow._22 * fInvDeterminant, matScreentoShadow._12 * -fInvDeterminant,

matScreentoShadow._21 * -fInvDeterminant, matScreentoShadow._11 * fInvDeterminant );

float2 vRightShadowTexelLocation = float2( m_fTexelSize, 0.0f );

float2 vUpShadowTexelLocation = float2( 0.0f, m_fTexelSize );

// Transform the right pixel by the shadow space to screen space matrix.

float2 vRightTexelDepthRatio = mul( vRightShadowTexelLocation, matShadowToScreen );

float2 vUpTexelDepthRatio = mul( vUpShadowTexelLocation, matShadowToScreen );

// We can now caculate how much depth changes when you move up or right in the shadow map.

// We use the ratio of change in x and y times the dervivite in X and Y of the screen space

// depth to calculate this change.

fUpTextDepthWeight =

vUpTexelDepthRatio.x * vShadowTexDDX.z

+ vUpTexelDepthRatio.y * vShadowTexDDY.z;

fRightTextDepthWeight =

vRightTexelDepthRatio.x * vShadowTexDDX.z

+ vRightTexelDepthRatio.y * vShadowTexDDY.z;

}

void CalculatePCFPercentLit ( in float4 vShadowTexCoord,

in float fRightTexelDepthDelta,

in float fUpTexelDepthDelta,

in float fBlurRowSize,

out float fPercentLit )

{

// Use PCF to sample the depth map and return a percent lit value.

fPercentLit = 0.0f;

/*

// This loop could be unrolled, and texture immediate offsets could be used if the kernel size were fixed.

// This would be performance improvment.

//for( int x = m_iPCFBlurForLoopStart; x < m_iPCFBlurForLoopEnd; ++x )

{

//for( int y = m_iPCFBlurForLoopStart; y < m_iPCFBlurForLoopEnd; ++y )

{

float depthcompare = vShadowTexCoord.z;

// A very simple solution to the depth bias problems of PCF is to use an offset.

// Unfortunately, too much offset can lead to Peter-panning (shadows near the base of object disappear )

// Too little offset can lead to shadow acne ( objects that should not be in shadow are partially self shadowed ).

depthcompare -= m_fShadowBiasFromGUI;

// Compare the transformed pixel depth to the depth read from the map.

//fPercentLit += g_txShadow.SampleCmpLevelZero( g_samShadow,

// float2(

// vShadowTexCoord.x + ( ( (float) x ) * m_fNativeTexelSizeInX ) ,

// vShadowTexCoord.y + ( ( (float) y ) * m_fTexelSize )

// ),

// depthcompare );

// LEE, Research sampler comparison coommand for DX9 : SampleCmpLevelZero

//fPercentLit += g_txShadow.SampleCmpLevelZero( g_samShadow,

// float2( vShadowTexCoord.x, vShadowTexCoord.y ),

// depthcompare );

//

//fPercentLit += tex2D(DepthMap1,float2(vShadowTexCoord.x, vShadowTexCoord.y));// < Depth ? 0.5f:0.0f);

//}

//}

//fPercentLit /= (float)fBlurRowSize;

*/

}

void CalculateBlendAmountForInterval ( in int iCurrentCascadeIndex,

in out float fPixelDepth,

in out float fCurrentPixelsBlendBandLocation,

out float fBlendBetweenCascadesAmount )

{

// Calculate amount to blend between two cascades and the band where blending will occure.

// We need to calculate the band of the current shadow map where it will fade into the next cascade.

// We can then early out of the expensive PCF for loop.

float fBlendInterval = m_fCascadeFrustumsEyeSpaceDepths[ iCurrentCascadeIndex ];

//if( iNextCascadeIndex > 1 )

int fBlendIntervalbelowIndex = min(0, iCurrentCascadeIndex-1);

fPixelDepth -= m_fCascadeFrustumsEyeSpaceDepths[ fBlendIntervalbelowIndex ];

fBlendInterval -= m_fCascadeFrustumsEyeSpaceDepths[ fBlendIntervalbelowIndex ];

// The current pixel's blend band location will be used to determine when we need to blend and by how much.

fCurrentPixelsBlendBandLocation = fPixelDepth / fBlendInterval;

fCurrentPixelsBlendBandLocation = 1.0f - fCurrentPixelsBlendBandLocation;

// The fBlendBetweenCascadesAmount is our location in the blend band.

fBlendBetweenCascadesAmount = fCurrentPixelsBlendBandLocation / m_fCascadeBlendArea;

}

/*******Vertex Shader***************************/

OUT_Depth VS_Depth(IN_Depth IN)

{

OUT_Depth OUT;

OUT.OPos = mul(IN.Pos,WorldViewProjection);

return OUT;

}

vertexOutput mainVS(appdata IN)

{

vertexOutput OUT;

//float4 tempPos = float4(IN.Position, 1);

float4 worldSpacePos = mul(IN.Position, World);

OUT.WPos = worldSpacePos;

OUT.WorldNormal = normalize(mul(IN.Normal, WorldIT).xyz);

float3 eyeoffset = float3 (10,100,0);

//OUT.LightVec = normalize (eyePos+eyeoffset - worldSpacePos );

OUT.LightVec = normalize (LightSource - worldSpacePos );

OUT.Position = mul(IN.Position, WorldViewProjection);

OUT.TexCoord = IN.UV0 ;

OUT.TexCoordLM = IN.UV1;

// calculate Water FOG colour

float4 cameraPos = mul( worldSpacePos, View );

float fogstrength = cameraPos.z * FogColor.w;

OUT.WaterFog = min(fogstrength,1.0);

// all shaders should send the clip value to the pixel shader (for refr/refl)

OUT.clip = dot(worldSpacePos, clipPlane);

OUT.vTexShadow = float4(0,0,0,0);

OUT.vInterpPos = float4(0,0,0,0);

OUT.vDepth = 0.0f;

// SHADOW MAPPING - transform the shadow texture coordinates for all the cascades.

OUT.vInterpPos = IN.Position;

OUT.vDepth = mul( IN.Position, WorldView ).z;

OUT.vTexShadow = mul( IN.Position, m_mShadow );

return OUT;

}

/****************Framgent Shader*****************/

float4 PS_Depth(OUT_Depth IN) : COLOR

{

return float4(1,1,0,1);//(IN.Depth/LightRange)+0.01f;

}

float4 CalcSpotFlash( float3 worldNormal, float3 worldPos )

{

float4 output = (float4)0.0;

float3 toLight = (SpotFlashPos.xyz - worldPos.xyz);

float3 lightDir = normalize( toLight );

float lightDist = length( toLight );

float MinFalloff = 100; //falloff start distance

float LinearFalloff = 1;

float ExpFalloff = .005; // 1/200

SpotFlashPos.w = clamp(0,1,SpotFlashPos.w -.2);

//classic attenuation - but never actually reaches zero

//float fAtten = 1.0/(MinFalloff + (LinearFalloff*lightDist)); //bit faster linear atten only

float fAtten = 1.0/(MinFalloff + (LinearFalloff*lightDist)+(ExpFalloff*lightDist*lightDist));

//output += max(0,dot( lightDir, worldNormal ) * (SpotFlashColor) *fAtten * (SpotFlashPos.w) );

output += (SpotFlashColor) *fAtten * (SpotFlashPos.w); //don't use normal, faster

//faster attenuation function based on min and max falloff distances

//float fAtten = saturate((500-lightDist)/(500-50)); //50 is minimum distance, 500 is end distance

//output=fAtten*SpotFlashPos.w*SpotFlashColor*.01; //fastest technique - doesn't use Normal

//output = max(0,dot( lightDir, worldNormal )) * fAtten*SpotFlashPos.w*(SpotFlashColor/100);

return output;

}

float4 CalcLighting(float3 Nb, float3 worldPos, float3 Vn, float4 diffusemap,float4 specmap)

{

float4 output = (float4)0.0;

// light 0

float3 toLight = g_lights_pos0.xyz - worldPos;

float lightDist = length( toLight );

//float fAtten = saturate((200-lightDist)/(200-0)); //faster distance-based atten but needs lightrange from FPSC

float fAtten = 1.0/dot( g_lights_atten0, float4(1,lightDist,lightDist*lightDist,0) );

float3 lightDir = normalize( toLight );

//output += max(0,dot( lightDir, Nb ) * g_lights_diffuse0 * fAtten * 1.7); //cheaper-no spec

float3 halfvec = normalize(Vn + lightDir);

float4 lit0 = lit(dot(lightDir,Nb),dot(halfvec,Nb),24);

output+= (lit0.y *g_lights_diffuse0 * fAtten * 1.7*diffusemap) + (lit0.z * g_lights_diffuse0 * fAtten *specmap);

// light 1

toLight = g_lights_pos1.xyz - worldPos;

lightDist = length( toLight );

fAtten = 1.0/dot( g_lights_atten1, float4(1,lightDist,lightDist*lightDist,0) );

lightDir = normalize( toLight );

//output += max(0,dot( lightDir, Nb ) * g_lights_diffuse1 * fAtten * 1.7); //cheaper-no spec

halfvec = normalize(Vn + lightDir);

float4 lit1 = lit(dot(lightDir,Nb),dot(halfvec,Nb),24);

output+= (lit1.y *g_lights_diffuse1 * fAtten * 1.7*diffusemap) + (lit1.z * g_lights_diffuse1 * fAtten *specmap);

// light 2 -maybe optimize by not calculating spec?

toLight = g_lights_pos2.xyz - worldPos;

lightDist = length( toLight );

fAtten = 1.0/dot( g_lights_atten2, float4(1,lightDist,lightDist*lightDist,0) );

lightDir = normalize( toLight );

//output += max(0,dot( lightDir, Nb ) * g_lights_diffuse1 * fAtten * 1.7); //cheaper-no spec

halfvec = normalize(Vn + lightDir);

float4 lit2 = lit(dot(lightDir,Nb),dot(halfvec,Nb),24);

output+= (lit2.y *g_lights_diffuse2 * fAtten * 1.7*diffusemap) + (lit2.z * g_lights_diffuse2 * fAtten *specmap);

// (pixel shader 2.0 runs out of space here)

// // light 2

// toLight = g_lights_pos2.xyz - worldPos;

// lightDist = length( toLight );

// fAtten = 1.0/dot( g_lights_atten2, float4(1,lightDist,lightDist*lightDist,0) );

// lightDir = normalize( toLight );

// output += max(0,dot( lightDir, worldNormal ) * g_lights_diffuse2 * fAtten * 1.7);

// // light 3

// toLight = g_lights_pos3.xyz - worldPos;

// lightDist = length( toLight );

// fAtten = 1.0/dot( g_lights_atten3, float4(1,lightDist,lightDist*lightDist,0) );

// lightDir = normalize( toLight );

// output += max(0,dot( lightDir, worldNormal ) * g_lights_diffuse3 * fAtten * 1.7);

return output;

}

float4 mainPS(vertexOutput IN) : COLOR

{

float4 finalcolor;

clip(IN.clip); // all shaders should receive the clip value

float3 V = (eyePos - IN.WPos);

float3 Vn = normalize(V);

////////TANGENT BASIS CONSTRUCTION FOR CONEMAPPING

// Optimisation 3:

// assume M is orthogonal

float3 p = (IN.WPos);

// get edge vectors of the pixel triangle

float3 dp1 = ddx(p );

float3 dp2 = ddy(p );

float2 duv1 = ddx( IN.TexCoord.xy );

float2 duv2 = ddy( IN.TexCoord.xy );

// solve the linear system

// (not much solving is left going here)

float3x3 M = float3x3( dp1, dp2, cross(dp1,dp2) );

float2x3 invTM = float2x3(cross(M[1],M[2]),cross(M[2],M[0]));

float3 T = mul( float2( duv1.x, duv2.x ), invTM );

float3 B = mul( float2( duv1.y, duv2.y ), invTM );

float3 Nn = normalize(IN.WorldNormal);

// construct tangent frame basis matrix

float3x3 tangentbasis = float3x3( 1*normalize(T), 1*normalize(B),Nn );

////////////////////////////////////////////////////////////////////////////////

///////////////CREATE NEW UV COORDS///////////////////////////////////////

float3 newUVs = float3(IN.TexCoord, 0.0);

float3 rayVec = (IN.WPos- ViewInverse[3]);

rayVec = mul(tangentbasis,rayVec);

rayVec = normalize(rayVec);

rayVec.z = abs(rayVec.z);

float depth = 0.03;

rayVec.xy *= depth;

float dist = length(rayVec.xy);

for( int i=0;i<16; i++ )

{

float4 tex = tex2D(NormalSampler, newUVs.xy);

float height = saturate(tex.w - newUVs.z);

float cone_ratio = tex.z*tex.z;

float stepDist = height * cone_ratio / (cone_ratio + dist);

newUVs += rayVec * stepDist;

}

float4 lightmap = tex2D(LightmapSampler,IN.TexCoordLM); //sample lightmap texture

float4 diffusemap = tex2D(DiffuseSampler,newUVs.xy); //sample D2 texture

float4 specmap =diffusemap.w*2;

float3 Nb = tex2D(NormalSampler,newUVs.xy);

Nb.xy = Nb.xy * 2.0 - 1.0;

//Nb.y = -Nb.y;

Nb.z = sqrt(1.0 - dot(Nb.xy, Nb.xy));

Nb = mul(Nb,tangentbasis);

Nb = normalize(Nb);

float3 Ln = normalize(IN.LightVec); //light vector

float3 Hn = normalize(Vn+Ln); //half-vector

//main lighting equation

float4 lighting = lit((dot(Ln,Nb)),dot(Hn,Nb),24);

float4 dynamiclighting = CalcLighting (Nb, IN.WPos.xyz, Vn, diffusemap,specmap);

float4 spotflashlighting = CalcSpotFlash (IN.WorldNormal, IN.WPos.xyz);

AmbiColor*= (AmbiColorOverride/255); //remember to account for ambient COLOR script changes

//diffuse and ambient contribution

float4 diffuseContrib = diffusemap *lighting.y *lightmap;

//specular light contribution

float4 specContrib = specmap *lighting.z *lightmap ;

//Ambient, Dynamic, and Spotflash contributions + half-strength lightmap

//float4 ambContrib = ((0.5*lightmap) + AmbiColor + dynamiclighting + spotflashlighting) * diffusemap;

float4 ambContrib = (((0.5*lightmap) + AmbiColor + spotflashlighting) * diffusemap) + dynamiclighting;

//float4 ambContrib = (lightmap+AmbiColor+dynamiclighting+spotflashlighting) *diffusemap; //full lightmap overly bright

//float4 ambContrib = (AmbiColor + dynamiclighting + spotflashlighting) * diffusemap; //no extra lightmap (too dark)

float4 result = ambContrib + diffuseContrib;

/*

// per pixel shadow projection (for correct split)

float4 Proj1 = mul(ViewMat,mul(IN.WPos,LightProjMatrix1));

float4 Proj2 = mul(ViewMat,mul(IN.WPos,LightProjMatrix2));

float4 Proj3 = mul(ViewMat,mul(IN.WPos,LightProjMatrix3));

float4 Proj4 = mul(ViewMat,mul(IN.WPos,LightProjMatrix4));

//float Depth=(IN.Proj.z/LightRange);

//float shadowmap=1-(tex2Dproj(DepthMap,IN.Proj+float4(-0.8,-0.8,0,0)) < Depth ? 0.05111f:0.0f); // quick PCF softening

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(0,-0.8,0,0)) < Depth ? 0.05111f:0.0f);

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(0.8,-0.8,0,0)) < Depth ? 0.05111f:0.0f);

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(-0.8,0,0,0)) < Depth ? 0.05111f:0.0f);

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(0,0,0,0)) < Depth ? 0.05111f:0.0f);

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(0.8,0,0,0)) < Depth ? 0.05111f:0.0f);

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(-0.8,0.8,0,0)) < Depth ? 0.05111f:0.0f);

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(0,0.8,0,0)) < Depth ? 0.05111f:0.0f);

//shadowmap=shadowmap-(tex2Dproj(DepthMap,IN.Proj+float4(0.8,0.8,0,0)) < Depth ? 0.05111f:0.0f);

//affect result by any shadows cast on this pixel

//float3 shadowProj1 = Proj1.xyz / Proj1.w;

//float3 shadowProj2 = Proj2.xyz / Proj2.w;

//float3 shadowProj3 = Proj3.xyz / Proj3.w;

//float3 shadowProj4 = Proj4.xyz / Proj4.w;

//bool s1 = all(abs(shadowProj1 - 0.5f) < 0.5f);

//bool s2 = all(abs(shadowProj2 - 0.5f) < 0.5f);

//bool s3 = all(abs(shadowProj3 - 0.5f) < 0.5f);

//bool s4 = all(abs(shadowProj4 - 0.5f) < 0.5f);

result = float4(0,0,0,1);

float Depth;

float shadowmap;

float fPixelDepth = IN.vDepth / 250.0f;

if ( fPixelDepth>0.75f )

{

Depth=(Proj4.z/LightRange);

shadowmap=1-(tex2Dproj(DepthMap4,Proj4+float4(0.0,0.0,0,0)) < Depth ? 0.5f:0.0f);

result = float4(0,1,0,1) * shadowmap;

}

if ( fPixelDepth>=0.5f && fPixelDepth<0.75f )

{

Depth=(Proj3.z/LightRange);

shadowmap=1-(tex2Dproj(DepthMap3,Proj3+float4(0.0,0.0,0,0)) < Depth ? 0.5f:0.0f);

result = float4(1,0,0,1) * shadowmap;

}

if ( fPixelDepth>=0.25f && fPixelDepth<0.5f )

{

Depth=(Proj2.z/LightRange);

shadowmap=1-(tex2Dproj(DepthMap2,Proj2+float4(0.0,0.0,0,0)) < Depth ? 0.5f:0.0f);

result = float4(1,1,0,1) * shadowmap;

}

if ( fPixelDepth>=0.0f && fPixelDepth<0.25f )

{

Depth=(Proj1.z/LightRange);

shadowmap=1-(tex2Dproj(DepthMap1,Proj1+float4(0.0,0.0,0,0)) < Depth ? 0.5f:0.0f);

result = float4(1,1,1,1) * shadowmap;

}

//result = float4(1,1,1,1) * shadowmap;

//result = result * shadowmap;

*/

float4 vShadowMapTextureCoord = 0.0f;

float4 vShadowMapTextureCoord_blend = 0.0f;

float fPercentLit = 0.0f;

float fPercentLit_blend = 0.0f;

float fUpTextDepthWeight=0;

float fRightTextDepthWeight=0;

float fUpTextDepthWeight_blend=0;

float fRightTextDepthWeight_blend=0;

int iBlurRowSize = m_iPCFBlurForLoopEnd - m_iPCFBlurForLoopStart;

iBlurRowSize *= iBlurRowSize;

float fBlurRowSize = (float)iBlurRowSize;

int iCascadeFound = 0;

// The interval based selection technique compares the pixel's depth against the frustum's cascade divisions.

float fCurrentPixelDepth;

fCurrentPixelDepth = IN.vDepth;

// This for loop is not necessary when the frustum is uniformaly divided and interval based selection is used.

// In this case fCurrentPixelDepth could be used as an array lookup into the correct frustum.

int iCurrentCascadeIndex;

float4 vShadowMapTextureCoordViewSpace = IN.vTexShadow;

iCurrentCascadeIndex = 3;

//if ( fCurrentPixelDepth < m_fCascadeFrustumsEyeSpaceDepths[2] ) iCurrentCascadeIndex = 2;

//if ( fCurrentPixelDepth < m_fCascadeFrustumsEyeSpaceDepths[1] ) iCurrentCascadeIndex = 1;

//if ( fCurrentPixelDepth < m_fCascadeFrustumsEyeSpaceDepths[0] ) iCurrentCascadeIndex = 0;

if ( fCurrentPixelDepth < 300 ) iCurrentCascadeIndex = 2;

if ( fCurrentPixelDepth < 80 ) iCurrentCascadeIndex = 1;

if ( fCurrentPixelDepth < 40 ) iCurrentCascadeIndex = 0;

float4 color = 0;

// Repeat text coord calculations for the next cascade.

// The next cascade index is used for blurring between maps.

int iNextCascadeIndex = 1;

iNextCascadeIndex = min ( 8 - 1, iCurrentCascadeIndex + 1 );

float fBlendBetweenCascadesAmount = 1.0f;

float fCurrentPixelsBlendBandLocation = 1.0f;

CalculateBlendAmountForInterval ( iCurrentCascadeIndex, fCurrentPixelDepth,

fCurrentPixelsBlendBandLocation, fBlendBetweenCascadesAmount );

ComputeCoordinatesTransform( iCurrentCascadeIndex,

IN.vInterpPos,

vShadowMapTextureCoord,

vShadowMapTextureCoordViewSpace );

// hack in for now 4AM!!

if ( iCurrentCascadeIndex==0 )

{

result += float4(0.5,0,0,1);//tex2D(DepthMap1,float2(vShadowTexCoord.x, vShadowTexCoord.y));

}

if ( iCurrentCascadeIndex==1 )

{

result += float4(0,0.5,0,1);//tex2D(DepthMap2,float2(vShadowTexCoord.x, vShadowTexCoord.y));

}

if ( iCurrentCascadeIndex==2 )

{

result += float4(0.5,0.5,0,1);//tex2D(DepthMap3,float2(vShadowTexCoord.x, vShadowTexCoord.y));

}

if ( iCurrentCascadeIndex==3 )

{

result += float4(0,0,0.5,1);//tex2D(DepthMap4,float2(vShadowTexCoord.x, vShadowTexCoord.y));

}

//CalculatePCFPercentLit ( vShadowMapTextureCoord, fRightTextDepthWeight,

// fUpTextDepthWeight, fBlurRowSize, fPercentLit );

if( fCurrentPixelsBlendBandLocation < m_fCascadeBlendArea)

{

// the current pixel is within the blend band.

// Repeat text coord calculations for the next cascade.

// The next cascade index is used for blurring between maps.

//if( !SELECT_CASCADE_BY_INTERVAL_FLAG )

//{

// vShadowMapTextureCoord_blend = vShadowMapTextureCoordViewSpace * m_vCascadeScale[iNextCascadeIndex];

// vShadowMapTextureCoord_blend += m_vCascadeOffset[iNextCascadeIndex];

//}

ComputeCoordinatesTransform( iNextCascadeIndex, IN.vInterpPos,

vShadowMapTextureCoord_blend,

vShadowMapTextureCoordViewSpace );

// We repeat the calcuation for the next cascade layer, when blending between maps.

if( fCurrentPixelsBlendBandLocation < m_fCascadeBlendArea)

{

// the current pixel is within the blend band.

CalculatePCFPercentLit ( vShadowMapTextureCoord_blend, fRightTextDepthWeight_blend,

fUpTextDepthWeight_blend, fBlurRowSize, fPercentLit_blend );

fPercentLit = lerp( fPercentLit_blend, fPercentLit, fBlendBetweenCascadesAmount );

// Blend the two calculated shadows by the blend amount.

}

}

// use fPercentLit to apply the shadow :)

//result = lerp( float4(0,0,0,1), result, fPercentLit );

//calculate hud pixel-fog

float4 cameraPos = mul(IN.WPos, View);

float hudfogfactor = saturate((cameraPos.z- HudFogDist.x)/(HudFogDist.y - HudFogDist.x));

//Mix in HUD Fog with final color;

float4 hudfogresult = lerp(result,HudFogColor,hudfogfactor);

//And Finally add in any Water Fog

float4 waterfogresult = lerp(hudfogresult,FogColor,IN.WaterFog);

finalcolor=float4(waterfogresult);

return finalcolor;

}

/****** technique ********************************/

technique DepthMap

{

pass p0

{

VertexShader = compile vs_2_0 VS_Depth();

PixelShader = compile ps_2_0 PS_Depth();

}

}

technique ShadowMapping

{

pass P0

{

// shaders

VertexShader = compile vs_3_0 mainVS();

PixelShader = compile ps_3_0 mainPS();

CullMode = None;

AlphaBlendEnable = FALSE;

AlphaTestEnable = FALSE;

}

}