feat: Implement fading of the shadow light

This commit is contained in:
Vsevolod Kremianskii 2021-02-17 22:57:08 +07:00
parent 14c3ee3722
commit 230e5efc16
6 changed files with 59 additions and 23 deletions

View file

@ -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) {

View file

@ -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 };
};

View file

@ -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);

View file

@ -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<bool>(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();
}

View file

@ -157,16 +157,35 @@ void SceneGraph::refreshFromSceneNode(const std::shared_ptr<SceneNode> &node) {
}
void SceneGraph::refreshShadowLight() {
_shadowLightPresent = false;
const LightSceneNode *nextShadowLight = nullptr;
if (!_shadowReference) return;
if (_shadowReference) {
vector<LightSceneNode *> lights;
getLightsAt(*_shadowReference, lights, 1, [](auto &light) { return light.isShadow(); });
vector<LightSceneNode *> 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) {

View file

@ -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<bool(const LightSceneNode &)> 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<CameraSceneNode> _activeCamera;
glm::vec3 _ambientLightColor { 0.5f };
uint32_t _textureId { 0 };
bool _shadowLightPresent { false };
glm::vec3 _shadowLightPosition { 0.0f };
std::shared_ptr<SceneNode> _shadowReference;
bool _update { true };
render::ShaderUniforms _uniformsPrototype;
float _exposure { kDefaultExposure };
// Shadows
const LightSceneNode *_shadowLight { nullptr };
std::shared_ptr<SceneNode> _shadowReference;
float _shadowStrength { 1.0f };
bool _shadowFading { false };
// END Shadows
void refreshNodeLists();
void refreshFromSceneNode(const std::shared_ptr<SceneNode> &node);
void refreshShadowLight();