diff options
author | x2048 <codeforsmile@gmail.com> | 2021-07-25 12:36:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-25 12:36:23 +0200 |
commit | bf3acbf388406f736286d990adb5f35a9023c390 (patch) | |
tree | 9fdff755e37253580c222ff768802a6b0170be10 /src/client/shadows/dynamicshadows.cpp | |
parent | ff2d2a6e93d75d24b3f69f2b3690bcac6440961e (diff) | |
download | minetest-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.cpp | 60 |
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; |