aboutsummaryrefslogtreecommitdiff
path: root/src/client/shadows/dynamicshadows.cpp
diff options
context:
space:
mode:
authorx2048 <codeforsmile@gmail.com>2021-07-25 12:36:23 +0200
committerGitHub <noreply@github.com>2021-07-25 12:36:23 +0200
commitbf3acbf388406f736286d990adb5f35a9023c390 (patch)
tree9fdff755e37253580c222ff768802a6b0170be10 /src/client/shadows/dynamicshadows.cpp
parentff2d2a6e93d75d24b3f69f2b3690bcac6440961e (diff)
downloadminetest-bf3acbf388406f736286d990adb5f35a9023c390.tar.gz
minetest-bf3acbf388406f736286d990adb5f35a9023c390.tar.bz2
minetest-bf3acbf388406f736286d990adb5f35a9023c390.zip
Distribute shadow map update over multiple frames to reduce stutter (#11422)
Reduces stutter and freezes when playing. * Maintains double SM and SM Color textures * Light frustum update triggers incremental generation of shadow map into secondary 'future' textures. * Every incremental update renders a portion of the shadow draw list (split equally). * After defined number of frames (currently, 4), 'future' and 'current' textures are swapped, and DirectionalLight 'commits' the new frustum to use when rendering shadows on screen. Co-authored-by: sfan5 <sfan5@live.de>
Diffstat (limited to 'src/client/shadows/dynamicshadows.cpp')
-rw-r--r--src/client/shadows/dynamicshadows.cpp60
1 files changed, 46 insertions, 14 deletions
diff --git a/src/client/shadows/dynamicshadows.cpp b/src/client/shadows/dynamicshadows.cpp
index 17b711a61..0c7eea0e7 100644
--- a/src/client/shadows/dynamicshadows.cpp
+++ b/src/client/shadows/dynamicshadows.cpp
@@ -38,8 +38,8 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
float tanFovX = tanf(cam->getFovX() * 0.5f);
// adjusted frustum boundaries
- float sfNear = shadow_frustum.zNear;
- float sfFar = adjustDist(shadow_frustum.zFar, cam->getFovY());
+ float sfNear = future_frustum.zNear;
+ float sfFar = adjustDist(future_frustum.zFar, cam->getFovY());
// adjusted camera positions
v3f camPos2 = cam->getPosition();
@@ -87,14 +87,15 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
v3f eye_displacement = direction * vvolume;
// we must compute the viewmat with the position - the camera offset
- // but the shadow_frustum position must be the actual world position
+ // but the future_frustum position must be the actual world position
v3f eye = frustumCenter - eye_displacement;
- shadow_frustum.position = world_center - eye_displacement;
- shadow_frustum.length = vvolume;
- shadow_frustum.ViewMat.buildCameraLookAtMatrixLH(eye, frustumCenter, v3f(0.0f, 1.0f, 0.0f));
- shadow_frustum.ProjOrthMat.buildProjectionMatrixOrthoLH(shadow_frustum.length,
- shadow_frustum.length, -shadow_frustum.length,
- shadow_frustum.length,false);
+ future_frustum.position = world_center - eye_displacement;
+ future_frustum.length = vvolume;
+ future_frustum.ViewMat.buildCameraLookAtMatrixLH(eye, frustumCenter, v3f(0.0f, 1.0f, 0.0f));
+ future_frustum.ProjOrthMat.buildProjectionMatrixOrthoLH(future_frustum.length,
+ future_frustum.length, -future_frustum.length,
+ future_frustum.length,false);
+ future_frustum.camera_offset = cam->getOffset();
}
DirectionalLight::DirectionalLight(const u32 shadowMapResolution,
@@ -104,23 +105,44 @@ DirectionalLight::DirectionalLight(const u32 shadowMapResolution,
farPlane(farValue), mapRes(shadowMapResolution), pos(position)
{}
-void DirectionalLight::update_frustum(const Camera *cam, Client *client)
+void DirectionalLight::update_frustum(const Camera *cam, Client *client, bool force)
{
- should_update_map_shadow = true;
+ if (dirty && !force)
+ return;
+
float zNear = cam->getCameraNode()->getNearValue();
float zFar = getMaxFarValue();
///////////////////////////////////
// update splits near and fars
- shadow_frustum.zNear = zNear;
- shadow_frustum.zFar = zFar;
+ future_frustum.zNear = zNear;
+ future_frustum.zFar = zFar;
// update shadow frustum
createSplitMatrices(cam);
// get the draw list for shadows
client->getEnv().getClientMap().updateDrawListShadow(
- getPosition(), getDirection(), shadow_frustum.length);
+ getPosition(), getDirection(), future_frustum.length);
should_update_map_shadow = true;
+ dirty = true;
+
+ // when camera offset changes, adjust the current frustum view matrix to avoid flicker
+ v3s16 cam_offset = cam->getOffset();
+ if (cam_offset != shadow_frustum.camera_offset) {
+ v3f rotated_offset;
+ shadow_frustum.ViewMat.rotateVect(rotated_offset, intToFloat(cam_offset - shadow_frustum.camera_offset, BS));
+ shadow_frustum.ViewMat.setTranslation(shadow_frustum.ViewMat.getTranslation() + rotated_offset);
+ shadow_frustum.camera_offset = cam_offset;
+ }
+}
+
+void DirectionalLight::commitFrustum()
+{
+ if (!dirty)
+ return;
+
+ shadow_frustum = future_frustum;
+ dirty = false;
}
void DirectionalLight::setDirection(v3f dir)
@@ -144,6 +166,16 @@ const m4f &DirectionalLight::getProjectionMatrix() const
return shadow_frustum.ProjOrthMat;
}
+const m4f &DirectionalLight::getFutureViewMatrix() const
+{
+ return future_frustum.ViewMat;
+}
+
+const m4f &DirectionalLight::getFutureProjectionMatrix() const
+{
+ return future_frustum.ProjOrthMat;
+}
+
m4f DirectionalLight::getViewProjMatrix()
{
return shadow_frustum.ProjOrthMat * shadow_frustum.ViewMat;