#include "hd2d/Weather.h" #include "hd2d/Renderer.h" #include #include namespace hd2d { Weather::Weather() { // Heavy overcast rain: weak grey sun, flat cool ambient, thick low fog, // almost no god rays, strong gusty wind. storm.sunIntensity = 0.7f; storm.sunColor = {0.78f, 0.82f, 0.9f}; storm.zenith = {0.30f, 0.34f, 0.40f}; storm.horizon = {0.42f, 0.45f, 0.50f}; storm.ground = {0.13f, 0.15f, 0.13f}; storm.ambient = 0.62f; storm.fogColor = {0.30f, 0.33f, 0.38f}; storm.fogDensity = 0.03f; storm.fogHeightFalloff = 0.22f; storm.godRays = 0.6f; storm.shaftStrength = 0.2f; storm.cookieStrength = 0.0f; storm.windStrength = 0.2f; storm.windGustSpeed = 3.0f; storm.bloomStrength = 0.06f; storm.saturation = 0.82f; } WeatherLook Weather::capture(const Scene& s, const RenderSettings& r) { WeatherLook l; l.sunIntensity = s.sun.intensity; l.sunColor = s.sun.color; l.zenith = s.sky.zenith; l.horizon = s.sky.horizon; l.ground = s.sky.ground; l.ambient = s.sky.ambient; l.fogColor = r.fogColor; l.fogDensity = r.fogDensity; l.fogHeightFalloff = r.fogHeightFalloff; l.godRays = r.godRayIntensity; l.shaftStrength = r.shaftStrength; l.cookieStrength = r.cookieStrength; l.windStrength = r.windStrength; l.windGustSpeed = r.windGustSpeed; l.bloomStrength = r.bloomStrength; l.saturation = r.saturation; return l; } void Weather::apply(const WeatherLook& l, Scene& s, RenderSettings& r) { s.sun.intensity = l.sunIntensity; s.sun.color = l.sunColor; s.sky.zenith = l.zenith; s.sky.horizon = l.horizon; s.sky.ground = l.ground; s.sky.ambient = l.ambient; r.fogColor = l.fogColor; r.fogDensity = l.fogDensity; r.fogHeightFalloff = l.fogHeightFalloff; r.godRayIntensity = l.godRays; r.shaftStrength = l.shaftStrength; r.cookieStrength = l.cookieStrength; r.windStrength = l.windStrength; r.windGustSpeed = l.windGustSpeed; r.bloomStrength = l.bloomStrength; r.saturation = l.saturation; } static WeatherLook mixLook(const WeatherLook& a, const WeatherLook& b, float t) { WeatherLook o; auto m = [t](auto x, auto y) { return x + (y - x) * t; }; o.sunIntensity = m(a.sunIntensity, b.sunIntensity); o.sunColor = m(a.sunColor, b.sunColor); o.zenith = m(a.zenith, b.zenith); o.horizon = m(a.horizon, b.horizon); o.ground = m(a.ground, b.ground); o.ambient = m(a.ambient, b.ambient); o.fogColor = m(a.fogColor, b.fogColor); o.fogDensity = m(a.fogDensity, b.fogDensity); o.fogHeightFalloff = m(a.fogHeightFalloff, b.fogHeightFalloff); o.godRays = m(a.godRays, b.godRays); o.shaftStrength = m(a.shaftStrength, b.shaftStrength); o.cookieStrength = m(a.cookieStrength, b.cookieStrength); o.windStrength = m(a.windStrength, b.windStrength); o.windGustSpeed = m(a.windGustSpeed, b.windGustSpeed); o.bloomStrength = m(a.bloomStrength, b.bloomStrength); o.saturation = m(a.saturation, b.saturation); return o; } void Weather::update(float dt, Scene& scene, RenderSettings& settings) { // While fully clear, keep tracking the live look so UI tweaks survive. if (rain_ <= 0.0f && targetRain_ <= 0.0f) { clear_ = capture(scene, settings); haveClear_ = true; } else if (!haveClear_) { clear_ = capture(scene, settings); haveClear_ = true; } float step = dt / std::max(transitionSeconds, 1e-3f); rain_ = rain_ < targetRain_ ? std::min(targetRain_, rain_ + step) : std::max(targetRain_, rain_ - step); // Surfaces soak quickly and dry slowly. float wetRate = wetness_ < rain_ ? step * 1.5f : step * 0.3f; wetness_ = wetness_ < rain_ ? std::min(rain_, wetness_ + wetRate) : std::max(rain_, wetness_ - wetRate); float k = rain_ * rain_ * (3.0f - 2.0f * rain_); // smoothstep if (rain_ > 0.0f || targetRain_ > 0.0f) apply(mixLook(clear_, storm, k), scene, settings); scene.rain = rain_; scene.wetness = wetness_; if (scene.particles) { ParticleSystem& ps = *scene.particles; ps.ambientFade = 1.0f - k; glm::vec2 wd = glm::length(settings.windDirection) > 1e-4f ? glm::normalize(settings.windDirection) : glm::vec2(1, 0); ps.wind = glm::vec3(wd.x, 0.0f, wd.y) * settings.windStrength * 10.0f; // Ground splashes around the focus point (water gets ripples instead). splashAccum_ += splashesPerSecond * rain_ * dt; std::uniform_real_distribution u(-1.0f, 1.0f); glm::vec3 color = (scene.sky.horizon * 0.8f + glm::vec3(0.15f)) * scene.sky.ambient * 1.6f; while (splashAccum_ >= 1.0f) { splashAccum_ -= 1.0f; glm::vec2 p = glm::vec2(scene.focusPoint.x, scene.focusPoint.z) + glm::vec2(u(rng_), u(rng_)) * splashRadius; if (!scene.terrain) continue; float y = scene.terrain->heightAt(p.x, p.y); if (scene.water && y < scene.water->level()) continue; ps.burst({p.x, y + 0.02f, p.y}, 2, color, 0.9f, 0.022f, 0.28f); } } } } // namespace hd2d