From 230e5efc1641e14733ca4044d0d928075a284d9e Mon Sep 17 00:00:00 2001 From: Vsevolod Kremianskii Date: Wed, 17 Feb 2021 22:57:08 +0700 Subject: [PATCH] feat: Implement fading of the shadow light --- src/render/shaders.cpp | 3 ++- src/render/shaders.h | 1 + src/scene/pipeline/control.cpp | 2 -- src/scene/pipeline/world.cpp | 20 +++++++++++------ src/scene/scenegraph.cpp | 39 ++++++++++++++++++++++++++++------ src/scene/scenegraph.h | 17 +++++++++------ 6 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/render/shaders.cpp b/src/render/shaders.cpp index a9f7a866..c1412956 100644 --- a/src/render/shaders.cpp +++ b/src/render/shaders.cpp @@ -100,6 +100,7 @@ layout(std140) uniform General { float uWaterAlpha; int uFeatureMask; bool uShadowLightPresent; + float uShadowStrength; float uRoughness; float uExposure; }; @@ -237,7 +238,7 @@ float getShadow() { } } - return shadow / (samples * samples * samples); + return uShadowStrength * shadow / (samples * samples * samples); } float getLightAttenuation(int light) { diff --git a/src/render/shaders.h b/src/render/shaders.h index c54fd440..51ec8bf6 100644 --- a/src/render/shaders.h +++ b/src/render/shaders.h @@ -98,6 +98,7 @@ struct GeneralUniforms { float waterAlpha { 1.0f }; int featureMask { 0 }; /**< any combination of UniformFeaturesFlags */ int shadowLightPresent { false }; + float shadowStrength { 1.0f }; float roughness { 0.0f }; float exposure { 1.0f }; }; diff --git a/src/scene/pipeline/control.cpp b/src/scene/pipeline/control.cpp index 7265ec7e..7177a817 100644 --- a/src/scene/pipeline/control.cpp +++ b/src/scene/pipeline/control.cpp @@ -72,8 +72,6 @@ void ControlRenderPipeline::render(const glm::ivec2 &offset) { uniforms.general.projection = _scene->activeCamera()->projection(); uniforms.general.view = _scene->activeCamera()->view(); uniforms.general.cameraPosition = _scene->activeCamera()->absoluteTransform()[3]; - uniforms.general.shadowLightPresent = _scene->isShadowLightPresent(); - uniforms.general.shadowLightPosition = glm::vec4(_scene->shadowLightPosition(), 1.0f); _scene->setUniformsPrototype(move(uniforms)); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); diff --git a/src/scene/pipeline/world.cpp b/src/scene/pipeline/world.cpp index ad41ec55..083acbf1 100644 --- a/src/scene/pipeline/world.cpp +++ b/src/scene/pipeline/world.cpp @@ -32,6 +32,7 @@ #include "../../render/window.h" #include "../node/cameranode.h" +#include "../node/lightnode.h" #include "../scenegraph.h" using namespace std; @@ -131,19 +132,21 @@ void WorldRenderPipeline::render() { } void WorldRenderPipeline::drawShadows() { - if (!_scene->isShadowLightPresent() || _opts.shadowResolution < 1) return; + if (_opts.shadowResolution < 1) return; - withViewport(glm::ivec4(0, 0, 1024 * _opts.shadowResolution, 1024 * _opts.shadowResolution), [this]() { + const LightSceneNode *shadowLight = _scene->shadowLight(); + if (!shadowLight) return; + + withViewport(glm::ivec4(0, 0, 1024 * _opts.shadowResolution, 1024 * _opts.shadowResolution), [&]() { _shadows.bind(); glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); glm::mat4 projection(glm::perspective(glm::radians(90.0f), 1.0f, 1.0f, kShadowFarPlane)); - glm::vec3 lightPosition(_scene->shadowLightPosition()); + glm::vec3 lightPosition(shadowLight->absoluteTransform()[3]); ShaderUniforms uniforms; - uniforms.general.shadowLightPresent = true; uniforms.general.shadowLightPosition = glm::vec4(lightPosition, 1.0f); for (int i = 0; i < kNumCubeFaces; ++i) { @@ -183,15 +186,18 @@ void WorldRenderPipeline::drawGeometry() { static constexpr GLenum buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 }; glDrawBuffers(2, buffers); + const LightSceneNode *shadowLight = _scene->shadowLight(); + ShaderUniforms uniforms; uniforms.general.projection = _scene->activeCamera()->projection(); uniforms.general.view = _scene->activeCamera()->view(); uniforms.general.cameraPosition = _scene->activeCamera()->absoluteTransform()[3]; - uniforms.general.shadowLightPresent = _scene->isShadowLightPresent(); - uniforms.general.shadowLightPosition = glm::vec4(_scene->shadowLightPosition(), 1.0f); + uniforms.general.shadowLightPresent = static_cast(shadowLight); + uniforms.general.shadowLightPosition = shadowLight ? shadowLight->absoluteTransform()[3] : glm::vec4(0.0f); + uniforms.general.shadowStrength = _scene->shadowStrength(); _scene->setUniformsPrototype(move(uniforms)); - if (_scene->isShadowLightPresent()) { + if (shadowLight) { setActiveTextureUnit(TextureUnits::shadowMap); _shadowsDepth->bind(); } diff --git a/src/scene/scenegraph.cpp b/src/scene/scenegraph.cpp index 9ebe7523..914d2d24 100644 --- a/src/scene/scenegraph.cpp +++ b/src/scene/scenegraph.cpp @@ -157,16 +157,35 @@ void SceneGraph::refreshFromSceneNode(const std::shared_ptr &node) { } void SceneGraph::refreshShadowLight() { - _shadowLightPresent = false; + const LightSceneNode *nextShadowLight = nullptr; - if (!_shadowReference) return; + if (_shadowReference) { + vector lights; + getLightsAt(*_shadowReference, lights, 1, [](auto &light) { return light.isShadow(); }); - vector lights; - getLightsAt(*_shadowReference, lights, 1, [](auto &light) { return light.isShadow(); }); + if (!lights.empty()) { + nextShadowLight = lights.front(); + } + } - if (!lights.empty()) { - _shadowLightPresent = true; - _shadowLightPosition = lights.front()->absoluteTransform()[3]; + if (!nextShadowLight) { + _shadowLight = nullptr; + return; + } + + if (!_shadowLight) { + _shadowLight = nextShadowLight; + _shadowFading = false; + return; + } + + if (_shadowLight == nextShadowLight) return; + + if (_shadowFading && _shadowStrength == 0.0f) { + _shadowLight = nextShadowLight; + _shadowFading = false; + } else { + _shadowFading = true; } } @@ -176,6 +195,12 @@ void SceneGraph::update(float dt) { for (auto &root : _roots) { root->update(dt); } + + if (_shadowFading) { + _shadowStrength = glm::max(0.0f, _shadowStrength - dt); + } else { + _shadowStrength = glm::min(_shadowStrength + dt, 1.0f); + } } void SceneGraph::render(bool shadowPass) { diff --git a/src/scene/scenegraph.h b/src/scene/scenegraph.h index 44bac488..c0ef3ee1 100644 --- a/src/scene/scenegraph.h +++ b/src/scene/scenegraph.h @@ -71,8 +71,6 @@ public: // Lights and shadows - bool isShadowLightPresent() const { return _shadowLightPresent; } - /** * Fills lights vector with up to count lights, sorted by priority and * proximity to the reference node. @@ -84,7 +82,8 @@ public: std::function predicate = [](auto &light) { return true; }) const; const glm::vec3 &ambientLightColor() const { return _ambientLightColor; } - const glm::vec3 &shadowLightPosition() const { return _shadowLightPosition; } + const LightSceneNode *shadowLight() const { return _shadowLight; } + float shadowStrength() const { return _shadowStrength; } void setAmbientLightColor(const glm::vec3 &color); @@ -102,13 +101,19 @@ private: std::shared_ptr _activeCamera; glm::vec3 _ambientLightColor { 0.5f }; uint32_t _textureId { 0 }; - bool _shadowLightPresent { false }; - glm::vec3 _shadowLightPosition { 0.0f }; - std::shared_ptr _shadowReference; bool _update { true }; render::ShaderUniforms _uniformsPrototype; float _exposure { kDefaultExposure }; + // Shadows + + const LightSceneNode *_shadowLight { nullptr }; + std::shared_ptr _shadowReference; + float _shadowStrength { 1.0f }; + bool _shadowFading { false }; + + // END Shadows + void refreshNodeLists(); void refreshFromSceneNode(const std::shared_ptr &node); void refreshShadowLight();