diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index ca80ed11..7b2a2a5d 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -173,7 +173,7 @@ void LevelScreen::saveWorldPreview() { static_cast(previewSize)} ); - renderer->draw(ctx, camera, false, true, 0.0f, *postProcessing); + renderer->renderFrame(ctx, camera, false, true, 0.0f, *postProcessing); auto image = postProcessing->toImage(); image->flipY(); imageio::write("world:preview.png", image.get()); @@ -260,7 +260,7 @@ void LevelScreen::draw(float delta) { if (!hud->isPause()) { scripting::on_entities_render(engine.getTime().getDelta()); } - renderer->draw( + renderer->renderFrame( ctx, *camera, hudVisible, hud->isPause(), delta, *postProcessing ); diff --git a/src/graphics/core/ShadowMap.cpp b/src/graphics/core/ShadowMap.cpp deleted file mode 100644 index e5032d8b..00000000 --- a/src/graphics/core/ShadowMap.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "ShadowMap.hpp" - -#include - -ShadowMap::ShadowMap(int resolution) : resolution(resolution) { - glGenTextures(1, &depthMap); - glBindTexture(GL_TEXTURE_2D, depthMap); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, - resolution, resolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - float border[4] {1.0f, 1.0f, 1.0f, 1.0f}; - glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR, border); - - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0); - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -ShadowMap::~ShadowMap() { - glDeleteFramebuffers(1, &fbo); - glDeleteTextures(1, &depthMap); -} - -void ShadowMap::bind() { - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - glClear(GL_DEPTH_BUFFER_BIT); -} - -void ShadowMap::unbind() { - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -uint ShadowMap::getDepthMap() const { - return depthMap; -} - -int ShadowMap::getResolution() const { - return resolution; -} diff --git a/src/graphics/core/ShadowMap.hpp b/src/graphics/core/ShadowMap.hpp deleted file mode 100644 index 828c51aa..00000000 --- a/src/graphics/core/ShadowMap.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "typedefs.hpp" - -class ShadowMap { -public: - ShadowMap(int resolution); - ~ShadowMap(); - - void bind(); - void unbind(); - uint getDepthMap() const; - int getResolution() const; -private: - uint fbo; - uint depthMap; - int resolution; -}; diff --git a/src/graphics/core/Shadows.cpp b/src/graphics/core/Shadows.cpp new file mode 100644 index 00000000..c6ac8e37 --- /dev/null +++ b/src/graphics/core/Shadows.cpp @@ -0,0 +1,199 @@ +#include "Shadows.hpp" + +#include + +#include + +#include "assets/Assets.hpp" +#include "graphics/core/DrawContext.hpp" +#include "graphics/core/Shader.hpp" +#include "graphics/core/commons.hpp" +#include "world/Level.hpp" +#include "world/Weather.hpp" +#include "world/World.hpp" + +using namespace advanced_pipeline; + +inline constexpr int MIN_SHADOW_MAP_RES = 512; +inline constexpr GLenum TEXTURE_MAIN = GL_TEXTURE0; + +class ShadowMap { +public: + ShadowMap(int resolution) : resolution(resolution) { + glGenTextures(1, &depthMap); + glBindTexture(GL_TEXTURE_2D, depthMap); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, + resolution, resolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); + glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE + ); + float border[4] {1.0f, 1.0f, 1.0f, 1.0f}; + glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border); + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMap, 0 + ); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + ~ShadowMap() { + glDeleteFramebuffers(1, &fbo); + glDeleteTextures(1, &depthMap); + } + + void bind(){ + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glClear(GL_DEPTH_BUFFER_BIT); + } + + void unbind() { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + uint getDepthMap() const { + return depthMap; + } + int getResolution() const { + return resolution; + } +private: + uint fbo; + uint depthMap; + int resolution; +}; + +Shadows::Shadows(const Level& level) : level(level) {} + +Shadows::~Shadows() = default; + +void Shadows::setQuality(int quality) { + int resolution = MIN_SHADOW_MAP_RES << quality; + if (quality > 0 && !shadows) { + shadowMap = std::make_unique(resolution); + wideShadowMap = std::make_unique(resolution); + shadows = true; + } else if (quality == 0 && shadows) { + shadowMap.reset(); + wideShadowMap.reset(); + shadows = false; + } + if (shadows && shadowMap->getResolution() != resolution) { + shadowMap = std::make_unique(resolution); + wideShadowMap = std::make_unique(resolution); + } + this->quality = quality; +} + +void Shadows::setup(Shader& shader, const Weather& weather) { + if (shadows) { + const auto& worldInfo = level.getWorld()->getInfo(); + float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds()); + shader.uniform1i("u_screen", 0); + shader.uniformMatrix("u_shadowsMatrix[0]", shadowCamera.getProjView()); + shader.uniformMatrix("u_shadowsMatrix[1]", wideShadowCamera.getProjView()); + shader.uniform3f("u_sunDir", shadowCamera.front); + shader.uniform1i("u_shadowsRes", shadowMap->getResolution()); + shader.uniform1f("u_shadowsOpacity", 1.0f - cloudsIntensity); // TODO: make it configurable + shader.uniform1f("u_shadowsSoftness", 1.0f + cloudsIntensity * 4); // TODO: make it configurable + + glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS0); + shader.uniform1i("u_shadows[0]", TARGET_SHADOWS0); + glBindTexture(GL_TEXTURE_2D, shadowMap->getDepthMap()); + + glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS1); + shader.uniform1i("u_shadows[1]", TARGET_SHADOWS1); + glBindTexture(GL_TEXTURE_2D, wideShadowMap->getDepthMap()); + + glActiveTexture(TEXTURE_MAIN); + } +} + +void Shadows::refresh(const Camera& camera, const DrawContext& pctx, std::function renderShadowPass) { + static int frameid = 0; + if (shadows) { + if (frameid % 2 == 0) { + generateShadowsMap(camera, pctx, *shadowMap, shadowCamera, 1.0f, renderShadowPass); + } else { + generateShadowsMap(camera, pctx, *wideShadowMap, wideShadowCamera, 3.0f, renderShadowPass); + } + } + frameid++; +} + +void Shadows::generateShadowsMap( + const Camera& camera, + const DrawContext& pctx, + ShadowMap& shadowMap, + Camera& shadowCamera, + float scale, + std::function renderShadowPass +) { + auto world = level.getWorld(); + const auto& worldInfo = world->getInfo(); + + int resolution = shadowMap.getResolution(); + float shadowMapScale = 0.32f / (1 << glm::max(0, quality)) * scale; + float shadowMapSize = resolution * shadowMapScale; + + glm::vec3 basePos = glm::floor(camera.position / 4.0f) * 4.0f; + glm::vec3 prevPos = shadowCamera.position; + shadowCamera = Camera( + glm::distance2(prevPos, basePos) > 25.0f ? basePos : prevPos, + shadowMapSize + ); + shadowCamera.near = 0.1f; + shadowCamera.far = 1000.0f; + shadowCamera.perspective = false; + shadowCamera.setAspectRatio(1.0f); + + float t = worldInfo.daytime - 0.25f; + if (t < 0.0f) { + t += 1.0f; + } + t = fmod(t, 0.5f); + + float sunCycleStep = 1.0f / 500.0f; + float sunAngle = glm::radians( + 90.0f - + ((static_cast(t / sunCycleStep)) * sunCycleStep + 0.25f) * 360.0f + ); + float sunAltitude = glm::pi() * 0.25f; + shadowCamera.rotate( + -glm::cos(sunAngle + glm::pi() * 0.5f) * sunAltitude, + sunAngle - glm::pi() * 0.5f, + glm::radians(0.0f) + ); + + shadowCamera.position -= shadowCamera.front * 500.0f; + shadowCamera.position += shadowCamera.up * 0.0f; + shadowCamera.position += camera.front * 0.0f; + + auto view = shadowCamera.getView(); + + auto currentPos = shadowCamera.position; + auto topRight = shadowCamera.right + shadowCamera.up; + auto min = view * glm::vec4(currentPos - topRight * shadowMapSize * 0.5f, 1.0f); + auto max = view * glm::vec4(currentPos + topRight * shadowMapSize * 0.5f, 1.0f); + + shadowCamera.setProjection(glm::ortho(min.x, max.x, min.y, max.y, 0.1f, 1000.0f)); + + { + auto sctx = pctx.sub(); + sctx.setDepthTest(true); + sctx.setCullFace(true); + sctx.setViewport({resolution, resolution}); + shadowMap.bind(); + if (renderShadowPass) { + renderShadowPass(shadowCamera); + } + shadowMap.unbind(); + } +} diff --git a/src/graphics/core/Shadows.hpp b/src/graphics/core/Shadows.hpp new file mode 100644 index 00000000..6f21a2d7 --- /dev/null +++ b/src/graphics/core/Shadows.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +#include "typedefs.hpp" +#include "window/Camera.hpp" + +class Shader; +class Level; +class Assets; +struct Weather; +class DrawContext; +struct EngineSettings; +class ShadowMap; + +class Shadows { +public: + Shadows(const Level& level); + ~Shadows(); + + void setup(Shader& shader, const Weather& weather); + void setQuality(int quality); + void refresh( + const Camera& camera, + const DrawContext& pctx, + std::function renderShadowPass + ); +private: + const Level& level; + bool shadows = false; + Camera shadowCamera; + Camera wideShadowCamera; + std::unique_ptr shadowMap; + std::unique_ptr wideShadowMap; + int quality = 0; + + void generateShadowsMap( + const Camera& camera, + const DrawContext& pctx, + ShadowMap& shadowMap, + Camera& shadowCamera, + float scale, + std::function renderShadowPass + ); +}; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index bb816c37..571a10e5 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -184,7 +184,7 @@ const Mesh* ChunksRenderer::retrieveChunk( return mesh; } -void ChunksRenderer::drawChunksShadowsPass( +void ChunksRenderer::drawShadowsPass( const Camera& camera, Shader& shader, const Camera& playerCamera ) { Frustum frustum; diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index 70925343..9215a863 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -73,7 +73,7 @@ public: const std::shared_ptr& chunk, bool important ); - void drawChunksShadowsPass( + void drawShadowsPass( const Camera& camera, Shader& shader, const Camera& playerCamera ); diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index f2425e0b..97bf870d 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -42,7 +42,7 @@ #include "graphics/core/Shader.hpp" #include "graphics/core/Texture.hpp" #include "graphics/core/Font.hpp" -#include "graphics/core/ShadowMap.hpp" +#include "graphics/core/Shadows.hpp" #include "graphics/core/GBuffer.hpp" #include "BlockWrapsRenderer.hpp" #include "ParticlesRenderer.hpp" @@ -62,8 +62,6 @@ using namespace advanced_pipeline; inline constexpr size_t BATCH3D_CAPACITY = 4096; inline constexpr size_t MODEL_BATCH_CAPACITY = 20'000; -inline constexpr GLenum TEXTURE_MAIN = GL_TEXTURE0; -inline constexpr int MIN_SHADOW_MAP_RES = 512; bool WorldRenderer::showChunkBorders = false; bool WorldRenderer::showEntitiesDebug = false; @@ -82,7 +80,7 @@ WorldRenderer::WorldRenderer( MODEL_BATCH_CAPACITY, assets, *player.chunks, engine.getSettings() )), guides(std::make_unique()), - chunks(std::make_unique( + chunksRenderer(std::make_unique( &level, *player.chunks, assets, @@ -103,7 +101,7 @@ WorldRenderer::WorldRenderer( auto& settings = engine.getSettings(); level.events->listen( LevelEventType::CHUNK_HIDDEN, - [this](LevelEventType, Chunk* chunk) { chunks->unload(chunk); } + [this](LevelEventType, Chunk* chunk) { chunksRenderer->unload(chunk); } ); auto assets = engine.getAssets(); skybox = std::make_unique( @@ -120,10 +118,24 @@ WorldRenderer::WorldRenderer( *assets, *modelBatch, skeletons->createSkeleton("hand", &skeletonConfig) ); lines = std::make_unique(); + shadowMapping = std::make_unique(level); } WorldRenderer::~WorldRenderer() = default; +static void setup_weather(Shader& shader, const Weather& weather) { + shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity()); + shader.uniform1f("u_weatherFogDencity", weather.fogDencity()); + shader.uniform1f("u_weatherFogCurve", weather.fogCurve()); +} + +static void setup_camera(Shader& shader, const Camera& camera) { + shader.uniformMatrix("u_model", glm::mat4(1.0f)); + shader.uniformMatrix("u_proj", camera.getProjection()); + shader.uniformMatrix("u_view", camera.getView()); + shader.uniform3f("u_cameraPos", camera.position); +} + void WorldRenderer::setupWorldShader( Shader& shader, const Camera& camera, @@ -131,45 +143,20 @@ void WorldRenderer::setupWorldShader( float fogFactor ) { shader.use(); - shader.uniformMatrix("u_model", glm::mat4(1.0f)); - shader.uniformMatrix("u_proj", camera.getProjection()); - shader.uniformMatrix("u_view", camera.getView()); + + setup_camera(shader, camera); + setup_weather(shader, weather); + shadowMapping->setup(shader, weather); + shader.uniform1f("u_timer", timer); shader.uniform1f("u_gamma", settings.graphics.gamma.get()); shader.uniform1f("u_fogFactor", fogFactor); shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get()); shader.uniform1i("u_debugLights", lightsDebug); shader.uniform1i("u_debugNormals", false); - shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity()); - shader.uniform1f("u_weatherFogDencity", weather.fogDencity()); - shader.uniform1f("u_weatherFogCurve", weather.fogCurve()); shader.uniform1f("u_dayTime", level.getWorld()->getInfo().daytime); shader.uniform2f("u_lightDir", skybox->getLightDir()); - shader.uniform3f("u_cameraPos", camera.position); - shader.uniform1i("u_skybox", 1); - shader.uniform1i("u_enableShadows", shadows); - - if (shadows) { - const auto& worldInfo = level.getWorld()->getInfo(); - float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds()); - shader.uniform1i("u_screen", 0); - shader.uniformMatrix("u_shadowsMatrix[0]", shadowCamera.getProjView()); - shader.uniformMatrix("u_shadowsMatrix[1]", wideShadowCamera.getProjView()); - shader.uniform3f("u_sunDir", shadowCamera.front); - shader.uniform1i("u_shadowsRes", shadowMap->getResolution()); - shader.uniform1f("u_shadowsOpacity", 1.0f - cloudsIntensity); // TODO: make it configurable - shader.uniform1f("u_shadowsSoftness", 1.0f + cloudsIntensity * 4); // TODO: make it configurable - - glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS0); - shader.uniform1i("u_shadows[0]", TARGET_SHADOWS0); - glBindTexture(GL_TEXTURE_2D, shadowMap->getDepthMap()); - - glActiveTexture(GL_TEXTURE0 + TARGET_SHADOWS1); - shader.uniform1i("u_shadows[1]", TARGET_SHADOWS1); - glBindTexture(GL_TEXTURE_2D, wideShadowMap->getDepthMap()); - - glActiveTexture(TEXTURE_MAIN); - } + shader.uniform1i("u_skybox", TARGET_SKYBOX); auto indices = level.content.getIndices(); // Light emission when an emissive item is chosen @@ -188,7 +175,7 @@ void WorldRenderer::setupWorldShader( } } -void WorldRenderer::renderLevel( +void WorldRenderer::renderOpaque( const DrawContext& ctx, const Camera& camera, const EngineSettings& settings, @@ -227,7 +214,7 @@ void WorldRenderer::renderLevel( setupWorldShader(shader, camera, settings, fogFactor); - chunks->drawChunks(camera, shader); + chunksRenderer->drawChunks(camera, shader); blockWraps->draw(ctx, player); if (hudVisible) { @@ -286,79 +273,7 @@ void WorldRenderer::renderLines( } } -void WorldRenderer::generateShadowsMap( - const Camera& camera, - const DrawContext& pctx, - ShadowMap& shadowMap, - Camera& shadowCamera, - float scale -) { - auto& shadowsShader = assets.require("shadows"); - - auto world = level.getWorld(); - const auto& worldInfo = world->getInfo(); - - const auto& settings = engine.getSettings(); - int resolution = shadowMap.getResolution(); - int quality = settings.graphics.shadowsQuality.get(); - float shadowMapScale = 0.32f / (1 << glm::max(0, quality)) * scale; - float shadowMapSize = resolution * shadowMapScale; - - glm::vec3 basePos = glm::floor(camera.position / 4.0f) * 4.0f; - glm::vec3 prevPos = shadowCamera.position; - shadowCamera = Camera( - glm::distance2(prevPos, basePos) > 25.0f ? basePos : prevPos, - shadowMapSize - ); - shadowCamera.near = 0.1f; - shadowCamera.far = 1000.0f; - shadowCamera.perspective = false; - shadowCamera.setAspectRatio(1.0f); - - float t = worldInfo.daytime - 0.25f; - if (t < 0.0f) { - t += 1.0f; - } - t = fmod(t, 0.5f); - - float sunCycleStep = 1.0f / 500.0f; - float sunAngle = glm::radians( - 90.0f - - ((static_cast(t / sunCycleStep)) * sunCycleStep + 0.25f) * 360.0f - ); - float sunAltitude = glm::pi() * 0.25f; - shadowCamera.rotate( - -glm::cos(sunAngle + glm::pi() * 0.5f) * sunAltitude, - sunAngle - glm::pi() * 0.5f, - glm::radians(0.0f) - ); - - shadowCamera.position -= shadowCamera.front * 500.0f; - shadowCamera.position += shadowCamera.up * 0.0f; - shadowCamera.position += camera.front * 0.0f; - - auto view = shadowCamera.getView(); - - auto currentPos = shadowCamera.position; - auto topRight = shadowCamera.right + shadowCamera.up; - auto min = view * glm::vec4(currentPos - topRight * shadowMapSize * 0.5f, 1.0f); - auto max = view * glm::vec4(currentPos + topRight * shadowMapSize * 0.5f, 1.0f); - - shadowCamera.setProjection(glm::ortho(min.x, max.x, min.y, max.y, 0.1f, 1000.0f)); - - { - auto sctx = pctx.sub(); - sctx.setDepthTest(true); - sctx.setCullFace(true); - sctx.setViewport({resolution, resolution}); - shadowMap.bind(); - setupWorldShader(shadowsShader, shadowCamera, settings, 0.0f); - chunks->drawChunksShadowsPass(shadowCamera, shadowsShader, camera); - shadowMap.unbind(); - } -} - -void WorldRenderer::draw( +void WorldRenderer::renderFrame( const DrawContext& pctx, Camera& camera, bool hudVisible, @@ -382,22 +297,17 @@ void WorldRenderer::draw( auto& deferredShader = assets.require("deferred_lighting").getShader(); const auto& settings = engine.getSettings(); + Shader* affectedShaders[] { + &mainShader, &entityShader, &translucentShader, &deferredShader + }; + gbufferPipeline = settings.graphics.advancedRender.get(); int shadowsQuality = settings.graphics.shadowsQuality.get() * gbufferPipeline; - int resolution = MIN_SHADOW_MAP_RES << shadowsQuality; - if (shadowsQuality > 0 && !shadows) { - shadowMap = std::make_unique(resolution); - wideShadowMap = std::make_unique(resolution); - shadows = true; - } else if (shadowsQuality == 0 && shadows) { - shadowMap.reset(); - wideShadowMap.reset(); - shadows = false; - } + shadowMapping->setQuality(shadowsQuality); CompileTimeShaderSettings currentSettings { gbufferPipeline, - shadows, + shadowsQuality != 0, settings.graphics.ssao.get() && gbufferPipeline }; if ( @@ -408,18 +318,12 @@ void WorldRenderer::draw( Shader::preprocessor->setDefined("ENABLE_SHADOWS", currentSettings.shadows); Shader::preprocessor->setDefined("ENABLE_SSAO", currentSettings.ssao); Shader::preprocessor->setDefined("ADVANCED_RENDER", currentSettings.advancedRender); - mainShader.recompile(); - entityShader.recompile(); - deferredShader.recompile(); - translucentShader.recompile(); + for (auto shader : affectedShaders) { + shader->recompile(); + } prevCTShaderSettings = currentSettings; } - if (shadows && shadowMap->getResolution() != resolution) { - shadowMap = std::make_unique(resolution); - wideShadowMap = std::make_unique(resolution); - } - const auto& worldInfo = world->getInfo(); float clouds = weather.clouds(); @@ -428,30 +332,27 @@ void WorldRenderer::draw( skybox->refresh(pctx, worldInfo.daytime, mie, 4); - chunks->update(); + chunksRenderer->update(); - static int frameid = 0; - if (shadows) { - if (frameid % 2 == 0) { - generateShadowsMap(camera, pctx, *shadowMap, shadowCamera, 1.0f); - } else { - generateShadowsMap(camera, pctx, *wideShadowMap, wideShadowCamera, 3.0f); - } - } - frameid++; + 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& linesShader = assets.require("lines"); - /* World render scope with diegetic HUD included */ { + + { DrawContext wctx = pctx.sub(); postProcessing.use(wctx, gbufferPipeline); display::clearDepth(); - /* Actually world render with depth buffer on */ { + /* Main opaque pass (GBuffer pass) */ { DrawContext ctx = wctx.sub(); ctx.setDepthTest(true); ctx.setCullFace(true); - renderLevel(ctx, camera, settings, uiDelta, pause, hudVisible); + renderOpaque(ctx, camera, settings, uiDelta, pause, hudVisible); // Debug lines if (hudVisible) { if (debug) { @@ -480,23 +381,27 @@ void WorldRenderer::draw( } else { postProcessing.getFramebuffer()->bind(); } - // Drawing background sky plane + + // Background sky plane skybox->draw(ctx, camera, assets, worldInfo.daytime, clouds); + // In-world lines linesShader.use(); lines->draw(*lineBatch); lineBatch->flush(); + // Translucent blocks { auto sctx = ctx.sub(); sctx.setCullFace(true); skybox->bind(); translucentShader.use(); setupWorldShader(translucentShader, camera, settings, fogFactor); - chunks->drawSortedMeshes(camera, translucentShader); + chunksRenderer->drawSortedMeshes(camera, translucentShader); skybox->unbind(); } + // Weather effects entityShader.use(); setupWorldShader(entityShader, camera, settings, fogFactor); @@ -588,7 +493,7 @@ void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) { } void WorldRenderer::clear() { - chunks->clear(); + chunksRenderer->clear(); } void WorldRenderer::setDebug(bool flag) { diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index 600e2e4f..955568fa 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -34,7 +34,7 @@ class PostProcessing; class DrawContext; class ModelBatch; class Assets; -class ShadowMap; +class Shadows; class GBuffer; struct EngineSettings; @@ -54,20 +54,17 @@ class WorldRenderer { std::unique_ptr batch3d; std::unique_ptr modelBatch; std::unique_ptr guides; - std::unique_ptr chunks; + std::unique_ptr chunksRenderer; std::unique_ptr hands; std::unique_ptr skybox; - std::unique_ptr shadowMap; - std::unique_ptr wideShadowMap; + std::unique_ptr shadowMapping; Weather weather {}; - Camera shadowCamera; - Camera wideShadowCamera; float timer = 0.0f; bool debug = false; bool lightsDebug = false; bool gbufferPipeline = false; - bool shadows = false; + CompileTimeShaderSettings prevCTShaderSettings {}; @@ -90,12 +87,17 @@ class WorldRenderer { float fogFactor ); - void generateShadowsMap( - const Camera& camera, - const DrawContext& pctx, - ShadowMap& shadowMap, - Camera& shadowCamera, - float scale + /// @brief Render opaque pass + /// @param context graphics context + /// @param camera active camera + /// @param settings engine settings + void renderOpaque( + const DrawContext& context, + const Camera& camera, + const EngineSettings& settings, + float delta, + bool pause, + bool hudVisible ); public: std::unique_ptr particles; @@ -111,7 +113,7 @@ public: WorldRenderer(Engine& engine, LevelFrontend& frontend, Player& player); ~WorldRenderer(); - void draw( + void renderFrame( const DrawContext& context, Camera& camera, bool hudVisible, @@ -120,19 +122,6 @@ public: PostProcessing& postProcessing ); - /// @brief Render level without diegetic interface - /// @param context graphics context - /// @param camera active camera - /// @param settings engine settings - void renderLevel( - const DrawContext& context, - const Camera& camera, - const EngineSettings& settings, - float delta, - bool pause, - bool hudVisible - ); - void clear(); void setDebug(bool flag);