half bias (half b, half x) { return pow (x, log (b) / log (0.5)); } half4 sunlightInscatter (half4 sunColour, half absorption, half incidenceAngleCos, half sunlightScatteringFactor) { half scatteredSunlight = bias (sunlightScatteringFactor * 0.5, incidenceAngleCos); sunColour = sunColour * (1 - absorption) * half4 (0.9, 0.5, 0.09, 1); return sunColour * scatteredSunlight; } half fogExp (half z, half density) { return 1 - clamp (pow (2.71828, -z * density), 0, 1); } void SkyDome_vp (half4 position : POSITION, half4 normal : NORMAL, half2 uv : TEXCOORD0, out half4 oPosition : POSITION, out half4 oCol : COLOR, out half2 oUv : TEXCOORD0, out half incidenceAngleCos : TEXCOORD1, out half y : TEXCOORD2, out half3 oNormal : TEXCOORD3, uniform half lightAbsorption, uniform half4x4 worldViewProj, uniform half3 sunDirection) { sunDirection = normalize (sunDirection); normal = normalize (normal); half cosine = dot (-sunDirection, normal); incidenceAngleCos = -cosine; y = -sunDirection.y; oPosition = mul(worldViewProj, position); oCol = half4 (1, 1, 1, 1); oUv = uv; oNormal = -normal; } void SkyDome_fp (half4 col : COLOR, half2 uv : TEXCOORD0, half incidenceAngleCos : TEXCOORD1, half y : TEXCOORD2, half3 normal : TEXCOORD3, out half4 oCol : COLOR, uniform sampler gradientsMap : register(s0), uniform sampler1D atmRelativeDepth : register(s1), uniform half4 hazeColour, uniform half offset) { // half4 sunColour = half4 (3, 2.5, 1, 1); half4 sunColour = half4 (3, 3, 3, 1); half fogDensity = 15; // Haze amount calculation half invHazeHeight = 100; half haze = fogExp (pow (clamp (1 - normal.y, 0, 1), invHazeHeight), fogDensity); // Pass the colour oCol = tex2D (gradientsMap, uv + half2 (offset, 0)) * col; // Sunlight inscatter if (incidenceAngleCos > 0) { half sunlightScatteringFactor = 0.05; half sunlightScatteringLossFactor = 0.1; half atmLightAbsorptionFactor = 0.1; oCol.rgb += sunlightInscatter (sunColour, clamp (atmLightAbsorptionFactor * (1 - tex1D (atmRelativeDepth, y).r), 0, 1), clamp (incidenceAngleCos, 0, 1), sunlightScatteringFactor).rgb * (1 - sunlightScatteringLossFactor); } // Haze pass hazeColour.a = 1; oCol = oCol * (1 - haze) + hazeColour * haze; } void Haze_vp (half4 position : POSITION, half4 normal : NORMAL, out half4 oPosition : POSITION, out half haze : TEXCOORD0, out half2 sunlight : TEXCOORD1, uniform half4x4 worldViewProj, uniform half4 camPos, uniform half3 sunDirection) { sunDirection = normalize (sunDirection); oPosition = mul(worldViewProj, position); haze = length (camPos - position); sunlight.x = dot (-sunDirection, normalize (position - camPos)); sunlight.y = -sunDirection.y; } void Haze_fp (half haze : TEXCOORD0, half2 sunlight : TEXCOORD1, out half4 oCol : COLOR, uniform sampler1D atmRelativeDepth : register(s0), uniform sampler2D gradientsMap : register (s1), uniform half4 fogColour) { half incidenceAngleCos = sunlight.x; half y = sunlight.y; half4 sunColour = half4 (3, 2.5, 1, 1); half atmLightAbsorptionFactor = 0.1; // Factor determining the amount of light lost due to absorption half fogDensity = 15; haze = fogExp (haze * 0.005, atmLightAbsorptionFactor); // Haze amount calculation half invHazeHeight = 100; half hazeAbsorption = fogExp (pow (1 - y, invHazeHeight), fogDensity); half4 hazeColour; hazeColour = fogColour; if (incidenceAngleCos > 0) { half sunlightScatteringFactor = 0.1; // Factor determining the amount of scattering for the sun light half sunlightScatteringLossFactor = 0.3; // Factor determining the amount of sun light intensity lost due to scattering half4 sunlightInscatterColour = sunlightInscatter (sunColour, clamp ((1 - tex1D (atmRelativeDepth, y).r) * hazeAbsorption, 0, 1), clamp (incidenceAngleCos, 0, 1), sunlightScatteringFactor) * (1 - sunlightScatteringLossFactor); hazeColour.rgb = hazeColour.rgb * (1 - sunlightInscatterColour.a) + sunlightInscatterColour.rgb * sunlightInscatterColour.a * haze; } oCol = hazeColour; oCol.a = haze; } /////////////////////////////////////////////////////////////////////////////// // Global cloud textures sampler cloud_shape1 : register(s0); sampler cloud_shape2 : register(s1); sampler cloud_detail : register(s2); // Global cloud parameters. uniform float cloudMassInvScale; uniform float cloudDetailInvScale; uniform float2 cloudMassOffset; uniform float2 cloudDetailOffset; uniform float cloudCover; uniform float cloudMassBlend; uniform float cloudDetailBlend; uniform float cloudSharpness; uniform float cloudThickness; uniform float cloudShininess; // Get cloud layer intensity at a certain point. float LayeredClouds_intensity(in float2 pos) { // Calculate the base alpha float2 finalMassOffset = cloudMassOffset + pos; float aCloud = lerp(tex2D(cloud_shape1, finalMassOffset * cloudMassInvScale).r, tex2D(cloud_shape2, finalMassOffset * cloudMassInvScale).r, cloudMassBlend); float aDetail = tex2D(cloud_detail, (cloudDetailOffset + pos) * cloudDetailInvScale).r; aCloud = (aCloud + aDetail * cloudDetailBlend) / (1 + cloudDetailBlend); return max(0, aCloud - (1 - cloudCover)); } // Entry point for Cloud vertex program. void LayeredClouds_vp ( in float4 position : POSITION, in float2 uv : TEXCOORD0, out float4 oPosition : POSITION, out float2 oUv : TEXCOORD0, out float oGlow : TEXCOORD1, out float3 relPosition : TEXCOORD2, uniform float4x4 worldViewProj, uniform float3 sunDirection ) { relPosition = normalize (position); oGlow = dot (relPosition, normalize (-sunDirection)); oPosition = mul(worldViewProj, position); oUv = uv; } // Entry point for Cloud fragment program. void LayeredClouds_fp ( in float2 uv : TEXCOORD0, in float glow : TEXCOORD1, in float3 relPosition : TEXCOORD2, uniform float cameraHeight, uniform float3 sunDirection, uniform float4 sunColour, uniform float4 fogColour, out float4 oCol : COLOR ) { // Initialize output. oCol.rgba = float4(1, 1, 1, 0); // Get cloud intensity. float intensity = LayeredClouds_intensity(uv); // Opacity is exponential. float aCloud = saturate(exp(cloudSharpness * intensity) - 1); float shine = pow(saturate(glow), 8) / 4; sunColour.rgb *= 1.5; float3 cloudColour = fogColour.rgb * (1 - intensity / 3); float thickness = saturate(0.8 - exp(-cloudThickness * (intensity + 0.2 - shine))); oCol.rgb = lerp(sunColour.rgb, cloudColour.rgb, thickness); //oCol.rgb = thickness; //oCol.rgb = sunColour.rgb; //oCol.rgb = cloudColour.rgb; // bottom 20th of the sky clouds vanish. // Simple and effective.e aCloud *= saturate (20 * relPosition.y); oCol.a = aCloud; oCol.rgb = (oCol.rgb); } /////////////////////////////////////////////////////////////////////////////// // Return fogging through a layer of fog which drops exponentially by height. // Foginess at a certain point is exp(-verticalDecay * (h - fogLevel)); // A fogLevel from the ground fogginess is 1. float ExpGroundFog (float invSinView, float h1, float h2, float density, float verticalDecay, float fogLevel) { // Integrate fog on a vertical line from h1 to h2. float vFog = (-1 / verticalDecay) * (exp (-verticalDecay * (h2 - fogLevel)) - exp (-verticalDecay * (h1 - fogLevel))); return 1 - exp (-density * invSinView * vFog); } // Just like ExpGroundFog with infinite h2 float ExpGroundFogInf (float invSinView, float h1, float density, float verticalDecay, float fogLevel) { // Integrate fog on a vertical line from h1 to h2. float vFog = exp (-verticalDecay * (h1 - fogLevel)) / verticalDecay; return 1 - exp (-density * invSinView * vFog); } // Entry point for GroundFog vertex program. void GroundFog_vp ( float4 position : POSITION, out float4 oPosition : POSITION, out float4 worldPos : TEXCOORD0, uniform float4x4 worldViewProj, uniform float4x4 world ) { oPosition = mul(worldViewProj, position); worldPos = mul(world, position); } // Entry point for GroundFog fragment program. void GroundFog_fp ( float3 worldPos : TEXCOORD0, uniform float3 camPos, uniform float4 fogColour, uniform float fogDensity, uniform float fogVerticalDecay, uniform float fogGroundLevel, out float4 oCol : COLOR ) { float h1 = camPos.y; float h2 = worldPos.y; float invSinView = length(camPos - worldPos) / (h2 - h1); float fog = ExpGroundFog(invSinView, h1, h2, fogDensity, fogVerticalDecay, fogGroundLevel); oCol.rgb = fogColour.rgb; oCol.a = fog; } // Entry point for GroundFogDome vertex program. void GroundFogDome_vp ( in float4 position : POSITION, out float4 oPosition : POSITION, out float3 relPosition : TEXCOORD0, uniform float4x4 worldViewProj ) { oPosition = mul(worldViewProj, position); relPosition = normalize(position); } // Entry point for the GroundFogDome fragment program. void GroundFogDome_fp ( in float3 relPosition : TEXCOORD0, uniform float cameraHeight, uniform float4 fogColour, uniform float fogDensity, uniform float fogVerticalDecay, uniform float fogGroundLevel, out float4 oCol : COLOR ) { // Fog magic. float invSinView = 1 / (relPosition.y); float h1 = cameraHeight; float aFog; if (invSinView < 0) { // Gazing into the abyss aFog = 0; } else { aFog = saturate (ExpGroundFogInf ( invSinView, h1, fogDensity, fogVerticalDecay, fogGroundLevel)); } oCol.a = aFog; oCol.rgb = fogColour.rgb; }