//------- Constants -------- float4x4 World : WORLD; float4x4 View : VIEW; float4x4 Proj : PROJECTION; float2 UVScale; bool NormalMapped; float4 LightDirection : LIGHT_DIRECTION; float4 CameraForward : VIEW_FORWARD; //Material Properties float4 AmbientColor : AMBIENT_COLOR; float AmbientPower : AMBIENT_POWER; float4 SpecularColor : SPECULAR_COLOR; float SpecularPower : SPECULAR_POWER; float4 DiffuseColor : DIFFUSE_COLOR; //Material Properties //Refraction bool Refraction; float WaterHeight; float WaterViewDepth; float4 DeepWaterColor; //Refraction //Edit Mode float3 CursorColor = {0, 0.1f, 0.4f}; float3 EditPosition; float EditRadius; bool EditMode; //Edit Mode texture DirtTexture; texture GrassTexture; texture RockTexture; texture SnowTexture; texture DirtTextureN; texture GrassTextureN; texture RockTextureN; texture SnowTextureN; sampler DirtTextureSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; sampler GrassTextureSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; sampler RockTextureSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; sampler SnowTextureSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; sampler DirtTextureNSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; sampler GrassTextureNSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; sampler RockTextureNSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; sampler SnowTextureNSampler = sampler_state { Texture = ; Magfilter = LINEAR; Minfilter = LINEAR; Mipfilter = LINEAR; AddressU = Wrap; AddressV = Wrap; AddressW = Wrap; }; struct VS_INPUT { float4 Position : Position0; float3 Normal : Normal0; float4 WeightOne : TexCoord0; float4 WeightTwo : TexCoord1; }; struct VS_INPUT_N { float4 Position : Position0; float3 Normal : Normal0; float4 Weight : TexCoord0; }; struct VS_OUTPUT { float4 Position : Position0; float4 HPosition : TexCoord0; float3 Normal : TexCoord1; float4 WeightOne : TexCoord2; float4 WeightTwo : TexCoord3; }; struct VS_OUTPUT_N { float4 Position : Position0; float4 HPosition : TexCoord0; float3 Normal : TexCoord1; float3 Binormal : TexCoord2; float3 Tangent : TexCoord3; float4 Weight : TexCoord4; }; VS_OUTPUT_N MultiTexturedNormalVertexShader( VS_INPUT_N input) { VS_OUTPUT_N Output; // These estimated values should work on terrain that isn't steep, // while steep terrain will not be fully normal mapped. float3 Binormal = (0.0f, 0.0f, -0.5f); float3 Tangent = (0.0f, -0.5f, 0.0f); Output.HPosition = mul(input.Position, World); Output.Position = mul(input.Position, mul(World, mul(View, Proj))); Output.Normal = mul(input.Normal, World); Output.Tangent = mul(Tangent, World); Output.Binormal = mul(Binormal, World); Output.Weight = input.Weight; return Output; } VS_OUTPUT MultiTexturedVertexShader( VS_INPUT input) { VS_OUTPUT Output; Output.HPosition = input.Position; Output.Position = mul(input.Position, mul(World, mul(View, Proj))); Output.Normal = mul(input.Normal, World); Output.WeightOne = input.WeightOne; Output.WeightTwo = input.WeightTwo; return Output; } float4 MultiTexturedNormalPixelShader(VS_OUTPUT_N input) : COLOR0 { float2 uv = (input.HPosition.xz - float2(0.5, 0.5)) * UVScale; float4 Color = tex2D(DirtTextureSampler, uv) * input.Weight.x; Color += tex2D(GrassTextureSampler, uv) * input.Weight.y; Color += tex2D(RockTextureSampler, uv) * input.Weight.z; Color += tex2D(SnowTextureSampler, uv) * input.Weight.w; float4 NColor = tex2D(DirtTextureNSampler, uv) * input.Weight.x; NColor += tex2D(GrassTextureNSampler, uv) * input.Weight.y; NColor += tex2D(RockTextureNSampler, uv) * input.Weight.z; NColor += tex2D(SnowTextureNSampler, uv) * input.Weight.w; NColor.rgb = normalize(mul(NColor, float3x3(input.Tangent, input.Binormal, input.Normal))) * 0.5f; float3 lightVector = -normalize(LightDirection); float lightingFactor = saturate(dot(NColor + input.Normal, lightVector)); float3 Reflect = (lightingFactor * input.Normal) + -lightVector; float3 specular = pow(saturate(dot(Reflect, -CameraForward)), SpecularPower); Color.rgb *= (AmbientColor + (DiffuseColor * lightingFactor) + (SpecularColor * specular * lightingFactor)) * AmbientPower; Color.a = 1.0f; if(EditMode) { float3 delta = input.HPosition - EditPosition; float len = length(delta); float colorStr = clamp((EditRadius / len), 0, 1); float3 EditColor = CursorColor * colorStr; Color.rgb += EditColor; } if(Refraction) { if(input.HPosition.y < WaterHeight) { float maxDepth = WaterHeight - WaterViewDepth; float depthWeight = 1 - clamp((input.HPosition.y) / maxDepth,0, 1); Color.rgb -= (Color.rgb * depthWeight); Color.rgb += DeepWaterColor.rgb * depthWeight; } } return Color; } float4 MultiTexturedPixelShader(VS_OUTPUT input) : COLOR0 { float2 uv = (input.HPosition.xz - float2(0.5, 0.5)) * UVScale; float4 Color = tex2D(DirtTextureSampler, uv) * input.WeightOne.x; Color += tex2D(GrassTextureSampler, uv) * input.WeightOne.y; Color += tex2D(RockTextureSampler, uv) * input.WeightOne.z; Color += tex2D(SnowTextureSampler, uv) * input.WeightOne.w; Color += tex2D(DirtTextureNSampler, uv) * input.WeightTwo.x; Color += tex2D(GrassTextureNSampler, uv) * input.WeightTwo.y; Color += tex2D(RockTextureNSampler, uv) * input.WeightTwo.z; Color += tex2D(SnowTextureNSampler, uv) * input.WeightTwo.w; float3 lightVector = -normalize(LightDirection); float NdL = max(0, dot(input.Normal, lightVector)); Color.rgb = NdL * Color.rgb; Color.a = 1.0f; if(EditMode) { float3 delta = input.HPosition - EditPosition; float len = min(EditRadius, length(delta)); float colorStr = clamp((1 - (len / EditRadius)), 0, 1); float3 EditColor = CursorColor * colorStr; Color.rgb += EditColor; } if(Refraction) { if(input.HPosition.y < WaterHeight) { float maxDepth = WaterHeight - WaterViewDepth; float depthWeight = 1 - clamp((input.HPosition.y) / maxDepth,0, 1); Color.rgb -= (Color.rgb * depthWeight); Color.rgb += DeepWaterColor.rgb * depthWeight; } } return Color; } technique MultiTextured { pass Pass0 { VertexShader = compile vs_1_1 MultiTexturedVertexShader(); PixelShader = compile ps_2_0 MultiTexturedPixelShader(); } } technique MultiTexturedNormal { pass Pass0 { VertexShader = compile vs_1_1 MultiTexturedNormalVertexShader(); PixelShader = compile ps_2_0 MultiTexturedNormalPixelShader(); } }