Files
Ipseity-Demo/Assets/_Content/Models/VFX/Fog/ShadersB/Fog.hlsl
T

297 lines
12 KiB
HLSL

#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,
float FogStartTime,
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 - FogStartTime) * .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 ---
// Transitions narrowed around the same centers (.2 / .5 / .8) as before: each
// quantized PaintSteps level now resolves closer to a pure A/B/C/D color instead
// of a muddier blend, giving a cleaner, more graphic/poster-like read.
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.16, 0.24, paintMask));
col = lerp(col, ColorC, smoothstep(0.46, 0.54, paintMask));
col = lerp(col, ColorD, smoothstep(0.76, 0.84, paintMask));
float luma = dot(col.rgb, float3(0.299, 0.587, 0.114));
col.rgb = lerp(col.rgb, luma.xxx, 0.2); // slightly more desaturated toward gray -> muted, graphic-novel mood
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);
// --- Heavy black ink outline + scattered grime/dirt (Enki Bilal style) ---
// mask*(1-mask) peaks exactly where a smoothstep is mid-transition, so the line always
// lands right on the silhouette boundary no matter how small/large spikeField or barField
// happen to be -- no fragile inset constants, no screen-space derivatives needed.
// A low power + a gain pass fattens that peak into a bold, mostly-solid core instead of
// a thin soft gradient line; the existing noise fields break it up so it reads as a rough
// ink/charcoal stroke rather than a clean vector ring.
float spikeRim = saturate(pow(4 * spikeMask * (1 - spikeMask), 0.4));
spikeRim = saturate(spikeRim * 1.6);
spikeRim *= lerp(0.4, 1.0, veins);
float barRim = saturate(pow(4 * barMask * (1 - barMask), 0.4));
barRim = saturate(barRim * 1.6);
barRim *= lerp(0.45, 1.0, saturate(grain * 0.5 + 0.5));
float inkRim = saturate(spikeRim + barRim);
col.rgb = lerp(col.rgb, float3(0, 0, 0), inkRim); // genuinely black, not a tinted wash
// Grime: independent dark smudges scattered across the whole surface, not tied to any silhouette
float grimeNoise = saturate(FBMNoise3D(PositionWS * 4 + float3(t * 0.05, 0, 0), 5, 3, 2, .5));
float grimeMask = smoothstep(0.5, 0.58, grimeNoise) * (1 - smoothstep(0.8, 0.9, grimeNoise));
col.rgb = lerp(col.rgb, float3(0, 0, 0), grimeMask * 0.75);
// --- Final output ---
Output = saturate(col.rgb);
Alpha = saturate(fog * combinedMask * lerp(.2, 1, smoothstep(0, 15, depth)) * col.a);
}
#endif
#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,
float FogStartTime,
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 - FogStartTime) * .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 ---
// Transitions narrowed around the same centers (.2 / .5 / .8) as before: each
// quantized PaintSteps level now resolves closer to a pure A/B/C/D color instead
// of a muddier blend, giving a cleaner, more graphic/poster-like read.
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.16, 0.24, paintMask));
col = lerp(col, ColorC, smoothstep(0.46, 0.54, paintMask));
col = lerp(col, ColorD, smoothstep(0.76, 0.84, paintMask));
float luma = dot(col.rgb, float3(0.299, 0.587, 0.114));
col.rgb = lerp(col.rgb, luma.xxx, 0.2); // slightly more desaturated toward gray -> muted, graphic-novel mood
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);
// --- Heavy black ink outline + scattered grime/dirt (Enki Bilal style) ---
// mask*(1-mask) peaks exactly where a smoothstep is mid-transition, so the line always
// lands right on the silhouette boundary no matter how small/large spikeField or barField
// happen to be -- no fragile inset constants, no screen-space derivatives needed.
// A low power + a gain pass fattens that peak into a bold, mostly-solid core instead of
// a thin soft gradient line; the existing noise fields break it up so it reads as a rough
// ink/charcoal stroke rather than a clean vector ring.
float spikeRim = saturate(pow(4 * spikeMask * (1 - spikeMask), 0.4));
spikeRim = saturate(spikeRim * 1.6);
spikeRim *= lerp(0.4, 1.0, veins);
float barRim = saturate(pow(4 * barMask * (1 - barMask), 0.4));
barRim = saturate(barRim * 1.6);
barRim *= lerp(0.45, 1.0, saturate(grain * 0.5 + 0.5));
float inkRim = saturate(spikeRim + barRim);
col.rgb = lerp(col.rgb, float3(0, 0, 0), inkRim); // genuinely black, not a tinted wash
// Grime: independent dark smudges scattered across the whole surface, not tied to any silhouette
float grimeNoise = saturate(FBMNoise3D(PositionWS * 4 + float3(t * 0.05, 0, 0), 5, 3, 2, .5));
float grimeMask = smoothstep(0.5, 0.58, grimeNoise) * (1 - smoothstep(0.8, 0.9, grimeNoise));
col.rgb = lerp(col.rgb, float3(0, 0, 0), grimeMask * 0.75);
// --- Final output ---
Output = saturate(col.rgb);
Alpha = saturate(fog * combinedMask * lerp(.2, 1, smoothstep(0, 15, depth)) * col.a);
}
#endif