99 lines
3.8 KiB
GLSL
99 lines
3.8 KiB
GLSL
uniform sampler2D m_ExploreMap;
|
||
uniform float m_Time;
|
||
uniform vec2 m_OverlayOrigin;
|
||
uniform vec2 m_OverlaySize;
|
||
uniform float m_FadePx;
|
||
|
||
in vec2 texCoord;
|
||
out vec4 outFragColor;
|
||
|
||
// ── Procedural Value Noise ────────────────────────────────────────────────────
|
||
|
||
float hash(vec2 p) {
|
||
vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));
|
||
p3 += dot(p3, p3.yzx + 33.33);
|
||
return fract((p3.x + p3.y) * p3.z);
|
||
}
|
||
|
||
float vnoise(vec2 p) {
|
||
vec2 i = floor(p);
|
||
vec2 f = fract(p);
|
||
f = f * f * (3.0 - 2.0 * f);
|
||
return mix(
|
||
mix(hash(i), hash(i + vec2(1.0, 0.0)), f.x),
|
||
mix(hash(i + vec2(0.0,1.0)), hash(i + vec2(1.0, 1.0)), f.x),
|
||
f.y);
|
||
}
|
||
|
||
// FBM: 3 Oktaven
|
||
float fbm(vec2 p) {
|
||
float v = 0.0;
|
||
v += vnoise(p) * 0.500;
|
||
v += vnoise(p * 2.1 + vec2(1.7, 9.2)) * 0.250;
|
||
v += vnoise(p * 4.3 + vec2(8.3, 2.8)) * 0.125;
|
||
return v / 0.875;
|
||
}
|
||
|
||
// ── Hauptprogramm ─────────────────────────────────────────────────────────────
|
||
|
||
void main() {
|
||
|
||
// Weichgezeichnete Erkundungsmaske (3×3-Kernel, 8-Texel-Radius = ~32 m)
|
||
float ts = 8.0 / 512.0;
|
||
float density =
|
||
texture(m_ExploreMap, texCoord + vec2(-ts,-ts)).a +
|
||
texture(m_ExploreMap, texCoord + vec2(0.0,-ts)).a +
|
||
texture(m_ExploreMap, texCoord + vec2( ts,-ts)).a +
|
||
texture(m_ExploreMap, texCoord + vec2(-ts, 0.0)).a +
|
||
texture(m_ExploreMap, texCoord ).a +
|
||
texture(m_ExploreMap, texCoord + vec2( ts, 0.0)).a +
|
||
texture(m_ExploreMap, texCoord + vec2(-ts, ts)).a +
|
||
texture(m_ExploreMap, texCoord + vec2(0.0, ts)).a +
|
||
texture(m_ExploreMap, texCoord + vec2( ts, ts)).a;
|
||
density /= 9.0;
|
||
|
||
// Vollständig erkundet → diesen Fragment überspringen
|
||
if (density <= 0.0) { discard; }
|
||
|
||
// ── Animierter Nebel mit Domain-Warping ───────────────────────────────────
|
||
|
||
float t = m_Time * 0.18;
|
||
vec2 uv = texCoord;
|
||
|
||
// Erste Warp-Schicht: langsam driftende Wirbel
|
||
vec2 q = vec2(
|
||
fbm(uv * 2.5 + vec2(t * 0.40, t * 0.15)),
|
||
fbm(uv * 2.5 + vec2(t * 0.15, t * 0.30) + vec2(5.2, 1.3))
|
||
);
|
||
|
||
// Zweite Warp-Schicht: gibt Tiefe und Komplexität
|
||
vec2 r = vec2(
|
||
fbm(uv * 2.0 + q * 0.9 + vec2(1.7, 9.2) + vec2(t * 0.10, 0.0)),
|
||
fbm(uv * 2.0 + q * 0.9 + vec2(8.3, 2.8) + vec2(0.0, t * 0.08))
|
||
);
|
||
|
||
// Finaler Noise-Wert [0..1]
|
||
float f = fbm(uv * 3.0 + r * 1.2 + vec2(t * 0.05, t * 0.04));
|
||
|
||
// ── Farbe + Alpha ─────────────────────────────────────────────────────────
|
||
|
||
// Dunkles Blaugrau – etwas heller an den "Schwaden"
|
||
vec3 fogColor = mix(
|
||
vec3(0.04, 0.05, 0.09), // tiefer Schatten
|
||
vec3(0.11, 0.13, 0.20), // heller Dunst
|
||
f
|
||
);
|
||
|
||
// Weich-Übergang am Overlay-Rand (Screen-Space, zoom-unabhängig)
|
||
float distL = gl_FragCoord.x - m_OverlayOrigin.x;
|
||
float distR = (m_OverlayOrigin.x + m_OverlaySize.x) - gl_FragCoord.x;
|
||
float distB = gl_FragCoord.y - m_OverlayOrigin.y;
|
||
float distT = (m_OverlayOrigin.y + m_OverlaySize.y) - gl_FragCoord.y;
|
||
float edgeFade = clamp(min(min(distL, distR), min(distB, distT)) / m_FadePx, 0.0, 1.0);
|
||
|
||
// Alpha: voll opak im unentdeckten Innern, weicher Rand durch Kernel + Edge-Fade
|
||
float alpha = density * (0.88 + f * 0.12) * edgeFade;
|
||
|
||
outFragColor = vec4(fogColor, alpha);
|
||
}
|