refactor: move shadows-related code to separate module
This commit is contained in:
parent
70c5c67bd1
commit
8290c147c5
@ -173,7 +173,7 @@ void LevelScreen::saveWorldPreview() {
|
||||
static_cast<uint>(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
|
||||
);
|
||||
|
||||
|
||||
@ -1,47 +0,0 @@
|
||||
#include "ShadowMap.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
199
src/graphics/core/Shadows.cpp
Normal file
199
src/graphics/core/Shadows.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
#include "Shadows.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#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<ShadowMap>(resolution);
|
||||
wideShadowMap = std::make_unique<ShadowMap>(resolution);
|
||||
shadows = true;
|
||||
} else if (quality == 0 && shadows) {
|
||||
shadowMap.reset();
|
||||
wideShadowMap.reset();
|
||||
shadows = false;
|
||||
}
|
||||
if (shadows && shadowMap->getResolution() != resolution) {
|
||||
shadowMap = std::make_unique<ShadowMap>(resolution);
|
||||
wideShadowMap = std::make_unique<ShadowMap>(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<void(Camera&)> 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<void(Camera&)> 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<int>(t / sunCycleStep)) * sunCycleStep + 0.25f) * 360.0f
|
||||
);
|
||||
float sunAltitude = glm::pi<float>() * 0.25f;
|
||||
shadowCamera.rotate(
|
||||
-glm::cos(sunAngle + glm::pi<float>() * 0.5f) * sunAltitude,
|
||||
sunAngle - glm::pi<float>() * 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();
|
||||
}
|
||||
}
|
||||
46
src/graphics/core/Shadows.hpp
Normal file
46
src/graphics/core/Shadows.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#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<void(Camera&)> renderShadowPass
|
||||
);
|
||||
private:
|
||||
const Level& level;
|
||||
bool shadows = false;
|
||||
Camera shadowCamera;
|
||||
Camera wideShadowCamera;
|
||||
std::unique_ptr<ShadowMap> shadowMap;
|
||||
std::unique_ptr<ShadowMap> wideShadowMap;
|
||||
int quality = 0;
|
||||
|
||||
void generateShadowsMap(
|
||||
const Camera& camera,
|
||||
const DrawContext& pctx,
|
||||
ShadowMap& shadowMap,
|
||||
Camera& shadowCamera,
|
||||
float scale,
|
||||
std::function<void(Camera&)> renderShadowPass
|
||||
);
|
||||
};
|
||||
@ -184,7 +184,7 @@ const Mesh<ChunkVertex>* ChunksRenderer::retrieveChunk(
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void ChunksRenderer::drawChunksShadowsPass(
|
||||
void ChunksRenderer::drawShadowsPass(
|
||||
const Camera& camera, Shader& shader, const Camera& playerCamera
|
||||
) {
|
||||
Frustum frustum;
|
||||
|
||||
@ -73,7 +73,7 @@ public:
|
||||
const std::shared_ptr<Chunk>& chunk, bool important
|
||||
);
|
||||
|
||||
void drawChunksShadowsPass(
|
||||
void drawShadowsPass(
|
||||
const Camera& camera, Shader& shader, const Camera& playerCamera
|
||||
);
|
||||
|
||||
|
||||
@ -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<GuidesRenderer>()),
|
||||
chunks(std::make_unique<ChunksRenderer>(
|
||||
chunksRenderer(std::make_unique<ChunksRenderer>(
|
||||
&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<Skybox>(
|
||||
@ -120,10 +118,24 @@ WorldRenderer::WorldRenderer(
|
||||
*assets, *modelBatch, skeletons->createSkeleton("hand", &skeletonConfig)
|
||||
);
|
||||
lines = std::make_unique<LinesRenderer>();
|
||||
shadowMapping = std::make_unique<Shadows>(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<Shader>("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<int>(t / sunCycleStep)) * sunCycleStep + 0.25f) * 360.0f
|
||||
);
|
||||
float sunAltitude = glm::pi<float>() * 0.25f;
|
||||
shadowCamera.rotate(
|
||||
-glm::cos(sunAngle + glm::pi<float>() * 0.5f) * sunAltitude,
|
||||
sunAngle - glm::pi<float>() * 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<PostEffect>("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<ShadowMap>(resolution);
|
||||
wideShadowMap = std::make_unique<ShadowMap>(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<ShadowMap>(resolution);
|
||||
wideShadowMap = std::make_unique<ShadowMap>(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<Shader>("shadows");
|
||||
setupWorldShader(shader, shadowCamera, engine.getSettings(), 0.0f);
|
||||
chunksRenderer->drawShadowsPass(shadowCamera, shader, camera);
|
||||
});
|
||||
|
||||
auto& linesShader = assets.require<Shader>("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) {
|
||||
|
||||
@ -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> batch3d;
|
||||
std::unique_ptr<ModelBatch> modelBatch;
|
||||
std::unique_ptr<GuidesRenderer> guides;
|
||||
std::unique_ptr<ChunksRenderer> chunks;
|
||||
std::unique_ptr<ChunksRenderer> chunksRenderer;
|
||||
std::unique_ptr<HandsRenderer> hands;
|
||||
std::unique_ptr<Skybox> skybox;
|
||||
std::unique_ptr<ShadowMap> shadowMap;
|
||||
std::unique_ptr<ShadowMap> wideShadowMap;
|
||||
std::unique_ptr<Shadows> 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<ParticlesRenderer> 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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user