168 lines
6.7 KiB
HLSL
168 lines
6.7 KiB
HLSL
#ifndef FOG_INCLUDED
|
|
#define FOG_INCLUDED
|
|
|
|
// Animated fog: the exact noise pattern doesn't matter, use the cheaper hash
|
|
#define NOISES_FAST_HASH
|
|
#include "Assets/_Content/Shaders/Include/Noises.hlsl"
|
|
|
|
// ------------------------------------------------------------
|
|
// FOG - meme famille stylistique que Water.hlsl :
|
|
// - densite "posterizee" en bandes plutot qu'un degrade lisse
|
|
// - bord de silhouette irregulier (jitter), comme dessine a la main
|
|
// Les couleurs exposees (ColorA/ColorB/DepthAtten) ne sont pas touchees,
|
|
// seule la facon dont la densite/alpha est construite change.
|
|
// ------------------------------------------------------------
|
|
|
|
// ============================================================
|
|
// TUNING
|
|
// ============================================================
|
|
#define FOG_POSTERIZE_STEPS 5.0 // nombre de "bandes" de densite (moins = plus graphique)
|
|
#define FOG_COLOR_BAND_STEPS 4.0 // nombre de poches de couleur distinctes entre ColorA/ColorB
|
|
#define FOG_EDGE_JITTER 0.16 // irregularite du bord de la silhouette
|
|
#define FOG_LINE_WIDTH 1.2 // epaisseur des lignes (meme logique que l'horizon de l'eau)
|
|
#define FOG_LINE_OPACITY 0.3 // intensite des lignes
|
|
|
|
// Always-on fine grain, added on top of the banded color output to
|
|
// break up the flat look of each posterized band/pocket. Additive
|
|
// (not multiplicative like a simple *grain), so it stays visible in
|
|
// dark bands instead of fading out near black.
|
|
#define FOG_FINE_GRAIN_SCALE_A 6.0
|
|
#define FOG_FINE_GRAIN_SCALE_B 23.0
|
|
#define FOG_FINE_GRAIN_WEIGHT_A 0.6
|
|
#define FOG_FINE_GRAIN_WEIGHT_B 0.4
|
|
#define FOG_FINE_GRAIN_STRENGTH 0.03
|
|
#define FOG_FINE_GRAIN_SCROLL 0.02 // world-space drift speed, keeps the grain from looking screen-locked
|
|
|
|
// ============================================================
|
|
// UTILS
|
|
// ============================================================
|
|
|
|
float FogPosterize(float v, float steps)
|
|
{
|
|
return floor(saturate(v) * steps) / steps;
|
|
}
|
|
|
|
// Isoligne fine sur un champ continu (meme technique que les lignes
|
|
// d'horizon de l'eau) : une ligne independante a une valeur donnee,
|
|
// PAS une bordure de region remplie -> lecture "courant qui coule"
|
|
// plutot que "carte/cellules".
|
|
float FogThinContour(float field, float level, float pixelWidth)
|
|
{
|
|
float fw = fwidth(field) * pixelWidth;
|
|
fw = max(fw, 1e-5);
|
|
return 1.0 - smoothstep(0.0, fw, abs(field - level));
|
|
}
|
|
|
|
// Cheap value noise: 4 hash taps + bilinear interpolation, no FBM
|
|
// octaves needed. Much cheaper than another FBMNoise3D call and
|
|
// plenty for fine dither-grain -- this is meant to break flatness,
|
|
// not add structure.
|
|
float FogHash(float n)
|
|
{
|
|
return frac(sin(n) * 43758.5453123);
|
|
}
|
|
|
|
float FogCheapValueNoise(float2 uv)
|
|
{
|
|
float2 i = floor(uv);
|
|
float2 f = frac(uv);
|
|
|
|
float a = FogHash(i.x + i.y * 57.0);
|
|
float b = FogHash(i.x + 1.0 + i.y * 57.0);
|
|
float c = FogHash(i.x + (i.y + 1.0) * 57.0);
|
|
float d = FogHash(i.x + 1.0 + (i.y + 1.0) * 57.0);
|
|
|
|
f = f * f * (3.0 - 2.0 * f); // smoothstep interpolation
|
|
return lerp(lerp(a, b, f.x), lerp(c, d, f.x), f.y);
|
|
}
|
|
|
|
void Fog_float
|
|
(
|
|
float4 ColorA,
|
|
float4 ColorB,
|
|
float DepthAtten,
|
|
float3 PositionWS,
|
|
float3 PositionOS,
|
|
float3 PivotWS,
|
|
float3 Scale,
|
|
out float3 Output,
|
|
out float Alpha
|
|
)
|
|
{
|
|
// Test
|
|
|
|
//float test = ValueNoise3D(PositionWS, 40);
|
|
//float test = PerlinNoise3D(PositionWS, 40);
|
|
//float test = PerlinNoise3DLOD(PositionWS, 100, 3.5);
|
|
//float test = SimplexNoise3D(PositionWS, 40);
|
|
//float test = WorleyNoise3D(PositionWS, 40, 1);
|
|
//float id;
|
|
//float test = VoronoiNoise3D(PositionWS, 10, 1, .05, id);
|
|
//float test = FBMNoise3D(PositionWS, 10, 2, 2, .5);
|
|
//float test = RidgedNoise3D(PositionWS, 10, 2, 2, .5);
|
|
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);
|
|
|
|
|
|
float3 p = PositionWS;// - PivotWS;
|
|
p += float3(t, t * .2, t);
|
|
|
|
float noise = RidgedNoise3D(p - PivotWS * .9, .1, 5, 1.6, 1);
|
|
|
|
p += noise * 3;
|
|
|
|
float fog = FBMNoise3D((p - PivotWS * .5), 10 / s, 3, 1.5, .5);
|
|
|
|
// --- densite "posterizee" en bandes, comme l'eau : casse le
|
|
// degrade lisse en paliers, plus graphique/grave ---
|
|
float fogBanded = FogPosterize(fog, FOG_POSTERIZE_STEPS);
|
|
|
|
// --- blend ColorA/ColorB en poches distinctes plutot qu'un
|
|
// degrade continu -> evite l'effet "voile uniforme" ---
|
|
float colorFactor = saturate(RidgedNoise3D((p - PivotWS * .9) * float3(1, 1.6, 1), 3 / s, 3, 1.6, 1));
|
|
float colorFactorBanded = FogPosterize(colorFactor, FOG_COLOR_BAND_STEPS);
|
|
float4 col = lerp(ColorA, ColorB, colorFactorBanded);
|
|
|
|
// --- bord de silhouette irregulier : on jitter le seuil utilise
|
|
// par le mask, pour que le contour du brouillard ne soit pas une
|
|
// courbe parfaitement lisse mais quelque chose de dessine a la main ---
|
|
float edgeJitter = (FBMNoise3D(PositionWS * 0.5 + float3(t * 0.4, t * 0.15, t * 0.3) + float3(820.0, 137.0, 55.0), 1.0, 3, 2.0, 0.5) - 0.5) * FOG_EDGE_JITTER;
|
|
|
|
float mask = smoothstep(0, lerp(.3, .1, depthAtten), PositionOS.y + edgeJitter) * pow(smoothstep(1, .5, PositionOS.y - .15 + noise * .3 + edgeJitter * 0.5), 2);
|
|
|
|
// --- lignes fines flottantes, comme l'horizon de l'eau : plusieurs
|
|
// isolignes independantes sur le champ continu (pas des bordures
|
|
// de region), elles bougent naturellement car le champ derive
|
|
// deja dans le temps (via "t" ajoute a "p" plus haut) ---
|
|
float fogLines = 0.0;
|
|
fogLines += FogThinContour(colorFactor, 0.30, FOG_LINE_WIDTH);
|
|
fogLines += FogThinContour(colorFactor, 0.50, FOG_LINE_WIDTH);
|
|
fogLines += FogThinContour(colorFactor, 0.70, FOG_LINE_WIDTH);
|
|
fogLines = saturate(fogLines) * mask;
|
|
|
|
// Output
|
|
|
|
Output = lerp(col.rgb, float3(0.0, 0.0, 0.0), fogLines * FOG_LINE_OPACITY);
|
|
|
|
// Always-on fine grain, applied last so it sits on top of the
|
|
// banded color/lines instead of getting smoothed away by them.
|
|
// Two octaves at different scales avoid an obvious repeating
|
|
// pattern; sampled in world XZ + a slow time offset so it drifts
|
|
// instead of looking baked onto the mesh.
|
|
float2 grainUV = PositionWS.xz + t * FOG_FINE_GRAIN_SCROLL;
|
|
float fineGrain = FogCheapValueNoise(grainUV * FOG_FINE_GRAIN_SCALE_A) * FOG_FINE_GRAIN_WEIGHT_A
|
|
+ FogCheapValueNoise(grainUV * FOG_FINE_GRAIN_SCALE_B) * FOG_FINE_GRAIN_WEIGHT_B;
|
|
Output += (fineGrain - 0.5) * FOG_FINE_GRAIN_STRENGTH;
|
|
Output = saturate(Output);
|
|
|
|
float baseAlpha = lerp(fogBanded, smoothstep(1, .5, PositionOS.y), depthAtten * mask) * lerp(.2, 1, smoothstep(0, 15, depth)) * mask * col.a;
|
|
Alpha = saturate(baseAlpha);
|
|
}
|
|
|
|
#endif
|