#ifndef FOG_INCLUDED #define FOG_INCLUDED #include "Assets/_Content/Shaders/Include/Noises.hlsl" void Fog_float ( float4 ColorA, float4 ColorB, float4 ColorC, float4 ColorD, float DepthAtten, float3 PositionWS, float3 PositionOS, float3 PivotWS, float3 Scale, float SpikeAmount, float SpikeScale, float SpikeTilt, float SpikeSpeed, float PaintSteps, float GrainAmount, out float3 Output, out float Alpha ) { float3 camPos = _WorldSpaceCameraPos.xyz; float depth = distance(camPos, PositionWS); float depthAtten = lerp(1, smoothstep(5, 30, depth), DepthAtten); float t = _Time.y * .7; float s = lerp(Scale.x, 1, .3); // Base sampling position, scrolling over time float3 p = PositionWS; p += float3(t, t * .2, t); // Domain warp for organic fog shapes float noise = RidgedNoise3D(p - PivotWS * .9, .1, 5, 1.6, 1); p += noise * 3; // Base fog density float fog = saturate(FBMNoise3D((p - PivotWS * .5), 10 / s, 3, 1.5, .5)); // --- Painterly grain --- float grain = FBMNoise3D(PositionWS * 25, 4, 2, 2, .5); grain = grain * 2 - 1; // --- Color bands --- float colorMask = saturate(RidgedNoise3D((p - PivotWS * .9) * float3(1, 1.6, 1), 3 / s, 3, 1.6, 1)); float paintMask = saturate(colorMask + grain * 0.03); paintMask = floor(paintMask * PaintSteps) / max(PaintSteps - 1, 1); float4 col = lerp(ColorA, ColorB, smoothstep(0.0, 0.4, paintMask)); col = lerp(col, ColorC, smoothstep(0.35, 0.65, paintMask)); col = lerp(col, ColorD, smoothstep(0.6, 1.0, paintMask)); float luma = dot(col.rgb, float3(0.299, 0.587, 0.114)); col.rgb = lerp(col.rgb, luma.xxx, 0.15); col.rgb *= (1 + grain * GrainAmount); // --- Ground glow --- float height01 = saturate(PositionOS.y / 0.3); float groundMask = pow(1 - height01, 2); // --- Reference vector from pivot --- float2 radial = PositionWS.xz - PivotWS.xz; // Smooth left/right factor, zero exactly at the front/back seams of the circle float sideSign = clamp(radial.x / (Scale.x * 0.3 + 0.001), -1, 1); // Tangential direction (= "around the circle") float2 tangentDir = normalize(float2(-radial.y, radial.x)); // --- Spikes: lean + drift tangentially, direction flips per side --- float2 spikeXZ = radial + tangentDir * (SpikeTilt * height01 * sideSign); // Tangential animation, same sign as the lean -> each half rotates outward, opposite directions spikeXZ += tangentDir * (t * SpikeSpeed * sideSign); // Horizontal-only animation, drifting outward (same direction as the tilt) spikeXZ.y -= t * SpikeSpeed * sideSign; // Low frequency field defines the spike's overall height/silhouette // (low freq -> the lean doesn't break the shape into zigzags) float spikeField = saturate(FBMNoise3D(float3(spikeXZ.x, spikeXZ.y, 0), SpikeScale * 0.3, 3, 2, .5)); spikeField = pow(spikeField, 4) * SpikeAmount; spikeField = min(spikeField, 0.7); // never reaches the sky // High frequency detail -> subtle jagged/organic edges only float edgeWarp = RidgedNoise3D(float3(spikeXZ * 4, t * 0.1), .1, 3, 2, .5); float veins = RidgedNoise3D(float3(spikeXZ * 12, t * 0.05), .1, 4, 2.2, .6); spikeField *= lerp(0.75, 1.0, veins); float spikeMask = smoothstep(spikeField, spikeField - 0.04, height01 + edgeWarp * 0.02); // --- Tall organic bars reaching toward the sky --- float2 barXZ = radial + float2(SpikeTilt * 0.3 * height01 * sideSign, 0); float phase = FBMNoise3D(float3(radial * 0.2, t * 0.02), 1, 2, 2, .5) * 6.2831; float wobble = sin(height01 * 6.2831 * 1.5 + phase) * 2.5 * height01; barXZ.x += wobble; float barField = saturate(FBMNoise3D(float3(barXZ * 0.4, t * 0.02), 1, 3, 2, .5)); barField = saturate(pow(barField, 3) * 1.1); float barMask = smoothstep(barField, barField - 0.2, height01); // --- Combine --- float combinedMask = saturate(max(groundMask, max(spikeMask, barMask))); // Spikes read as red glowing veins; bars keep the painted color bands col.rgb = lerp(col.rgb, ColorA.rgb, spikeMask); // --- Final output --- Output = saturate(col.rgb); Alpha = saturate(fog * combinedMask * lerp(.2, 1, smoothstep(0, 15, depth)) * col.a); } #endif