Kelsidavis-WoWee/assets/shaders/clouds.frag.glsl

105 lines
3.4 KiB
Text
Raw Normal View History

#version 450
layout(push_constant) uniform Push {
vec4 cloudColor; // xyz = DBC-derived base cloud color, w = unused
vec4 sunDirDensity; // xyz = sun direction, w = density
vec4 windAndLight; // x = windOffset, y = sunIntensity, z = ambient, w = unused
} push;
layout(location = 0) in vec3 vWorldDir;
layout(location = 0) out vec4 outColor;
// --- Gradient noise (smoother than hash-based) ---
vec2 hash2(vec2 p) {
p = vec2(dot(p, vec2(127.1, 311.7)),
dot(p, vec2(269.5, 183.3)));
return fract(sin(p) * 43758.5453);
}
float gradientNoise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
// Quintic interpolation for smoother results
vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
float a = dot(hash2(i + vec2(0.0, 0.0)) * 2.0 - 1.0, f - vec2(0.0, 0.0));
float b = dot(hash2(i + vec2(1.0, 0.0)) * 2.0 - 1.0, f - vec2(1.0, 0.0));
float c = dot(hash2(i + vec2(0.0, 1.0)) * 2.0 - 1.0, f - vec2(0.0, 1.0));
float d = dot(hash2(i + vec2(1.0, 1.0)) * 2.0 - 1.0, f - vec2(1.0, 1.0));
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y) * 0.5 + 0.5;
}
float fbm(vec2 p) {
float val = 0.0;
float amp = 0.5;
for (int i = 0; i < 6; i++) {
val += amp * gradientNoise(p);
p *= 2.0;
amp *= 0.5;
}
return val;
}
void main() {
vec3 dir = normalize(vWorldDir);
float altitude = dir.z;
if (altitude < 0.0) discard;
vec3 sunDir = push.sunDirDensity.xyz;
float density = push.sunDirDensity.w;
float windOffset = push.windAndLight.x;
float sunIntensity = push.windAndLight.y;
float ambient = push.windAndLight.z;
vec2 uv = dir.xy / (altitude + 0.001);
uv += windOffset;
// --- 6-octave FBM for cloud shape ---
float cloud1 = fbm(uv * 0.8);
float cloud2 = fbm(uv * 1.6 + 5.0);
float cloud = cloud1 * 0.7 + cloud2 * 0.3;
// Coverage control: base coverage with detail erosion
float baseCoverage = smoothstep(0.30, 0.55, cloud);
float detailErosion = gradientNoise(uv * 4.0);
cloud = baseCoverage * smoothstep(0.2, 0.5, detailErosion);
cloud *= density;
// Horizon fade
float horizonFade = smoothstep(0.0, 0.15, altitude);
cloud *= horizonFade;
if (cloud < 0.01) discard;
// --- Sun lighting on clouds ---
// Sun dot product for view-relative brightness
float sunDot = max(dot(vec3(0.0, 0.0, 1.0), sunDir), 0.0);
// Self-shadowing: sample noise offset toward sun direction, darken if occluded
float lightSample = fbm((uv + sunDir.xy * 0.05) * 0.8);
float shadow = smoothstep(0.3, 0.7, lightSample);
// Base lit color: mix dark (shadow) and bright (sunlit) based on shadow and sun
vec3 baseColor = push.cloudColor.rgb;
vec3 shadowColor = baseColor * (ambient * 0.8);
vec3 litColor = baseColor * (ambient + sunIntensity * 0.6);
vec3 cloudRgb = mix(shadowColor, litColor, shadow * sunDot);
// Add ambient fill so clouds aren't too dark
cloudRgb = mix(baseColor * ambient, cloudRgb, 0.7 + 0.3 * sunIntensity);
// --- Silver lining effect at cloud edges ---
float edgeLight = smoothstep(0.0, 0.3, cloud) * (1.0 - smoothstep(0.3, 0.8, cloud));
cloudRgb += vec3(1.0, 0.95, 0.9) * edgeLight * sunDot * sunIntensity * 0.4;
// --- Edge softness for alpha ---
float edgeSoftness = smoothstep(0.0, 0.3, cloud);
float alpha = cloud * edgeSoftness;
if (alpha < 0.01) discard;
outColor = vec4(cloudRgb, alpha);
}