shader ScriptedWaterShader : PositionVertexTransform, ComputeColor, Texturing { #define PI 3.141592 #define SPECULAR_POWER 18 #define SPECULAR_INTENSITY 0.5 #define DEPTH_FACTOR 2 cbuffer PerMaterial { [Color] stage float3 SunColor; stage float2 SkyTextureOffset; stage float3 CameraPosition; stage float3 DirectionToLight; stage float2 NormalPhase; stage float4 NormalOffsets; stage float2 DiffusePhase; stage float4 DiffuseOffsets; stage float NormalPulseReduction; stage float DiffusePulseReduction; stage float DisplacementSpeed; stage float DisplacementAmplitude; stage float WaterTransparency; stage float4 WorldOffsetAndScale; } rgroup PerMaterial { stage Texture2D SkyTexture; stage Texture2D DiffuseTexture0; stage Texture2D DiffuseTexture1; stage Texture2D NormalTexture0; stage Texture2D NormalTexture1; stage Texture2D FlowMapTexture; stage Texture2D NoiseTexture; } // TODO: I seem to have to inherit from ComputeColor and then everride this to get the shader compiled. Does not seem to make it into // the final shader .hlsl file so I don't know if it matters more than excess code. override float4 Compute() { return float4(1,1,1,1); } override stage void VSMain() { float phase = streams.TexCoord.y - 0.95f; streams.Position.y += sin((phase + Global.Time * DisplacementSpeed) * 2 * 3.14) * DisplacementAmplitude; base.VSMain(); } override stage void PSMain() { float2 flowmap = FlowMapTexture.Sample(RepeatSampler, streams.TexCoord); float noiseSample = NoiseTexture.Sample(RepeatSampler, streams.TexCoord); // Normal float normalPhase0 = (NormalPhase.x + noiseSample * NormalPulseReduction) % 1; float normalPhase1 = (NormalPhase.y + noiseSample * NormalPulseReduction) % 1; float2 normalTexCoord0 = streams.TexCoord + NormalOffsets.xy + flowmap * normalPhase0; float2 normalTexCoord1 = streams.TexCoord + NormalOffsets.zw + flowmap * normalPhase1; float3 normalSample0 = NormalTexture0.Sample(RepeatSampler, normalTexCoord0); float3 normalSample1 = NormalTexture1.Sample(RepeatSampler, normalTexCoord1); float normalBlend = 2 * abs(normalPhase0 - 0.5); float3 finalNormal = normalize(lerp(normalSample0, normalSample1, normalBlend)); // Reflections float directionalIntensity = saturate(dot(finalNormal, DirectionToLight)); float3 reflectionVector = normalize(reflect(-DirectionToLight, finalNormal)); float3 directionToCamera = normalize(CameraPosition - streams.PositionWS); float lightPower = dot(reflectionVector, directionToCamera); float3 specularTerm = saturate(SunColor * SPECULAR_INTENSITY * pow(saturate(lightPower), SPECULAR_POWER)); // Sky float3 skyReflectionVector = normalize(reflect(streams.PositionWS - CameraPosition, finalNormal)); float2 thetaPhi = (((atan2(skyReflectionVector.yy, skyReflectionVector.xz) + PI) % PI) / PI); float3 skyColor = SkyTexture.Sample(RepeatSampler, thetaPhi + SkyTextureOffset).rgb; // Diffuse float diffusePhase0 = (DiffusePhase.x + noiseSample * DiffusePulseReduction) % 1 - 0.5; float diffusePhase1 = (DiffusePhase.y + noiseSample * DiffusePulseReduction) % 1 - 0.5; float2 diffuseTexCoord1 = streams.TexCoord + DiffuseOffsets.xy + flowmap * diffusePhase0; float2 diffuseTexCoord2 = streams.TexCoord + DiffuseOffsets.zw + flowmap * diffusePhase1; float3 diffuseSample0 = DiffuseTexture0.Sample(RepeatSampler, diffuseTexCoord1); float3 diffuseSample1 = DiffuseTexture1.Sample(RepeatSampler, diffuseTexCoord2); float diffuseBlend = 2 * abs(diffusePhase0); float3 finalDiffuse = lerp(diffuseSample0, diffuseSample1, diffuseBlend); // Combine it all float3 resultColor = (skyColor + finalDiffuse)* directionalIntensity + specularTerm; float waterTransparency = 0.85f; // A height map could be used here to provide dynamic transparency streams.ColorTarget = float4(resultColor, waterTransparency); } };