#ifndef TOD_BASE_INCLUDED #define TOD_BASE_INCLUDED #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_CloudMainTex); SAMPLER(sampler_CloudMainTex); TEXTURE2D(TOD_BayerTexture); SAMPLER(samplerTOD_BayerTexture); TEXTURE2D(TOD_CloudTexture); SAMPLER(samplerTOD_CloudTexture); TEXTURE2D(TOD_CloudAlphaTexture); SAMPLER(samplerTOD_CloudAlphaTexture); TEXTURECUBE(_CubeTex); SAMPLER(sampler_CubeTex); CBUFFER_START(UnityPerMaterial_TOD) float _CubeBrightness; half4 _MainTex_ST; half4 _TintColor; half4 _CloudMainTex_ST; half4 _CloudTintColor; half _CloudBrightness; half4x4 TOD_World2Sky, TOD_Sky2World, TOD_World2CloudCameraProjMatrix; half3 TOD_SunLightColor, TOD_MoonLightColor, TOD_SunSkyColor, TOD_MoonSkyColor; half3 TOD_SunMeshColor, TOD_MoonMeshColor, TOD_SunCloudColor, TOD_MoonCloudColor; half3 TOD_FogColor, TOD_GroundColor, TOD_AmbientColor; half3 TOD_SunDirection, TOD_MoonDirection, TOD_LightDirection; half3 TOD_LocalSunDirection, TOD_LocalMoonDirection, TOD_LocalLightDirection; half TOD_Contrast, TOD_Brightness, TOD_Fogginess; half TOD_MoonHaloPower; half3 TOD_MoonHaloColor; half TOD_CloudOpacity, TOD_CloudCoverage, TOD_CloudSharpness, TOD_CloudDensity, TOD_CloudColoring, TOD_CloudAttenuation, TOD_CloudSaturation, TOD_CloudScattering, TOD_CloudBrightness; half3 TOD_CloudOffset, TOD_CloudWind, TOD_CloudSize; half TOD_CloudShadowCutoff, TOD_CloudShadowFade, TOD_CloudShadowIntensity; half TOD_StarSize, TOD_StarBrightness, TOD_StarVisibility; half TOD_SunMeshContrast, TOD_SunMeshBrightness; half TOD_MoonMeshContrast, TOD_MoonMeshBrightness; half3 TOD_ScatterDensity, TOD_kBetaMie; half4 TOD_kSun, TOD_k4PI, TOD_kRadius, TOD_kScale; half3 TOD_SunWorldPos, TOD_HeroWorldPos; half TOD_IsDay; half4 _SG_VirtualScatterLightColor; half _SG_AtmosphereFogDensityFactor; CBUFFER_END // Vertex transform used by the entire sky dome #if UNITY_VERSION >= 540 #define TOD_TRANSFORM_VERT(vert) UnityObjectToClipPos(vert) #else #define TOD_TRANSFORM_VERT(vert) UnityObjectToClipPos(vert) #endif #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) #if UNITY_VERSION >= 540 // Matrices #define TOD_Object2World unity_ObjectToWorld #define TOD_World2Object unity_WorldToObject #else #define TOD_Object2World unity_ObjectToWorld #define TOD_World2Object unity_WorldToObject #endif #if UNITY_VERSION >= 540 // Screen space adjust #define TOD_UV(x, y) UnityStereoScreenSpaceUVAdjust(x, y) #else #define TOD_UV(x, y) x #endif #if UNITY_VERSION >= 540 // Stereo output #define TOD_VERTEX_OUTPUT_STEREO UNITY_VERTEX_OUTPUT_STEREO #define TOD_INITIALIZE_VERTEX_OUTPUT_STEREO(o) UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o) #else #define TOD_VERTEX_OUTPUT_STEREO #define TOD_INITIALIZE_VERTEX_OUTPUT_STEREO(o) #endif #if UNITY_VERSION >= 540 // Instancing #define TOD_INSTANCE_ID UNITY_VERTEX_INPUT_INSTANCE_ID #define TOD_SETUP_INSTANCE_ID(o) UNITY_SETUP_INSTANCE_ID(o) #else #define TOD_INSTANCE_ID #define TOD_SETUP_INSTANCE_ID(o) #endif #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 Adjust(half4 color) { #if !TOD_OUTPUT_HDR color = TOD_HDR2LDR(color); #endif #if !TOD_OUTPUT_LINEAR color = TOD_LINEAR2GAMMA(color); #endif return color; } //////////////////////////////////////////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(_MainTex, sampler_MainTex, uv1); half4 n2 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv2); half4 n3 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv3); half4 n4 = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv4); 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 up direction half4 nz = half4(n1.r, n2.g, n3.b, n4.a); // Noise when marching in view direction density.y += dot(ny, sumy); // Density when marching in up direction density.z += dot(nz, sumz); // Density when marching in view direction half2 stepA = TOD_CloudCoverage; // Coverage half2 stepB = TOD_CloudCoverage + TOD_CloudSharpness; half2 stepC = TOD_CloudDensity; density.yz = smoothstep(stepA, stepB, density.yz) + saturate(density.yz - stepB) * stepC; density.x = saturate(density.z); // Opacity density.yz *= half2(TOD_CloudAttenuation, TOD_CloudSaturation); // Shading density.yz = 1.0 - exp2(-density.yz); // Remap #else half4 n = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, uv.xy); density.y += n.r; // Density when marching in up direction density.z += n.r; // Density when marching in view direction density.yz = (density.yz - TOD_CloudCoverage) * half2(TOD_CloudAttenuation, TOD_CloudDensity); // Coverage density.x = saturate(density.z); // Opacity #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 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//////////////////////////////////////////// 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; half3 cameraPos = half3(0, kInnerRadius + kCameraHeight, 0); // Current camera position half far = sqrt(kOuterRadius2 + kInnerRadius2 * dir.y * dir.y - kInnerRadius2) - kInnerRadius * dir.y; // Length of the atmosphere half startDepth = exp(kScaleOverScaleDepth * (-kCameraHeight)); // Ray starting position and its scattering offset half startAngle = dot(dir, cameraPos) / (kInnerRadius + kCameraHeight); half startOffset = startDepth * Scale(startAngle); half sampleLength = far / 2; // Scattering loop variables 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; #if TOD_SCATTERING_RAYLEIGH // Sun scattering 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, 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); half fogIntensity = camDist * heightDensityExpInv; // Get base fog intensity at pixel half clampRes = step(abs(heightDensity), 0.01); // Apply height falloff fogIntensity *= ((1.0 - heightDensityExpInv) / heightDensity) * step(abs(heightDensity), 0.01) + step(0.01, abs(heightDensity)); fogIntensity = min(10, globalDensity * fogIntensity); // Clamp intensity 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).a * (1.0 / (TOD_BAYER_DIM * TOD_BAYER_DIM + 1.0)); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif