float4x4 gWorld : WORLD; float4x4 gWorldViewProj : WORLDVIEWPROJECTION; float4x4 gWorldViewProj_Light; float3 gLightDirection = float3(-0.577f, -0.577f, 0.577f); float gShadowMapBias = 0.01f; Texture2D gDiffuseMap; Texture2D gShadowMap; SamplerState samLinear { Filter = MIN_MAG_MIP_LINEAR; AddressU = Wrap;// or Mirror or Clamp or Border AddressV = Wrap;// or Mirror or Clamp or Border }; SamplerState samPoint { Filter = MIN_MAG_MIP_POINT; AddressU = Wrap;// or Mirror or Clamp or Border AddressV = Wrap;// or Mirror or Clamp or Border }; SamplerComparisonState cmpSampler { // sampler state Filter = COMPARISON_MIN_MAG_MIP_LINEAR; AddressU = MIRROR; AddressV = MIRROR; // sampler comparison state ComparisonFunc = LESS_EQUAL; }; RasterizerState Solid { FillMode = SOLID; CullMode = FRONT; }; struct VS_INPUT { float3 pos : POSITION; float3 normal : NORMAL; float2 texCoord : TEXCOORD; }; struct VS_OUTPUT { float4 pos : SV_POSITION; float3 normal : NORMAL; float2 texCoord : TEXCOORD; float4 lPos : TEXCOORD1; }; DepthStencilState EnableDepth { DepthEnable = TRUE; DepthWriteMask = ALL; }; RasterizerState NoCulling { CullMode = NONE; }; //-------------------------------------------------------------------------------------- // Vertex Shader //-------------------------------------------------------------------------------------- VS_OUTPUT VS(VS_INPUT input) { VS_OUTPUT output = (VS_OUTPUT)0; output.pos = mul(float4(input.pos, 1.0), gWorldViewProj); output.normal = normalize(mul(input.normal, (float3x3) gWorld)); output.texCoord = input.texCoord; output.lPos = mul(float4(input.pos, 1.0), gWorldViewProj_Light); return output; } float2 texOffset(int u, int v) { //TODO: return offseted value (our shadow map has the following dimensions: 1280 * 720) float2 shadowMapSize = float2(1280.0f, 720.0f); return float2(u * 1.0f / shadowMapSize.x, v * 1.0f / shadowMapSize.y); } float EvaluateShadowMap(float4 lpos) { // re-homogenize position after interpolation lpos.xyz /= lpos.w; // if position is not visible to the light - don't illuminate it // results in hard light frustum if (lpos.x < -1.0f || lpos.x > 1.0f || lpos.y < -1.0f || lpos.y > 1.0f || lpos.z < 0.0f || lpos.z > 1.0f) return 0.0f; // transform clip space coords to texture space coords (-1:1 to 0:1) lpos.x = lpos.x / 2.0f + 0.5f; lpos.y = lpos.y / -2.0f + 0.5f; //apply shadow map bias lpos.z -= gShadowMapBias; // PCF filtering float sum = 0; for (float y = -1.5; y <= 1.5; y += 1) { for (float x = -1.5; x <= 1.5; x += 1) { sum += gShadowMap.SampleCmpLevelZero(cmpSampler, lpos.xy + texOffset(x, y), lpos.z).r; } } return sum / 16.f; } //-------------------------------------------------------------------------------------- // Pixel Shader //-------------------------------------------------------------------------------------- float4 PS(VS_OUTPUT input) : SV_TARGET { float shadowValue = EvaluateShadowMap(input.lPos); shadowValue = saturate(shadowValue + 0.5f); // make shadows less harsh float4 diffuseColor = gDiffuseMap.Sample( samLinear,input.texCoord ); float3 color_rgb= diffuseColor.rgb; float color_a = diffuseColor.a; //HalfLambert Diffuse :) float diffuseStrength = dot(input.normal, -gLightDirection); diffuseStrength = diffuseStrength * 0.5 + 0.5; diffuseStrength = saturate(diffuseStrength); color_rgb = color_rgb * diffuseStrength; return float4(color_rgb * shadowValue , color_a ); } //-------------------------------------------------------------------------------------- // Technique //-------------------------------------------------------------------------------------- technique11 Default { pass P0 { SetRasterizerState(NoCulling); SetDepthStencilState(EnableDepth, 0); SetVertexShader( CompileShader( vs_4_0, VS() ) ); SetGeometryShader( NULL ); SetPixelShader( CompileShader( ps_4_0, PS() ) ); } }