mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Enhanced sky atmosphere with DBC-driven colors, sun lighting, and zone weather
- Skybox now uses DBC sky colors (skyTop/skyMiddle/skyBand1/skyBand2) instead of hardcoded C++ color curves, with 3-band gradient and Rayleigh/Mie scattering - Clouds receive sun direction for lit edges, self-shadowing, and silver lining - Fixed sun quad box artifact with proper edge fade in celestial shader - Lens flare attenuated by fog, cloud density, and weather intensity - Replaced garish green/purple lens flare ghosts with warm natural palette - Added zone-based weather system for single-player mode with per-zone rain/snow configuration, probability-based activation, and smooth intensity transitions - Server SMSG_WEATHER remains authoritative when connected to a server
This commit is contained in:
parent
085fd09b9d
commit
6563eebb60
18 changed files with 434 additions and 252 deletions
|
|
@ -26,9 +26,21 @@ float valueNoise(vec2 p) {
|
|||
void main() {
|
||||
vec2 uv = TexCoord - 0.5;
|
||||
float dist = length(uv);
|
||||
float disc = smoothstep(0.42, 0.38, dist);
|
||||
float glow = exp(-dist * dist * 12.0) * 0.6;
|
||||
|
||||
// Hard disc with smooth edge
|
||||
float disc = smoothstep(0.42, 0.35, dist);
|
||||
|
||||
// Soft glow that fades to zero well within quad bounds
|
||||
// At dist=0.5 (quad edge), this should be negligible
|
||||
float glow = exp(-dist * dist * 18.0) * 0.5;
|
||||
|
||||
// Combine disc and glow
|
||||
float alpha = max(disc, glow) * push.intensity;
|
||||
|
||||
// Fade to zero at quad edges to prevent visible box
|
||||
float edgeFade = 1.0 - smoothstep(0.4, 0.5, dist);
|
||||
alpha *= edgeFade;
|
||||
|
||||
vec3 color = push.celestialColor.rgb;
|
||||
|
||||
// Animated haze/turbulence overlay for the sun disc
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,35 +1,42 @@
|
|||
#version 450
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 cloudColor;
|
||||
float density;
|
||||
float windOffset;
|
||||
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;
|
||||
|
||||
float hash(vec2 p) {
|
||||
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
|
||||
// --- 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 noise(vec2 p) {
|
||||
float gradientNoise(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
float a = hash(i);
|
||||
float b = hash(i + vec2(1.0, 0.0));
|
||||
float c = hash(i + vec2(0.0, 1.0));
|
||||
float d = hash(i + vec2(1.0, 1.0));
|
||||
return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
||||
|
||||
// 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 < 4; i++) {
|
||||
val += amp * noise(p);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
val += amp * gradientNoise(p);
|
||||
p *= 2.0;
|
||||
amp *= 0.5;
|
||||
}
|
||||
|
|
@ -38,26 +45,60 @@ float fbm(vec2 p) {
|
|||
|
||||
void main() {
|
||||
vec3 dir = normalize(vWorldDir);
|
||||
float altitude = dir.z; // Z is up in the Z-up world coordinate system
|
||||
float altitude = dir.z;
|
||||
if (altitude < 0.0) discard;
|
||||
|
||||
vec2 uv = dir.xy / (altitude + 0.001); // XY is the horizontal plane
|
||||
uv += push.windOffset;
|
||||
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;
|
||||
cloud = smoothstep(0.35, 0.65, cloud) * push.density;
|
||||
|
||||
float edgeBreak = noise(uv * 4.0);
|
||||
cloud *= smoothstep(0.2, 0.5, edgeBreak);
|
||||
// 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(push.cloudColor.rgb, alpha);
|
||||
outColor = vec4(cloudRgb, alpha);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -14,9 +14,11 @@ layout(set = 0, binding = 0) uniform PerFrame {
|
|||
};
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 horizonColor;
|
||||
vec4 zenithColor;
|
||||
float timeOfDay;
|
||||
vec4 zenithColor; // DBC skyTopColor
|
||||
vec4 midColor; // DBC skyMiddleColor
|
||||
vec4 horizonColor; // DBC skyBand1Color
|
||||
vec4 fogColorPush; // DBC skyBand2Color
|
||||
vec4 sunDirAndTime; // xyz = sun direction, w = timeOfDay
|
||||
} push;
|
||||
|
||||
layout(location = 0) in vec2 TexCoord;
|
||||
|
|
@ -25,27 +27,71 @@ layout(location = 0) out vec4 outColor;
|
|||
|
||||
void main() {
|
||||
// Reconstruct world-space ray direction from screen position.
|
||||
// TexCoord is [0,1]^2; convert to NDC [-1,1]^2.
|
||||
float ndcX = TexCoord.x * 2.0 - 1.0;
|
||||
float ndcY = -(TexCoord.y * 2.0 - 1.0); // flip Y: Vulkan NDC Y-down, but projection already flipped
|
||||
float ndcY = -(TexCoord.y * 2.0 - 1.0);
|
||||
|
||||
// Unproject to view space using focal lengths from projection matrix.
|
||||
// projection[0][0] = 2*near/(right-left) = 1/tan(fovX/2)
|
||||
// projection[1][1] = 2*near/(top-bottom) (already negated for Vulkan Y-flip)
|
||||
// We want the original magnitude, so take abs to get the focal length.
|
||||
vec3 viewDir = vec3(ndcX / projection[0][0],
|
||||
ndcY / abs(projection[1][1]),
|
||||
-1.0);
|
||||
|
||||
// Rotate to world space: view = R*T, so R^-1 = R^T = transpose(mat3(view))
|
||||
mat3 invViewRot = transpose(mat3(view));
|
||||
vec3 worldDir = normalize(invViewRot * viewDir);
|
||||
|
||||
// worldDir.z = sin(elevation); +1 = zenith, 0 = horizon, -1 = nadir
|
||||
float t = clamp(worldDir.z, 0.0, 1.0);
|
||||
t = pow(t, 1.5);
|
||||
vec3 sky = mix(push.horizonColor.rgb, push.zenithColor.rgb, t);
|
||||
float scatter = max(0.0, 1.0 - t * 2.0) * 0.15;
|
||||
sky += vec3(scatter * 0.8, scatter * 0.4, scatter * 0.1);
|
||||
vec3 sunDir = push.sunDirAndTime.xyz;
|
||||
float timeOfDay = push.sunDirAndTime.w;
|
||||
|
||||
// Elevation: +1 = zenith, 0 = horizon, -1 = nadir
|
||||
float elev = worldDir.z;
|
||||
float elevClamped = clamp(elev, 0.0, 1.0);
|
||||
|
||||
// --- 3-band sky gradient using DBC colors ---
|
||||
// Zenith dominates upper sky, mid color fills the middle,
|
||||
// horizon band at the bottom with a thin fog fringe.
|
||||
vec3 sky;
|
||||
if (elevClamped > 0.4) {
|
||||
// Upper sky: mid -> zenith
|
||||
float t = (elevClamped - 0.4) / 0.6;
|
||||
sky = mix(push.midColor.rgb, push.zenithColor.rgb, t);
|
||||
} else if (elevClamped > 0.05) {
|
||||
// Lower sky: horizon -> mid (wide band)
|
||||
float t = (elevClamped - 0.05) / 0.35;
|
||||
sky = mix(push.horizonColor.rgb, push.midColor.rgb, t);
|
||||
} else {
|
||||
// Thin fog fringe right at horizon
|
||||
float t = elevClamped / 0.05;
|
||||
sky = mix(push.fogColorPush.rgb, push.horizonColor.rgb, t);
|
||||
}
|
||||
|
||||
// --- Below-horizon darkening (nadir) ---
|
||||
if (elev < 0.0) {
|
||||
float nadirFade = clamp(-elev * 3.0, 0.0, 1.0);
|
||||
vec3 nadirColor = push.fogColorPush.rgb * 0.3;
|
||||
sky = mix(push.fogColorPush.rgb, nadirColor, nadirFade);
|
||||
}
|
||||
|
||||
// --- Rayleigh-like scattering (subtle warm glow near sun) ---
|
||||
float sunDot = max(dot(worldDir, sunDir), 0.0);
|
||||
float sunAboveHorizon = clamp(sunDir.z, 0.0, 1.0);
|
||||
|
||||
float rayleighStrength = pow(1.0 - elevClamped, 3.0) * 0.15;
|
||||
vec3 scatterColor = mix(vec3(0.8, 0.45, 0.15), vec3(0.3, 0.5, 1.0), elevClamped);
|
||||
sky += scatterColor * rayleighStrength * sunDot * sunAboveHorizon;
|
||||
|
||||
// --- Mie-like forward scatter (sun disk glow) ---
|
||||
float mieSharp = pow(sunDot, 64.0) * 0.4;
|
||||
float mieSoft = pow(sunDot, 8.0) * 0.1;
|
||||
vec3 sunGlowColor = mix(vec3(1.0, 0.85, 0.55), vec3(1.0, 1.0, 0.95), elevClamped);
|
||||
sky += sunGlowColor * (mieSharp + mieSoft) * sunAboveHorizon;
|
||||
|
||||
// --- Subtle horizon haze ---
|
||||
float hazeDensity = exp(-elevClamped * 12.0) * 0.06;
|
||||
sky += push.horizonColor.rgb * hazeDensity * sunAboveHorizon;
|
||||
|
||||
// --- Night: slight moonlight tint ---
|
||||
if (sunDir.z < 0.0) {
|
||||
float moonlight = clamp(-sunDir.z * 0.5, 0.0, 0.15);
|
||||
sky += vec3(0.02, 0.03, 0.08) * moonlight;
|
||||
}
|
||||
|
||||
outColor = vec4(sky, 1.0);
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue