diff --git a/src/frontend/debug_panel.cpp b/src/frontend/debug_panel.cpp index 780bbf00a..ba0cc2205 100644 --- a/src/frontend/debug_panel.cpp +++ b/src/frontend/debug_panel.cpp @@ -310,12 +310,6 @@ std::shared_ptr create_debug_panel( bar->setConsumer([&](double val) { worldInfo.daytime = val; }); panel->add(bar); } - if (allowDebugCheats) { - auto bar = std::make_shared(gui, 0.0f, 1.0f, 0.0f, 0.005f, 8); - bar->setSupplier([&]() { return worldInfo.fog; }); - bar->setConsumer([&](double val) { worldInfo.fog = val; }); - panel->add(bar); - } { auto checkbox = std::make_shared( gui, L"Show Chunk Borders", glm::vec2(400, 24) diff --git a/src/graphics/core/Shadows.cpp b/src/graphics/core/Shadows.cpp index c9ecc108d..593e4cb4e 100644 --- a/src/graphics/core/Shadows.cpp +++ b/src/graphics/core/Shadows.cpp @@ -100,7 +100,7 @@ void Shadows::setup(Shader& shader, const Weather& weather) { return; } const auto& worldInfo = level.getWorld()->getInfo(); - float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds()); + float cloudsIntensity = weather.clouds(); float shadowsOpacity = 1.0f - cloudsIntensity; shadowsOpacity *= glm::sqrt(glm::abs( glm::mod((worldInfo.daytime + 0.5f) * 2.0f, 1.0f) * 2.0f - 1.0f diff --git a/src/graphics/render/DebugLinesRenderer.cpp b/src/graphics/render/DebugLinesRenderer.cpp index df0b1af78..3750b2cd0 100644 --- a/src/graphics/render/DebugLinesRenderer.cpp +++ b/src/graphics/render/DebugLinesRenderer.cpp @@ -93,7 +93,7 @@ void DebugLinesRenderer::drawCoordSystem( } void DebugLinesRenderer::render( - DrawContext& pctx, + const DrawContext& pctx, const Camera& camera, LineBatch& linesBatch, Shader& linesShader, diff --git a/src/graphics/render/DebugLinesRenderer.hpp b/src/graphics/render/DebugLinesRenderer.hpp index 7a9f0a324..bc6609c5a 100644 --- a/src/graphics/render/DebugLinesRenderer.hpp +++ b/src/graphics/render/DebugLinesRenderer.hpp @@ -20,7 +20,7 @@ public: /// @param linesShader Shader used for rendering lines /// @param showChunkBorders Whether to show chunk borders void render( - DrawContext& ctx, + const DrawContext& ctx, const Camera& camera, LineBatch& linesBatch, Shader& linesShader, diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index e59d4392f..353c5fabd 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -70,10 +70,10 @@ bool WorldRenderer::showEntitiesDebug = false; template static ObserverHandler observe_setting( - ObservableSetting& setting, bool& dirtyShaders + ObservableSetting& setting, bool& dirtySettings ) { - return setting.observe([&dirtyShaders](auto const&) { - dirtyShaders = true; + return setting.observe([&dirtySettings](auto const&) { + dirtySettings = true; }); } @@ -133,9 +133,9 @@ WorldRenderer::WorldRenderer( debugLines = std::make_unique(level); cloudsRenderer = std::make_unique(); - keepAlive(observe_setting(settings.graphics.advancedRender, dirtyShaders)); - keepAlive(observe_setting(settings.graphics.shadowsQuality, dirtyShaders)); - keepAlive(observe_setting(settings.graphics.ssao, dirtyShaders)); + keepAlive(observe_setting(settings.graphics.advancedRender, dirtySettings)); + keepAlive(observe_setting(settings.graphics.shadowsQuality, dirtySettings)); + keepAlive(observe_setting(settings.graphics.ssao, dirtySettings)); } WorldRenderer::~WorldRenderer() = default; @@ -255,12 +255,12 @@ void WorldRenderer::renderOpaque( modelBatch->render(); particles->render(camera); - auto& shader = assets.require("main"); + auto& mainShader = assets.require("main"); auto& cloudsShader = assets.require("clouds"); - setupWorldShader(shader, camera, settings, fogFactor); + setupWorldShader(mainShader, camera, settings, fogFactor); - chunksRenderer->drawChunks(camera, shader); + chunksRenderer->drawChunks(camera, mainShader); blockWraps->draw(ctx); if (level.environment.sky.clouds) { @@ -275,7 +275,7 @@ void WorldRenderer::renderOpaque( if (hudVisible) { auto& linesShader = assets.require("lines"); - renderLines(camera, linesShader, ctx); + renderInWorldLines(camera, linesShader, ctx); } } @@ -308,7 +308,7 @@ void WorldRenderer::renderBlockSelection() { lineBatch->flush(); } -void WorldRenderer::renderLines( +void WorldRenderer::renderInWorldLines( const Camera& camera, Shader& linesShader, const DrawContext& pctx ) { linesShader.use(); @@ -327,159 +327,224 @@ void WorldRenderer::renderLines( void WorldRenderer::update(const Camera& camera, float delta) { timer += delta; + chunksRenderer->update(); weather.update(delta); precipitation->update(delta); particles->update(camera, delta); } +void WorldRenderer::renderFrameClassic( + const DrawContext& pctx, + Camera& camera, + bool hudVisible, + PostProcessing& postProcessing +) { + const auto& worldInfo = level.getWorld()->getInfo(); + + DrawContext ctx = pctx.sub(); + ctx.setDepthTest(true); + ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); + ctx.setFramebuffer(postProcessing.getFramebuffer()); + + skybox->draw( + level.environment, ctx, camera, worldInfo.daytime, weather.clouds() + ); + + if (debug && hudVisible) { + renderDebugLines(ctx, camera); + } + + DrawContext wctx = ctx.sub(); + wctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap()); + wctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); + // Translucent blocks + { + const auto& settings = engine.getSettings(); + auto& translucentShader = assets.require("translucent"); + auto sctx = wctx.sub(); + sctx.setCullFace(true); + translucentShader.use(); + setupWorldShader(translucentShader, camera, settings, calcFogFactor()); + chunksRenderer->drawSortedMeshes(camera, translucentShader); + } + + renderWeatherEffects(camera); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void WorldRenderer::renderFrameAdvanced( + const DrawContext& pctx, + Camera& camera, + bool hudVisible, + PostProcessing& postProcessing +) { + const auto& settings = engine.getSettings(); + const auto& worldInfo = level.getWorld()->getInfo(); + float fogFactor = calcFogFactor(); + + shadowMapping->refresh(camera, pctx, [this, &camera](Camera& shadowCamera) { + auto& shader = assets.require("shadows"); + setupWorldShader(shader, shadowCamera, engine.getSettings(), 0.0f); + chunksRenderer->drawShadowsPass(shadowCamera, shader, camera); + }); + + auto& deferredShader = + assets.require("deferred_lighting").getShader(); + deferredShader.use(); + setupWorldShader(deferredShader, camera, settings, fogFactor); + postProcessing.renderDeferredShading(pctx, assets, timer, camera); + + DrawContext ctx = pctx.sub(); + ctx.setDepthTest(true); + ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); + + postProcessing.bindDepthBuffer(); + + // Background sky plane + skybox->draw( + level.environment, ctx, camera, worldInfo.daytime, weather.clouds() + ); + if (debug && hudVisible) { + renderDebugLines(ctx, camera); + } + + DrawContext wctx = ctx.sub(); + wctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap()); + wctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); + // Translucent blocks + { + const auto& settings = engine.getSettings(); + auto& translucentShader = assets.require("translucent"); + auto sctx = wctx.sub(); + sctx.setCullFace(true); + translucentShader.use(); + setupWorldShader(translucentShader, camera, settings, fogFactor); + chunksRenderer->drawSortedMeshes(camera, translucentShader); + } + + renderWeatherEffects(camera); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + void WorldRenderer::renderFrame( const DrawContext& pctx, Camera& camera, bool hudVisible, PostProcessing& postProcessing ) { - auto projView = camera.getProjView(); - auto world = level.getWorld(); - const auto& vp = pctx.getViewport(); camera.setAspectRatio(vp.x / static_cast(vp.y)); - if (dirtyShaders) { + if (dirtySettings) { refreshSettings(); - dirtyShaders = false; + dirtySettings = false; } - const auto& worldInfo = world->getInfo(); + const auto& worldInfo = level.getWorld()->getInfo(); float clouds = weather.clouds(); - clouds = glm::max(worldInfo.fog, clouds); - float mie = 1.0f + glm::max(worldInfo.fog, clouds * 0.5f) * 2.0f; float random = rand() / static_cast(RAND_MAX); skybox->refresh( level.environment, pctx, worldInfo.daytime, - mie, + 1.0f + clouds, weather.skyTint(), weather.highlight * random, 4 ); - - chunksRenderer->update(); - - shadowMapping->refresh(camera, pctx, [this, &camera](Camera& shadowCamera) { - auto& shader = assets.require("shadows"); - setupWorldShader(shader, shadowCamera, engine.getSettings(), 0.0f); - chunksRenderer->drawShadowsPass(shadowCamera, shader, camera); - }); - const auto& settings = engine.getSettings(); - { - DrawContext wctx = pctx.sub(); - postProcessing.use(wctx, gbufferPipeline); - display::clearDepth(); - - /* Main opaque pass (GBuffer pass) */ { - DrawContext ctx = wctx.sub(); - ctx.setDepthTest(true); - ctx.setCullFace(true); - ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap()); - ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); - renderOpaque(ctx, camera, settings, hudVisible); - } - texts->render(pctx, camera, settings, hudVisible, true); - } - float fogFactor = calcFogFactor(); + renderOpaquePass(pctx, camera, hudVisible, postProcessing); if (gbufferPipeline) { - auto& deferredShader = - assets.require("deferred_lighting").getShader(); - deferredShader.use(); - setupWorldShader(deferredShader, camera, settings, fogFactor); - postProcessing.renderDeferredShading(pctx, assets, timer, camera); - } - auto& entityShader = assets.require("entity"); - { - DrawContext ctx = pctx.sub(); - ctx.setDepthTest(true); - ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); - - if (gbufferPipeline) { - postProcessing.bindDepthBuffer(); - } else { - ctx.setFramebuffer(postProcessing.getFramebuffer()); - } - - // Background sky plane - skybox->draw( - level.environment, ctx, camera, worldInfo.daytime, clouds - ); - - auto& linesShader = assets.require("lines"); - linesShader.use(); - if (debug && hudVisible) { - debugLines->render( - ctx, camera, *lineBatch, linesShader, showChunkBorders - ); - } - linesShader.uniformMatrix("u_projview", projView); - lineBatch->flush(); - - DrawContext wctx = ctx.sub(); - wctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap()); - wctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); - // Translucent blocks - { - auto& translucentShader = assets.require("translucent"); - auto sctx = wctx.sub(); - sctx.setCullFace(true); - translucentShader.use(); - setupWorldShader(translucentShader, camera, settings, fogFactor); - chunksRenderer->drawSortedMeshes(camera, translucentShader); - } - - // Weather effects - entityShader.use(); - setupWorldShader(entityShader, camera, settings, fogFactor); - - std::array weatherInstances { - &weather.a, &weather.b}; - for (const auto& weather : weatherInstances) { - float maxIntensity = weather->fall.maxIntensity; - float zero = weather->fall.minOpacity; - float one = weather->fall.maxOpacity; - float t = (weather->intensity * (one - zero)) * maxIntensity + zero; - entityShader.uniform1i("u_alphaClip", weather->fall.opaque); - entityShader.uniform1f( - "u_opacity", weather->fall.opaque ? t * t : t - ); - if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) { - precipitation->render(camera, *weather); - } - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + renderFrameAdvanced(pctx, camera, hudVisible, postProcessing); + } else { + renderFrameClassic(pctx, camera, hudVisible, postProcessing); } postProcessing.render(pctx, assets, timer, camera); if (player.currentCamera == player.fpCamera) { - DrawContext ctx = pctx.sub(); - ctx.setDepthTest(true); - ctx.setCullFace(true); - ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap()); - ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); - display::clearDepth(); - - // prepare modified HUD camera - Camera hudcam = camera; - hudcam.far = 10.0f; - hudcam.setFov(0.9f); - hudcam.position = {}; - - setupWorldShader(entityShader, hudcam, engine.getSettings(), 0.0f); - hands->render(camera); + renderHandsPass(pctx, camera); } renderBlockOverlay(pctx); glActiveTexture(GL_TEXTURE0); } + +void WorldRenderer::renderOpaquePass( + const DrawContext& pctx, + Camera& camera, + bool hudVisible, + PostProcessing& postProcessing +) { + const auto& settings = engine.getSettings(); + + DrawContext wctx = pctx.sub(); + postProcessing.use(wctx, gbufferPipeline); + display::clearDepth(); + + /* Main opaque pass (GBuffer pass) */ { + DrawContext ctx = wctx.sub(); + ctx.setDepthTest(true); + ctx.setCullFace(true); + ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap()); + ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); + renderOpaque(ctx, camera, settings, hudVisible); + } + texts->render(wctx, camera, settings, hudVisible, true); +} + +void WorldRenderer::renderWeatherEffects(Camera& camera) { + const auto& settings = engine.getSettings(); + auto& entityShader = assets.require("entity"); + entityShader.use(); + setupWorldShader(entityShader, camera, settings, calcFogFactor()); + + std::array weatherInstances { + &weather.a, &weather.b}; + for (const auto& weather : weatherInstances) { + float maxIntensity = weather->fall.maxIntensity; + float zero = weather->fall.minOpacity; + float one = weather->fall.maxOpacity; + float t = (weather->intensity * (one - zero)) * maxIntensity + zero; + entityShader.uniform1i("u_alphaClip", weather->fall.opaque); + entityShader.uniform1f( + "u_opacity", weather->fall.opaque ? t * t : t + ); + if (weather->intensity > 1.e-3f && !weather->fall.texture.empty()) { + precipitation->render(camera, *weather); + } + } +} + +void WorldRenderer::renderDebugLines(const DrawContext& ctx, Camera& camera) { + auto& linesShader = assets.require("lines"); + linesShader.use(); + debugLines->render( + ctx, camera, *lineBatch, linesShader, showChunkBorders + ); + linesShader.uniformMatrix("u_projview", camera.getProjView()); + lineBatch->flush(); +} + +void WorldRenderer::renderHandsPass(const DrawContext& pctx, Camera& camera) { + auto& entityShader = assets.require("entity"); + + DrawContext ctx = pctx.sub(); + ctx.setDepthTest(true); + ctx.setCullFace(true); + ctx.useTexture(advanced_pipeline::TARGET_SKYBOX, skybox->getCubemap()); + ctx.useTexture(advanced_pipeline::TARGET_COLOR, nullptr); + display::clearDepth(); + + // prepare modified HUD camera + Camera hudcam = camera; + hudcam.far = 10.0f; + hudcam.setFov(0.9f); + hudcam.position = {}; + + setupWorldShader(entityShader, hudcam, engine.getSettings(), 0.0f); + hands->render(camera); +} + void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) { int x = std::floor(player.currentCamera->position.x); int y = std::floor(player.currentCamera->position.y); diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index e813edb0b..d56c21cbf 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -10,7 +10,6 @@ #include #include -#include #include class Assets; @@ -85,7 +84,7 @@ private: bool lightsDebug = false; bool gbufferPipeline = false; - bool dirtyShaders = false; + bool dirtySettings = false; /// @brief Render block selection lines void renderBlockSelection(); @@ -93,7 +92,7 @@ private: /// @brief Render lines (selection and debug) /// @param camera active camera /// @param linesShader shader used - void renderLines( + void renderInWorldLines( const Camera& camera, Shader& linesShader, const DrawContext& pctx ); @@ -117,6 +116,33 @@ private: bool hudVisible ); + void renderOpaquePass( + const DrawContext& context, + Camera& camera, + bool hudVisible, + PostProcessing& postProcessing + ); + + void renderWeatherEffects(Camera& camera); + + void renderHandsPass(const DrawContext& pctx, Camera& camera); + + void renderDebugLines(const DrawContext& context, Camera& camera); + + void renderFrameClassic( + const DrawContext& context, + Camera& camera, + bool hudVisible, + PostProcessing& postProcessing + ); + + void renderFrameAdvanced( + const DrawContext& context, + Camera& camera, + bool hudVisible, + PostProcessing& postProcessing + ); + void refreshSettings(); float calcFogFactor() const; diff --git a/src/world/World.cpp b/src/world/World.cpp index 2acc7edaa..8bbc78b94 100644 --- a/src/world/World.cpp +++ b/src/world/World.cpp @@ -216,9 +216,6 @@ void WorldInfo::deserialize(const dv::value& root) { daytimeSpeed = timeobj["day-time-speed"].asNumber(); totalTime = timeobj["total-time"].asNumber(); } - if (root.has("weather")) { - fog = root["weather"]["fog"].asNumber(); - } nextInventoryId = root["next-inventory-id"].asInteger(2); nextEntityId = root["next-entity-id"].asInteger(1); root.at("next-player-id").get(nextPlayerId); @@ -244,9 +241,6 @@ dv::value WorldInfo::serialize() const { timeobj["day-time-speed"] = daytimeSpeed; timeobj["total-time"] = totalTime; - root["weather"] = dv::object(); - root["weather"]["fog"] = fog; - root["next-inventory-id"] = nextInventoryId; root["next-entity-id"] = nextEntityId; root["next-player-id"] = nextPlayerId; diff --git a/src/world/World.hpp b/src/world/World.hpp index 14649fb1b..7af7bd1db 100644 --- a/src/world/World.hpp +++ b/src/world/World.hpp @@ -39,9 +39,6 @@ struct WorldInfo : public Serializable { /// @brief total time passed in the world (not depending on daytimeSpeed) double totalTime = 0.0; - /// @brief will be replaced with weather in future - float fog = 0.0f; - entityid_t nextEntityId = 0; int major = 0, minor = -1;