start splitting render pipelines & remove the obsolete world fog parameter

This commit is contained in:
MihailRis 2026-06-19 00:01:14 +03:00
parent 07c35f001c
commit 22f09d3659
8 changed files with 223 additions and 147 deletions

View file

@ -310,12 +310,6 @@ std::shared_ptr<UINode> create_debug_panel(
bar->setConsumer([&](double val) { worldInfo.daytime = val; }); bar->setConsumer([&](double val) { worldInfo.daytime = val; });
panel->add(bar); panel->add(bar);
} }
if (allowDebugCheats) {
auto bar = std::make_shared<TrackBar>(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<FullCheckBox>( auto checkbox = std::make_shared<FullCheckBox>(
gui, L"Show Chunk Borders", glm::vec2(400, 24) gui, L"Show Chunk Borders", glm::vec2(400, 24)

View file

@ -100,7 +100,7 @@ void Shadows::setup(Shader& shader, const Weather& weather) {
return; return;
} }
const auto& worldInfo = level.getWorld()->getInfo(); const auto& worldInfo = level.getWorld()->getInfo();
float cloudsIntensity = glm::max(worldInfo.fog, weather.clouds()); float cloudsIntensity = weather.clouds();
float shadowsOpacity = 1.0f - cloudsIntensity; float shadowsOpacity = 1.0f - cloudsIntensity;
shadowsOpacity *= glm::sqrt(glm::abs( shadowsOpacity *= glm::sqrt(glm::abs(
glm::mod((worldInfo.daytime + 0.5f) * 2.0f, 1.0f) * 2.0f - 1.0f glm::mod((worldInfo.daytime + 0.5f) * 2.0f, 1.0f) * 2.0f - 1.0f

View file

@ -93,7 +93,7 @@ void DebugLinesRenderer::drawCoordSystem(
} }
void DebugLinesRenderer::render( void DebugLinesRenderer::render(
DrawContext& pctx, const DrawContext& pctx,
const Camera& camera, const Camera& camera,
LineBatch& linesBatch, LineBatch& linesBatch,
Shader& linesShader, Shader& linesShader,

View file

@ -20,7 +20,7 @@ public:
/// @param linesShader Shader used for rendering lines /// @param linesShader Shader used for rendering lines
/// @param showChunkBorders Whether to show chunk borders /// @param showChunkBorders Whether to show chunk borders
void render( void render(
DrawContext& ctx, const DrawContext& ctx,
const Camera& camera, const Camera& camera,
LineBatch& linesBatch, LineBatch& linesBatch,
Shader& linesShader, Shader& linesShader,

View file

@ -70,10 +70,10 @@ bool WorldRenderer::showEntitiesDebug = false;
template <typename T> template <typename T>
static ObserverHandler observe_setting( static ObserverHandler observe_setting(
ObservableSetting<T>& setting, bool& dirtyShaders ObservableSetting<T>& setting, bool& dirtySettings
) { ) {
return setting.observe([&dirtyShaders](auto const&) { return setting.observe([&dirtySettings](auto const&) {
dirtyShaders = true; dirtySettings = true;
}); });
} }
@ -133,9 +133,9 @@ WorldRenderer::WorldRenderer(
debugLines = std::make_unique<DebugLinesRenderer>(level); debugLines = std::make_unique<DebugLinesRenderer>(level);
cloudsRenderer = std::make_unique<CloudsRenderer>(); cloudsRenderer = std::make_unique<CloudsRenderer>();
keepAlive(observe_setting(settings.graphics.advancedRender, dirtyShaders)); keepAlive(observe_setting(settings.graphics.advancedRender, dirtySettings));
keepAlive(observe_setting(settings.graphics.shadowsQuality, dirtyShaders)); keepAlive(observe_setting(settings.graphics.shadowsQuality, dirtySettings));
keepAlive(observe_setting(settings.graphics.ssao, dirtyShaders)); keepAlive(observe_setting(settings.graphics.ssao, dirtySettings));
} }
WorldRenderer::~WorldRenderer() = default; WorldRenderer::~WorldRenderer() = default;
@ -255,12 +255,12 @@ void WorldRenderer::renderOpaque(
modelBatch->render(); modelBatch->render();
particles->render(camera); particles->render(camera);
auto& shader = assets.require<Shader>("main"); auto& mainShader = assets.require<Shader>("main");
auto& cloudsShader = assets.require<Shader>("clouds"); auto& cloudsShader = assets.require<Shader>("clouds");
setupWorldShader(shader, camera, settings, fogFactor); setupWorldShader(mainShader, camera, settings, fogFactor);
chunksRenderer->drawChunks(camera, shader); chunksRenderer->drawChunks(camera, mainShader);
blockWraps->draw(ctx); blockWraps->draw(ctx);
if (level.environment.sky.clouds) { if (level.environment.sky.clouds) {
@ -275,7 +275,7 @@ void WorldRenderer::renderOpaque(
if (hudVisible) { if (hudVisible) {
auto& linesShader = assets.require<Shader>("lines"); auto& linesShader = assets.require<Shader>("lines");
renderLines(camera, linesShader, ctx); renderInWorldLines(camera, linesShader, ctx);
} }
} }
@ -308,7 +308,7 @@ void WorldRenderer::renderBlockSelection() {
lineBatch->flush(); lineBatch->flush();
} }
void WorldRenderer::renderLines( void WorldRenderer::renderInWorldLines(
const Camera& camera, Shader& linesShader, const DrawContext& pctx const Camera& camera, Shader& linesShader, const DrawContext& pctx
) { ) {
linesShader.use(); linesShader.use();
@ -327,159 +327,224 @@ void WorldRenderer::renderLines(
void WorldRenderer::update(const Camera& camera, float delta) { void WorldRenderer::update(const Camera& camera, float delta) {
timer += delta; timer += delta;
chunksRenderer->update();
weather.update(delta); weather.update(delta);
precipitation->update(delta); precipitation->update(delta);
particles->update(camera, 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<Shader>("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<Shader>("shadows");
setupWorldShader(shader, shadowCamera, engine.getSettings(), 0.0f);
chunksRenderer->drawShadowsPass(shadowCamera, shader, camera);
});
auto& deferredShader =
assets.require<PostEffect>("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<Shader>("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( void WorldRenderer::renderFrame(
const DrawContext& pctx, const DrawContext& pctx,
Camera& camera, Camera& camera,
bool hudVisible, bool hudVisible,
PostProcessing& postProcessing PostProcessing& postProcessing
) { ) {
auto projView = camera.getProjView();
auto world = level.getWorld();
const auto& vp = pctx.getViewport(); const auto& vp = pctx.getViewport();
camera.setAspectRatio(vp.x / static_cast<float>(vp.y)); camera.setAspectRatio(vp.x / static_cast<float>(vp.y));
if (dirtyShaders) { if (dirtySettings) {
refreshSettings(); refreshSettings();
dirtyShaders = false; dirtySettings = false;
} }
const auto& worldInfo = world->getInfo(); const auto& worldInfo = level.getWorld()->getInfo();
float clouds = weather.clouds(); 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<float>(RAND_MAX); float random = rand() / static_cast<float>(RAND_MAX);
skybox->refresh( skybox->refresh(
level.environment, level.environment,
pctx, pctx,
worldInfo.daytime, worldInfo.daytime,
mie, 1.0f + clouds,
weather.skyTint(), weather.skyTint(),
weather.highlight * random, weather.highlight * random,
4 4
); );
renderOpaquePass(pctx, camera, hudVisible, postProcessing);
chunksRenderer->update();
shadowMapping->refresh(camera, pctx, [this, &camera](Camera& shadowCamera) {
auto& shader = assets.require<Shader>("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();
if (gbufferPipeline) { if (gbufferPipeline) {
auto& deferredShader = renderFrameAdvanced(pctx, camera, hudVisible, postProcessing);
assets.require<PostEffect>("deferred_lighting").getShader(); } else {
deferredShader.use(); renderFrameClassic(pctx, camera, hudVisible, postProcessing);
setupWorldShader(deferredShader, camera, settings, fogFactor);
postProcessing.renderDeferredShading(pctx, assets, timer, camera);
}
auto& entityShader = assets.require<Shader>("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<Shader>("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<Shader>("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<const WeatherPreset*, 2> 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);
} }
postProcessing.render(pctx, assets, timer, camera); postProcessing.render(pctx, assets, timer, camera);
if (player.currentCamera == player.fpCamera) { if (player.currentCamera == player.fpCamera) {
DrawContext ctx = pctx.sub(); renderHandsPass(pctx, camera);
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);
} }
renderBlockOverlay(pctx); renderBlockOverlay(pctx);
glActiveTexture(GL_TEXTURE0); 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<Shader>("entity");
entityShader.use();
setupWorldShader(entityShader, camera, settings, calcFogFactor());
std::array<const WeatherPreset*, 2> 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<Shader>("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<Shader>("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) { void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {
int x = std::floor(player.currentCamera->position.x); int x = std::floor(player.currentCamera->position.x);
int y = std::floor(player.currentCamera->position.y); int y = std::floor(player.currentCamera->position.y);

View file

@ -10,7 +10,6 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include <algorithm>
#include <string> #include <string>
class Assets; class Assets;
@ -85,7 +84,7 @@ private:
bool lightsDebug = false; bool lightsDebug = false;
bool gbufferPipeline = false; bool gbufferPipeline = false;
bool dirtyShaders = false; bool dirtySettings = false;
/// @brief Render block selection lines /// @brief Render block selection lines
void renderBlockSelection(); void renderBlockSelection();
@ -93,7 +92,7 @@ private:
/// @brief Render lines (selection and debug) /// @brief Render lines (selection and debug)
/// @param camera active camera /// @param camera active camera
/// @param linesShader shader used /// @param linesShader shader used
void renderLines( void renderInWorldLines(
const Camera& camera, Shader& linesShader, const DrawContext& pctx const Camera& camera, Shader& linesShader, const DrawContext& pctx
); );
@ -117,6 +116,33 @@ private:
bool hudVisible 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(); void refreshSettings();
float calcFogFactor() const; float calcFogFactor() const;

View file

@ -216,9 +216,6 @@ void WorldInfo::deserialize(const dv::value& root) {
daytimeSpeed = timeobj["day-time-speed"].asNumber(); daytimeSpeed = timeobj["day-time-speed"].asNumber();
totalTime = timeobj["total-time"].asNumber(); totalTime = timeobj["total-time"].asNumber();
} }
if (root.has("weather")) {
fog = root["weather"]["fog"].asNumber();
}
nextInventoryId = root["next-inventory-id"].asInteger(2); nextInventoryId = root["next-inventory-id"].asInteger(2);
nextEntityId = root["next-entity-id"].asInteger(1); nextEntityId = root["next-entity-id"].asInteger(1);
root.at("next-player-id").get(nextPlayerId); root.at("next-player-id").get(nextPlayerId);
@ -244,9 +241,6 @@ dv::value WorldInfo::serialize() const {
timeobj["day-time-speed"] = daytimeSpeed; timeobj["day-time-speed"] = daytimeSpeed;
timeobj["total-time"] = totalTime; timeobj["total-time"] = totalTime;
root["weather"] = dv::object();
root["weather"]["fog"] = fog;
root["next-inventory-id"] = nextInventoryId; root["next-inventory-id"] = nextInventoryId;
root["next-entity-id"] = nextEntityId; root["next-entity-id"] = nextEntityId;
root["next-player-id"] = nextPlayerId; root["next-player-id"] = nextPlayerId;

View file

@ -39,9 +39,6 @@ struct WorldInfo : public Serializable {
/// @brief total time passed in the world (not depending on daytimeSpeed) /// @brief total time passed in the world (not depending on daytimeSpeed)
double totalTime = 0.0; double totalTime = 0.0;
/// @brief will be replaced with weather in future
float fog = 0.0f;
entityid_t nextEntityId = 0; entityid_t nextEntityId = 0;
int major = 0, minor = -1; int major = 0, minor = -1;