aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorx2048 <codeforsmile@gmail.com>2022-11-20 21:28:01 +0100
committerGitHub <noreply@github.com>2022-11-20 21:28:01 +0100
commit70a82b07844ce5187ba030110ea84c0e6c07c291 (patch)
treea6266a4eac4030a5312a4d790a9bf1aa57dea15d /src
parent5f24a3c0c7630b2bad530aab7deeaa9468c59fd9 (diff)
downloadminetest-70a82b07844ce5187ba030110ea84c0e6c07c291.tar.xz
Avoid shadow flicker at certain angles (#12961)
Change the way look direction and camera position are quantized when calculating light frustum
Diffstat (limited to 'src')
-rw-r--r--src/client/shadows/dynamicshadows.cpp24
-rw-r--r--src/client/shadows/dynamicshadows.h4
2 files changed, 21 insertions, 7 deletions
diff --git a/src/client/shadows/dynamicshadows.cpp b/src/client/shadows/dynamicshadows.cpp
index 9f26ba94a..80db64286 100644
--- a/src/client/shadows/dynamicshadows.cpp
+++ b/src/client/shadows/dynamicshadows.cpp
@@ -41,10 +41,16 @@ static v3f quantizeDirection(v3f direction, float step)
void DirectionalLight::createSplitMatrices(const Camera *cam)
{
- const float DISTANCE_STEP = BS * 2.0; // 2 meters
+ static const float COS_15_DEG = 0.965926f;
v3f newCenter;
- v3f look = cam->getDirection();
- look = quantizeDirection(look, M_PI / 12.0); // 15 degrees
+ v3f look = cam->getDirection().normalize();
+
+ // if current look direction is < 15 degrees away from the captured
+ // look direction then stick to the captured value, otherwise recapture.
+ if (look.dotProduct(last_look) >= COS_15_DEG)
+ look = last_look;
+ else
+ last_look = look;
// camera view tangents
float tanFovY = tanf(cam->getFovY() * 0.5f);
@@ -56,10 +62,14 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
// adjusted camera positions
v3f cam_pos_world = cam->getPosition();
- cam_pos_world = v3f(
- floor(cam_pos_world.X / DISTANCE_STEP) * DISTANCE_STEP,
- floor(cam_pos_world.Y / DISTANCE_STEP) * DISTANCE_STEP,
- floor(cam_pos_world.Z / DISTANCE_STEP) * DISTANCE_STEP);
+
+ // if world position is less than 1 block away from the captured
+ // world position then stick to the captured value, otherwise recapture.
+ if (cam_pos_world.getDistanceFromSQ(last_cam_pos_world) < BS * BS)
+ cam_pos_world = last_cam_pos_world;
+ else
+ last_cam_pos_world = cam_pos_world;
+
v3f cam_pos_scene = v3f(cam_pos_world.X - cam->getOffset().X * BS,
cam_pos_world.Y - cam->getOffset().Y * BS,
cam_pos_world.Z - cam->getOffset().Z * BS);
diff --git a/src/client/shadows/dynamicshadows.h b/src/client/shadows/dynamicshadows.h
index 6e9d96b15..f592ec077 100644
--- a/src/client/shadows/dynamicshadows.h
+++ b/src/client/shadows/dynamicshadows.h
@@ -114,6 +114,10 @@ private:
v3f pos;
v3f direction{0};
+
+ v3f last_cam_pos_world{0,0,0};
+ v3f last_look{0,1,0};
+
shadowFrustum shadow_frustum;
shadowFrustum future_frustum;
bool dirty{false};