Shader "GAME/StylizedSky" { // Fully procedural stylized skybox: vertical sky gradient, sun + glow, moon, twinkling // stars and FBM clouds — all animated. Static art-direction lives in these Properties; // everything that changes with the time of day is pushed as GLOBALS by TimeOfDayManager // (mirrors how StylizedGrass reads the global "_Season"). No textures, no geometry. Properties { [Header(Clouds static tuning)][Space] _CloudScale("Cloud Scale", Float) = 1.0 _CloudSoftness("Cloud Softness", Range(0.01, 1)) = 0.08 _CloudShadingStrength("Cloud Shading Strength", Range(0, 4)) = 2.5 _CloudHorizonFade("Cloud Horizon Fade", Range(0.02, 0.6)) = 0.05 _CloudDetail("Cloud Detail (billow lumps)", Range(0, 1)) = 0.7 [Header(Sun static tuning)][Space] _SunSize("Sun Size", Range(0.002, 0.2)) = 0.04 _SunEdgeSoftness("Sun Edge Softness", Range(0.001, 0.1)) = 0.015 _SunGlowFalloff("Sun Glow Falloff", Range(1, 2000)) = 400 _SunGlowStrength("Sun Glow Strength", Range(0, 3)) = 0.6 [Header(Moon static tuning)][Space] _MoonSize("Moon Size", Range(0.002, 0.2)) = 0.05 _MoonEdgeSoftness("Moon Edge Softness", Range(0.001, 0.1)) = 0.012 [Header(Stars static tuning)][Space] _StarDensity("Star Density", Float) = 60 _StarThreshold("Star Threshold", Range(0.8, 0.999)) = 0.93 _StarSize("Star Size", Range(0.01, 0.5)) = 0.09 _StarTwinkleSpeed("Star Twinkle Speed", Float) = 3 [Header(Gradient shaping)][Space] _HorizonSharpness("Horizon Sharpness", Range(0.2, 8)) = 2.5 _GroundSharpness("Ground Sharpness", Range(0.2, 8)) = 3.0 } SubShader { Tags { "RenderType" = "Background" "Queue" = "Background" "RenderPipeline" = "UniversalPipeline" "PreviewType" = "Skybox" } Pass { Name "StylizedSky" Cull Off ZWrite Off ZTest LEqual HLSLPROGRAM #pragma target 3.0 #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" // --------------------------------------------------------------------------------- // Static per-material tuning // --------------------------------------------------------------------------------- CBUFFER_START(UnityPerMaterial) float _CloudScale; float _CloudSoftness; float _CloudShadingStrength; float _CloudHorizonFade; float _CloudDetail; float _SunSize; float _SunEdgeSoftness; float _SunGlowFalloff; float _SunGlowStrength; float _MoonSize; float _MoonEdgeSoftness; float _StarDensity; float _StarThreshold; float _StarSize; float _StarTwinkleSpeed; float _HorizonSharpness; float _GroundSharpness; CBUFFER_END // --------------------------------------------------------------------------------- // Time-of-day globals (written every frame by TimeOfDayManager via SetGlobalX). // Declared OUTSIDE the CBUFFER so they resolve to the global values, exactly like // StylizedGrass reads "_Season". // --------------------------------------------------------------------------------- float4 _SkyZenithColor; float4 _SkyHorizonColor; float4 _SkyGroundColor; float4 _SkySunDirection; // xyz = world direction TOWARD the sun (normalized) float4 _SkySunColor; float4 _SkyMoonDirection; // xyz = world direction TOWARD the moon (normalized) float4 _SkyMoonColor; float4 _SkyCloudColor; float4 _SkyCloudShadowColor; float4 _SkyCloudParams; // x = coverage threshold, y = opacity, zw = wind offset float _SkyStarOpacity; // --------------------------------------------------------------------------------- // Noise // --------------------------------------------------------------------------------- float hash21(float2 p) { p = frac(p * float2(123.34, 345.45)); p += dot(p, p + 34.345); return frac(p.x * p.y); } float valueNoise(float2 p) { float2 i = floor(p); float2 f = frac(p); float2 u = f * f * (3.0 - 2.0 * f); float a = hash21(i); float b = hash21(i + float2(1, 0)); float c = hash21(i + float2(0, 1)); float d = hash21(i + float2(1, 1)); return lerp(lerp(a, b, u.x), lerp(c, d, u.x), u.y); } float fbm(float2 p) { float v = 0.0; float amp = 0.5; [unroll] for (int i = 0; i < 5; i++) { v += amp * valueNoise(p); p *= 2.02; amp *= 0.5; } return v; } // Billow (turbulence) FBM: abs() folds each octave into rounded lumps, producing the // cauliflower/cumulus structure that plain value-noise FBM cannot. float billowFbm(float2 p) { float v = 0.0; float amp = 0.5; [unroll] for (int i = 0; i < 5; i++) { v += amp * abs(2.0 * valueNoise(p) - 1.0); p *= 2.03; amp *= 0.5; } return v; } // --------------------------------------------------------------------------------- // Sky pieces // --------------------------------------------------------------------------------- // Vertical zenith -> horizon -> ground ramp driven by view height (dir.y in [-1,1]). half3 SampleSkyGradient(float height) { float up = pow(saturate(height), 1.0 / _HorizonSharpness); half3 sky = lerp(_SkyHorizonColor.rgb, _SkyZenithColor.rgb, up); float down = pow(saturate(-height), 1.0 / _GroundSharpness); sky = lerp(sky, _SkyGroundColor.rgb, down); return sky; } // Planar projection of the sky onto a cloud sheet. Adding a constant to the height // (instead of dividing by a clamped near-zero) removes the hard horizon singularity // that smeared clouds into streaks, keeping puffs readable all the way down. float2 CloudPlaneUV(float3 dir) { float2 wind = _SkyCloudParams.zw; return (dir.xz / (dir.y + 0.28)) * _CloudScale + wind; } // Returns cloud coverage in .x and a fake self-shadow lighting term in .y. Big soft // masses (value FBM) are broken into rounded cumulus lumps by billow FBM, then a tight // smoothstep gives defined edges. The lighting term darkens the sun-shadowed underside // so the puffs read as volumetric rather than flat. float2 SampleClouds(float3 dir) { float2 uv = CloudPlaneUV(dir); float shape = fbm(uv * 0.6); float billow = billowFbm(uv * 1.9); float density = lerp(shape, shape * (0.5 + billow), _CloudDetail); float coverage = _SkyCloudParams.x; float cloud = smoothstep(coverage, coverage + _CloudSoftness, density); float2 lightDir = normalize(_SkySunDirection.xz + 1e-4); float lit = fbm((uv + lightDir * 0.22) * 0.6); float lighting = saturate((shape - lit) * _CloudShadingStrength + 0.55); return float2(cloud, lighting); } // Sparse twinkling star field, faded below the horizon and multiplied by night opacity. float SampleStars(float3 dir) { if (dir.y <= 0.0) return 0.0; float2 uv = (dir.xz / (dir.y + 0.35)) * _StarDensity; float2 id = floor(uv); float2 gv = frac(uv) - 0.5; float n = hash21(id); if (n < _StarThreshold) return 0.0; float twinkle = 0.6 + 0.4 * sin(_Time.y * _StarTwinkleSpeed + n * 100.0); float spark = smoothstep(_StarSize, 0.0, length(gv)); float horizon = smoothstep(0.0, 0.15, dir.y); return spark * twinkle * horizon; } // Sharp disc + soft power-falloff glow for a celestial body. void SampleBody(float3 dir, float3 bodyDir, float size, float edge, out float disc, out float glow) { float d = dot(dir, bodyDir); float inner = cos(size); float outer = cos(size + edge); disc = smoothstep(outer, inner, d); glow = pow(saturate(d), _SunGlowFalloff); } // --------------------------------------------------------------------------------- // Vertex / Fragment // --------------------------------------------------------------------------------- struct Attributes { float4 positionOS : POSITION; }; struct Varyings { float4 positionCS : SV_POSITION; float3 dirWS : TEXCOORD0; }; Varyings vert(Attributes IN) { Varyings OUT; OUT.positionCS = TransformObjectToHClip(IN.positionOS.xyz); OUT.dirWS = TransformObjectToWorldDir(IN.positionOS.xyz, false); return OUT; } half4 frag(Varyings IN) : SV_Target { float3 dir = normalize(IN.dirWS); half3 col = SampleSkyGradient(dir.y); col += SampleStars(dir) * _SkyStarOpacity; float moonDisc, moonGlowUnused; SampleBody(dir, _SkyMoonDirection.xyz, _MoonSize, _MoonEdgeSoftness, moonDisc, moonGlowUnused); col += _SkyMoonColor.rgb * moonDisc; float sunDisc, sunGlow; SampleBody(dir, _SkySunDirection.xyz, _SunSize, _SunEdgeSoftness, sunDisc, sunGlow); col += _SkySunColor.rgb * (sunGlow * _SunGlowStrength); col += _SkySunColor.rgb * sunDisc; float2 clouds = SampleClouds(dir); float horizonFade = smoothstep(0.0, _CloudHorizonFade, dir.y); float cloudAlpha = clouds.x * horizonFade * _SkyCloudParams.y; half3 cloudCol = lerp(_SkyCloudShadowColor.rgb, _SkyCloudColor.rgb, clouds.y); col = lerp(col, cloudCol, cloudAlpha); return half4(col, 1.0); } ENDHLSL } } Fallback Off }