#ifndef TOD_BASE #define TOD_BASE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" TEXTURE2D(TOD_BayerTexture); SAMPLER(samplerTOD_BayerTexture); TEXTURE2D(TOD_CloudTexture); SAMPLER(samplerTOD_CloudTexture); TEXTURE2D(TOD_CloudAlphaTexture); SAMPLER(samplerTOD_CloudAlphaTexture); CBUFFER_START(UnityPerMaterial_TOD) half4x4 TOD_World2Sky, TOD_Sky2World, TOD_World2CloudCameraProjMatrix; half3 TOD_FogColor; half3 TOD_SunLightColor; half3 TOD_GroundColor; half3 TOD_MoonLightColor; half3 TOD_AmbientColor; half3 TOD_SunSkyColor; half3 TOD_SunDirection; half3 TOD_MoonSkyColor; half3 TOD_MoonDirection; half3 TOD_SunMeshColor; half3 TOD_LightDirection; half3 TOD_MoonMeshColor; half3 TOD_LocalSunDirection; half3 TOD_SunCloudColor; half3 TOD_LocalMoonDirection; half3 TOD_MoonCloudColor; half3 TOD_LocalLightDirection; half TOD_Contrast; half TOD_CloudDensity; half TOD_Brightness; half TOD_CloudColoring; half TOD_Fogginess; half TOD_CloudAttenuation; half TOD_MoonHaloPower; half TOD_CloudSaturation; half3 TOD_MoonHaloColor; half TOD_CloudScattering; half TOD_CloudOpacity; half TOD_CloudBrightness; half TOD_CloudCoverage; half3 TOD_CloudOffset; half TOD_CloudSharpness; half3 TOD_CloudWind; half3 TOD_CloudSize; half TOD_SunMeshContrast; half TOD_CloudShadowCutoff; half TOD_SunMeshBrightness; half TOD_CloudShadowFade; half TOD_MoonMeshContrast; half TOD_CloudShadowIntensity; half TOD_MoonMeshBrightness; half TOD_StarSize; half3 TOD_ScatterDensity; half TOD_StarBrightness; half3 TOD_kBetaMie; half TOD_StarVisibility; half4 TOD_kSun; half4 TOD_k4PI; half3 TOD_SunWorldPos; half4 TOD_kRadius; half3 TOD_HeroWorldPos; half4 TOD_kScale; half TOD_IsDay; CBUFFER_END #define TOD_ROTATION_UV(angle) half2x2(cos(angle), -sin(angle), sin(angle), cos(angle)) // UV rotation matrix constructor #define TOD_HDR2LDR(color) (1.0 - exp2(-TOD_Brightness * color)) // Fast and simple tonemapping #define TOD_GAMMA2LINEAR(color) (color * color) // Approximates gamma by 2.0 instead of 2.2 #define TOD_LINEAR2GAMMA(color) sqrt(color) #define TOD_Object2World unity_ObjectToWorld #define TOD_World2Object unity_WorldToObject #define TOD_UV(x, y) x // Screen space adjust #define TOD_VERTEX_OUTPUT_STEREO // Stereo output #define TOD_INITIALIZE_VERTEX_OUTPUT_STEREO(o) #define TOD_INSTANCE_ID // Instancing #define TOD_SETUP_INSTANCE_ID(o) //////////////////////////////////////////CLOUD CALCULATION////////////////////////////////////////////////// inline half3 CloudPosition(half3 viewDir, half3 offset) { half mult = 1.0 / lerp(0.1, 1.0, viewDir.y); return (half3(viewDir.x * mult + offset.x, 0, viewDir.z * mult + offset.z)) / TOD_CloudSize; } inline half4 CloudUV(half3 viewDir, half3 offset) { half3 cloudPos = CloudPosition(viewDir, offset); half2 uv1 = cloudPos.xz + TOD_CloudOffset.xz + TOD_CloudWind.xz; half2 uv2 = mul(TOD_ROTATION_UV(radians(10.0)), cloudPos.xz) + TOD_CloudOffset.xz + TOD_CloudWind.xz; return half4(uv1.x, uv1.y, uv2.x, uv2.y); } inline half4 CloudUV(half3 viewDir) { return CloudUV(viewDir, 0); } inline half3 CloudColor(half3 viewDir, half3 lightDir) { half lerpValue = saturate(1 + 4 * lightDir.y) * saturate(dot(viewDir, lightDir) + 1.25); half3 cloudColor = lerp(TOD_MoonCloudColor, TOD_SunCloudColor, lerpValue); half3 fogColor = TOD_FogColor; return TOD_Brightness * lerp(cloudColor, fogColor, TOD_Fogginess); } inline half3 CloudLayerDensity(half4 uv, half3 viewDir) { half3 density = 0; #if TOD_CLOUDS_DENSITY const half thickness = 0.1; const half4 stepoffset = half4(0.0, 1.0, 2.0, 3.0) * thickness; const half4 sumy = half4(0.5000, 0.2500, 0.1250, 0.0625) / half4(1, 2, 3, 4); const half4 sumz = half4(0.5000, 0.2500, 0.1250, 0.0625); half2 uv1 = uv.xy + viewDir.xz * stepoffset.x; half2 uv2 = uv.zw + viewDir.xz * stepoffset.y; half2 uv3 = uv.xy + viewDir.xz * stepoffset.z; half2 uv4 = uv.zw + viewDir.xz * stepoffset.w; half4 n1 = SAMPLE_TEXTURE2D(TOD_CloudTexture, samplerTOD_CloudTexture, uv1); half4 n2 = SAMPLE_TEXTURE2D(TOD_CloudTexture, samplerTOD_CloudTexture, uv2); half4 n3 = SAMPLE_TEXTURE2D(TOD_CloudTexture, samplerTOD_CloudTexture, uv3); half4 n4 = SAMPLE_TEXTURE2D(TOD_CloudTexture, samplerTOD_CloudTexture, uv4); // Noise when marching in up direction half4 ny = half4(n1.r, n1.g + n2.g, n1.b + n2.b + n3.b, n1.a + n2.a + n3.a + n4.a); // Noise when marching in view direction half4 nz = half4(n1.r, n2.g, n3.b, n4.a); // Density when marching in up direction density.y += dot(ny, sumy); // Density when marching in view direction density.z += dot(nz, sumz); // Coverage half2 stepA = TOD_CloudCoverage; half2 stepB = TOD_CloudCoverage + TOD_CloudSharpness; half2 stepC = TOD_CloudDensity; density.yz = smoothstep(stepA, stepB, density.yz) + saturate(density.yz - stepB) * stepC; // Opacity density.x = saturate(density.z); // Shading density.yz *= half2(TOD_CloudAttenuation, TOD_CloudSaturation); // Remap density.yz = 1.0 - exp2(-density.yz); #else half4 n = SAMPLE_TEXTURE2D(TOD_CloudTexture, samplerTOD_CloudTexture, uv.xy); // Density when marching in up direction density.y += n.r; // Density when marching in view direction density.z += n.r; // Coverage density.yz = (density.yz - TOD_CloudCoverage) * half2(TOD_CloudAttenuation, TOD_CloudDensity); // Opacity density.x = saturate(density.z); #endif return density; } inline half4 CloudLayerColor(half4 uv, half4 color, half3 viewDir, half3 lightDir, half3 lightCol) { half3 density = CloudLayerDensity(uv, viewDir); half4 res = 0; res.a = density.x; res.rgb = 1.0 - density.y; res *= color; #if TOD_CLOUDS_BUMPED res.rgb += saturate((1.0 - density.z) * (1.0 - TOD_Fogginess)) * lightCol; #endif return res; } inline half CloudShadow(half4 uv) { return CloudLayerDensity(uv, half3(0, 1, 0)).x; } inline half3 CloudBillboardDensity(half2 uv, half3 viewDir) { half3 density = 0; half4 tex = SAMPLE_TEXTURE2D(TOD_CloudTexture, samplerTOD_CloudTexture, uv.xy); // Density when marching in up direction density.y = tex.a; // Density when marching in view direction #if TOD_CLOUDS_DENSITY density.z = lerp(lerp(tex.r, tex.g, saturate(viewDir.x)), tex.b, saturate(-viewDir.x)); #else density.z = tex.r; #endif // Opacity density.x = saturate(density.z); // Shading density.y *= TOD_CloudAttenuation; return density; } // inline half4 CloudBillboardColor(sampler2D normalTex, half4 uv, half4 color, half3 viewDir, half3 lightDir, half3 lightCol) // { // half3 density = CloudBillboardDensity(uv.xy, viewDir); // half4 res = 0; // res.a = density.x; // res.rgb = 1.0 - density.y; // #if TOD_CLOUDS_DENSITY // half3 normal = UnpackNormal(tex2D(normalTex, uv.zw)); // half NdotS = dot(normal, lightDir); // res.rgb += 0.25 * (1.0 - TOD_Fogginess) * NdotS; // #endif // res *= color; // #if TOD_CLOUDS_BUMPED // res.rgb += saturate((1.0 - density.z) * (1.0 - TOD_Fogginess)) * lightCol; // #endif // return res; // } inline half CloudShadow(half3 cameraToWorldPos) { half3 worldPos = _WorldSpaceCameraPos + cameraToWorldPos; half3 skyPos = mul((half3x3)TOD_World2Sky, worldPos); half4 cloudUV = CloudUV(TOD_LocalLightDirection, skyPos); return TOD_CloudOpacity * CloudShadow(cloudUV); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////SCATTERING CALCULATION//////////////////////////////////////////// #ifndef TOD_SCATTERING_MIE #define TOD_SCATTERING_MIE 1 #endif #ifndef TOD_SCATTERING_RAYLEIGH #define TOD_SCATTERING_RAYLEIGH 1 #endif #ifndef TOD_BAYER_DIM #define TOD_BAYER_DIM 8.0 #endif half4 _SG_VirtualScatterLightColor; inline half3 ApplayVirtualScatterLight(half3 curColor, float3 worldPos) { float3 worldViewDir = _WorldSpaceCameraPos.xyz - worldPos.xyz; half3 worldLightDir = normalize(GetMainLight().direction); half angleFactor = 1.0 - saturate(dot(normalize(worldViewDir), worldLightDir) * 0.5 + 0.8); half3 scatterLightColor = _SG_VirtualScatterLightColor.rgb * angleFactor; half3 finalColor = curColor + scatterLightColor; return finalColor; } inline half Scale(half inCos) { half x = 1.0 - inCos; return 0.25 * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); } inline half MiePhase(half eyeCos, half eyeCos2) { return TOD_kBetaMie.x * (1.0 + eyeCos2) / pow(TOD_kBetaMie.y + TOD_kBetaMie.z * eyeCos, 1.5); } inline half RayleighPhase(half eyeCos2) { return 0.75 + 0.75 * eyeCos2; } inline half RayleighPhase(half eyeCos2, half3 dir) { half groundPercent = 1-saturate(dir.y); half base = lerp(1.5, 0.2, groundPercent); half phase = base + 0.75 * eyeCos2; half isBottom = dir.y < -0.5; phase *= lerp(1, 0.2, isBottom); return phase; } inline half CloudPhase(half eyeCos, half eyeCos2) { const half g = 0.3; const half g2 = g * g; return TOD_CloudScattering * (1.5 * (1.0 - g2) / (2.0 + g2) * (1.0 + eyeCos2) / (1.0 + g2 - 2.0 * g * eyeCos) + g * eyeCos); } inline half3 NightPhase(half3 dir) { dir.y = abs(dir.y); return TOD_MoonSkyColor * (1.0 - 0.75 * dir.y); } inline half3 MoonPhase(half3 dir) { return TOD_MoonHaloColor * pow(max(0, dot(dir, TOD_LocalMoonDirection)), TOD_MoonHaloPower); } inline half3 PostProcess(half3 col, half3 dir) { col = pow(col * TOD_Brightness, TOD_Contrast); return col; } #if TOD_SCATTERING_RAYLEIGH && TOD_SCATTERING_MIE inline void ScatteringCoefficients(half3 dir, out half3 inscatter, out half3 outscatter) #elif TOD_SCATTERING_RAYLEIGH inline void ScatteringCoefficients(half3 dir, out half3 inscatter) #else inline void ScatteringCoefficients(half3 dir, out half3 outscatter) #endif { dir = normalize(half3(dir.x, max(0, dir.y), dir.z)); half kInnerRadius = TOD_kRadius.x; half kInnerRadius2 = TOD_kRadius.y; half kOuterRadius2 = TOD_kRadius.w; half kScale = TOD_kScale.x; half kScaleOverScaleDepth = TOD_kScale.z; half kCameraHeight = TOD_kScale.w; half3 kKr4PI = TOD_k4PI.xyz; half kKm4PI = TOD_k4PI.w; half3 kKrESun = TOD_kSun.xyz; half kKmESun = TOD_kSun.w; // Current camera position half3 cameraPos = half3(0, kInnerRadius + kCameraHeight, 0); // Length of the atmosphere half far = sqrt(kOuterRadius2 + kInnerRadius2 * dir.y * dir.y - kInnerRadius2) - kInnerRadius * dir.y; // Ray starting position and its scattering offset half startDepth = exp(kScaleOverScaleDepth * (-kCameraHeight)); half startAngle = dot(dir, cameraPos) / (kInnerRadius + kCameraHeight); half startOffset = startDepth * Scale(startAngle); // Scattering loop variables half sampleLength = far / 2; half scaledLength = sampleLength * kScale; half3 sampleRay = dir * sampleLength; half3 samplePoint = cameraPos + sampleRay * 0.5; half3 sunColor = half3(0.0, 0.0, 0.0); half height = max(1, length(samplePoint)); half invHeight = 1.0 / height; half depth = exp(kScaleOverScaleDepth * (kInnerRadius - height)); half atten = depth * scaledLength; half cameraAngle = dot(dir, samplePoint) * invHeight; half sunAngle = dot(TOD_LocalSunDirection, samplePoint) * invHeight; half sunScatter = startOffset + depth * (Scale(sunAngle) - Scale(cameraAngle)); half3 sunAtten = exp(-sunScatter * (kKr4PI + kKm4PI)); sunColor += sunAtten * atten; samplePoint += sampleRay; height = max(1, length(samplePoint)); invHeight = 1.0 / height; depth = exp(kScaleOverScaleDepth * (kInnerRadius - height)); atten = depth * scaledLength; cameraAngle = dot(dir, samplePoint) * invHeight; sunAngle = dot(TOD_LocalSunDirection, samplePoint) * invHeight; sunScatter = startOffset + depth * (Scale(sunAngle) - Scale(cameraAngle)); sunAtten = exp(-sunScatter * (kKr4PI + kKm4PI)); sunColor += sunAtten * atten; samplePoint += sampleRay; // Sun scattering #if TOD_SCATTERING_RAYLEIGH inscatter = TOD_SunSkyColor * sunColor * kKrESun; #endif #if TOD_SCATTERING_MIE outscatter = TOD_SunSkyColor * sunColor * kKmESun; #endif } #if TOD_SCATTERING_RAYLEIGH && TOD_SCATTERING_MIE inline half4 ScatteringColor(half3 dir, half3 inscatter, half3 outscatter) #elif TOD_SCATTERING_RAYLEIGH inline half4 ScatteringColor(half3 dir, half3 inscatter) #else inline half4 ScatteringColor(half3 dir, half3 outscatter) #endif { half3 resultColor = half3(0.05, 0.05, 0.1); half sunCos = dot(TOD_LocalSunDirection, dir); half sunCos2 = sunCos * sunCos; #if TOD_SCATTERING_RAYLEIGH resultColor += NightPhase(dir); #endif #if TOD_SCATTERING_MIE resultColor += MoonPhase(dir); #endif #if TOD_SCATTERING_RAYLEIGH //resultColor += RayleighPhase(sunCos2) * inscatter; resultColor += RayleighPhase(sunCos2, dir) * inscatter; #endif #if TOD_SCATTERING_MIE resultColor += MiePhase(sunCos, sunCos2) * outscatter; #endif return half4(PostProcess(resultColor, dir), 1.0); } inline half4 ScatteringColor(half3 dir) { #if TOD_SCATTERING_RAYLEIGH && TOD_SCATTERING_MIE half3 inscatter, outscatter; ScatteringCoefficients(dir, inscatter, outscatter); return ScatteringColor(dir, inscatter, outscatter); #elif TOD_SCATTERING_RAYLEIGH half3 inscatter; ScatteringCoefficients(dir, inscatter); return ScatteringColor(dir, inscatter); #else half3 outscatter; ScatteringCoefficients(dir, outscatter); return ScatteringColor(dir, outscatter); #endif } inline half FogDensity(half3 worldPos) { half camDist = length(worldPos - _WorldSpaceCameraPos); half globalDensity = TOD_ScatterDensity.z; half heightDensity = TOD_ScatterDensity.x * (worldPos.y - TOD_ScatterDensity.y); half heightDensityExpInv = exp(-heightDensity); // Get base fog intensity at pixel half fogIntensity = camDist * heightDensityExpInv; // Apply height falloff half clampRes = step(abs(heightDensity), 0.01); fogIntensity *= ((1.0 - heightDensityExpInv) / heightDensity) * step(abs(heightDensity), 0.01) + step(0.01, abs(heightDensity)); // Clamp intensity fogIntensity = min(10, globalDensity * fogIntensity); return 1.0 - exp(-fogIntensity); } inline half4 AtmosphericScattering(half3 cameraRay, half3 worldPos, half depth, half mask) { half3 dir = normalize(mul((half3x3)TOD_World2Sky, cameraRay)); #if TOD_SCATTERING_RAYLEIGH && TOD_SCATTERING_MIE half3 inscatter, outscatter; ScatteringCoefficients(dir, inscatter, outscatter); #elif TOD_SCATTERING_RAYLEIGH half3 inscatter; ScatteringCoefficients(dir, inscatter); #else half3 outscatter; ScatteringCoefficients(dir, outscatter); #endif depth = FogDensity(worldPos); #if TOD_SCATTERING_MIE outscatter = outscatter * depth * mask; #endif #if TOD_SCATTERING_RAYLEIGH inscatter = inscatter * depth; #endif #if TOD_SCATTERING_RAYLEIGH && TOD_SCATTERING_MIE half3 color = ScatteringColor(dir, inscatter, outscatter).rgb; #elif TOD_SCATTERING_RAYLEIGH half3 color = ScatteringColor(dir, inscatter).rgb; #else half3 color = ScatteringColor(dir, outscatter).rgb; #endif return half4(color, depth); } inline half4 AtmosphericScattering(half3 cameraRay, half3 worldPos, half depth) { const half mask = 1; // This should be sampled from the scattering occlusion mask return AtmosphericScattering(cameraRay, worldPos, depth, mask); } inline half4 AtmosphericScattering(half3 cameraRay, half3 worldPos) { half3 dir = normalize(mul((half3x3)TOD_World2Sky, cameraRay)); half depth = FogDensity(worldPos); half3 color = ScatteringColor(dir).rgb; return half4(color, depth); } inline half2 DitheringCoords(half2 screenPos) { return screenPos * _ScreenParams.xy * (1.0 / TOD_BAYER_DIM); } inline half DitheringColor(half2 uv) { return SAMPLE_TEXTURE2D(TOD_BayerTexture, samplerTOD_BayerTexture, uv.xy).a * (1.0 / (TOD_BAYER_DIM * TOD_BAYER_DIM + 1.0)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif