diff --git a/res/presets/weather/rain.json b/res/presets/weather/rain.json index a193978c..56f35063 100644 --- a/res/presets/weather/rain.json +++ b/res/presets/weather/rain.json @@ -12,7 +12,8 @@ "particles:rain_splash_1", "particles:rain_splash_2" ] - } + }, + "min_opacity": 0.8 }, "fog_opacity": 0.8, "fog_dencity": 2.0, diff --git a/res/presets/weather/snow.json b/res/presets/weather/snow.json index 04b77462..7c7b9a15 100644 --- a/res/presets/weather/snow.json +++ b/res/presets/weather/snow.json @@ -3,7 +3,10 @@ "vspeed": 0.75, "hspeed": 0.5, "texture": "misc/snow", - "scale": 0.35 + "scale": 0.35, + "opaque": true, + "min_opacity": 0.8, + "max_opacity": 2.0 }, "fog_opacity": 0.8, "fog_dencity": 2.5, diff --git a/res/textures/misc/snow.png b/res/textures/misc/snow.png index a687e841..107eacb4 100644 Binary files a/res/textures/misc/snow.png and b/res/textures/misc/snow.png differ diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 62fc747d..5926cdf2 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -210,7 +210,7 @@ void LevelScreen::update(float delta) { hud->update(hudVisible); decorator->update( - hud->isPause() ? 0.0f : delta, *camera, worldRenderer->weather + hud->isPause() ? 0.0f : delta, *camera, worldRenderer->weatherInstances.at(0) ); } diff --git a/src/graphics/render/PrecipitationRenderer.cpp b/src/graphics/render/PrecipitationRenderer.cpp index beef0ed1..2b626921 100644 --- a/src/graphics/render/PrecipitationRenderer.cpp +++ b/src/graphics/render/PrecipitationRenderer.cpp @@ -127,7 +127,11 @@ void PrecipitationRenderer::render( {{0, 0, 1}, {1, 0, 0}}, }; + bool cutBack = glm::dot(camera.up, glm::vec3(0, 1, 0)) > 0.35f * camera.getFov(); for (const auto& face : faces) { + if (glm::dot(camera.right, face.right) < 0.0f && cutBack) { + continue; + } for (int lx = -radius; lx <= radius; lx++) { for (int lz = depth; lz > 0; lz--) { // Position calculations diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 06952ad9..4df63e2f 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -102,8 +102,15 @@ WorldRenderer::WorldRenderer( assets->require("skybox_gen") ); - weather = {}; + WeatherPreset weather = {}; weather.deserialize(io::read_json("res:presets/weather/rain.json")); + weather.intensity = 0.5f; + weatherInstances.push_back(std::move(weather)); + + weather = {}; + weather.deserialize(io::read_json("res:presets/weather/snow.json")); + weather.intensity = 0.5f; + weatherInstances.push_back(std::move(weather)); } WorldRenderer::~WorldRenderer() = default; @@ -122,9 +129,18 @@ void WorldRenderer::setupWorldShader( shader.uniform1f("u_gamma", settings.graphics.gamma.get()); shader.uniform1f("u_fogFactor", fogFactor); shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get()); - shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity * weather.intensity); - shader.uniform1f("u_weatherFogDencity", weather.fogDencity); - shader.uniform1f("u_weatherFogCurve", weather.fogCurve); + + float fog_opacity = 0.0f; + float fog_dencity = 0.0f; + float fog_curve = 0.0f; + for (const auto& weather : weatherInstances) { + fog_opacity += weather.fogOpacity * weather.intensity; + fog_dencity += weather.fogDencity * weather.intensity; + fog_curve += weather.fogCurve * weather.intensity; + } + shader.uniform1f("u_weatherFogOpacity", fog_opacity); + shader.uniform1f("u_weatherFogDencity", fog_dencity); + shader.uniform1f("u_weatherFogCurve", fog_curve); shader.uniform1f("u_dayTime", level.getWorld()->getInfo().daytime); shader.uniform2f("u_lightDir", skybox->getLightDir()); shader.uniform3f("u_cameraPos", camera.position); @@ -200,13 +216,16 @@ void WorldRenderer::renderLevel( } setupWorldShader(entityShader, camera, settings, fogFactor); - entityShader.uniform1i("u_alphaClip", false); - float zero = weather.fall.minOpacity; - entityShader.uniform1f("u_opacity", (weather.intensity * (1.0f - zero)) + zero); - if (weather.intensity > 1.e-3f && !weather.fall.texture.empty()) { - precipitation->render(camera, pause ? 0.0f : delta, weather); + + for (const auto& weather : weatherInstances) { + float zero = weather.fall.minOpacity; + float one = weather.fall.maxOpacity; + entityShader.uniform1i("u_alphaClip", weather.fall.opaque); + entityShader.uniform1f("u_opacity", (weather.intensity * (one - zero)) + zero); + if (weather.intensity > 1.e-3f && !weather.fall.texture.empty()) { + precipitation->render(camera, pause ? 0.0f : delta, weather); + } } - //weather.intensity = -glm::cos(timer * 0.2f) * 0.5f + 0.5f; skybox->unbind(); } @@ -336,11 +355,12 @@ void WorldRenderer::draw( const auto& settings = engine.getSettings(); const auto& worldInfo = world->getInfo(); - - float mie = 1.0f + glm::max( - worldInfo.fog, - weather.clouds * glm::sqrt(weather.intensity) * 0.5f - ) * 2.0f; + float clouds = 0.0f; + for (const auto& weather : weatherInstances) { + clouds += weather.clouds * glm::sqrt(weather.intensity); + } + clouds = glm::max(worldInfo.fog, clouds); + float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f; skybox->refresh(pctx, worldInfo.daytime, mie, 4); @@ -354,7 +374,7 @@ void WorldRenderer::draw( Window::clearDepth(); // Drawing background sky plane - skybox->draw(pctx, camera, assets, worldInfo.daytime, mie); + skybox->draw(pctx, camera, assets, worldInfo.daytime, clouds); /* Actually world render with depth buffer on */ { DrawContext ctx = wctx.sub(); diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index 4ac9299c..78d81a15 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -75,7 +75,7 @@ public: std::unique_ptr particles; std::unique_ptr blockWraps; std::unique_ptr precipitation; - WeatherPreset weather; + std::vector weatherInstances; static bool showChunkBorders; static bool showEntitiesDebug; diff --git a/src/presets/WeatherPreset.cpp b/src/presets/WeatherPreset.cpp index 6a55c7ec..d681878a 100644 --- a/src/presets/WeatherPreset.cpp +++ b/src/presets/WeatherPreset.cpp @@ -11,6 +11,9 @@ dv::value WeatherPreset::serialize() const { froot["hspeed"] = fall.hspeed; froot["scale"] = fall.scale; froot["noise"] = fall.noise; + froot["min_opacity"] = fall.minOpacity; + froot["max_opacity"] = fall.maxOpacity; + froot["opaque"] = fall.opaque; if (fall.splash) { froot["splash"] = fall.splash->serialize(); } @@ -32,6 +35,9 @@ void WeatherPreset::deserialize(const dv::value& src) { froot.at("hspeed").get(fall.hspeed); froot.at("scale").get(fall.scale); froot.at("noise").get(fall.noise); + froot.at("min_opacity").get(fall.minOpacity); + froot.at("max_opacity").get(fall.maxOpacity); + froot.at("opaque").get(fall.opaque); if (froot.has("splash")) { const auto& sroot = froot["splash"]; diff --git a/src/presets/WeatherPreset.hpp b/src/presets/WeatherPreset.hpp index 8b449e90..a9a78f9c 100644 --- a/src/presets/WeatherPreset.hpp +++ b/src/presets/WeatherPreset.hpp @@ -20,7 +20,9 @@ struct WeatherPreset : Serializable { float scale = 0.1f; /// @brief Fall opacity interpreted as zero. /// @example if 0.8 then opacity range is 0.8-1.0 for 0.0-1.0 intensity - float minOpacity = 0.8f; + float minOpacity = 0.0f; + float maxOpacity = 1.0f; + bool opaque = false; /// @brief Fall splash std::optional splash; } fall {};