Skip to content

Commit

Permalink
Fix shadow flicker on camera offset update (#15709)
Browse files Browse the repository at this point in the history
  • Loading branch information
sfan5 authored Jan 25, 2025
1 parent 7c6ade0 commit b861f0c
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 22 deletions.
7 changes: 5 additions & 2 deletions src/client/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2984,6 +2984,10 @@ void Game::updateCameraOffset()
return;

if (!m_flags.disable_camera_update) {
auto *shadow = RenderingEngine::get_shadow_renderer();
if (shadow)
shadow->getDirectionalLight().updateCameraOffset(camera);

env.getClientMap().updateCamera(camera->getPosition(),
camera->getDirection(), camera->getFovMax(), camera_offset,
env.getLocalPlayer()->light_color);
Expand Down Expand Up @@ -3978,11 +3982,10 @@ void Game::updateShadows()
v3f light = is_day ? sky->getSunDirection() : sky->getMoonDirection();

v3f sun_pos = light * offset_constant;

shadow->getDirectionalLight().setDirection(sun_pos);
shadow->setTimeOfDay(in_timeofday);

shadow->getDirectionalLight().update_frustum(camera, client, m_camera_offset_changed);
shadow->getDirectionalLight().updateFrustum(camera, client);
}

void Game::drawScene(ProfilerGraph *graph, RunStats *stats)
Expand Down
23 changes: 10 additions & 13 deletions src/client/shadows/dynamicshadows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
// adjusted camera positions
v3f cam_pos_world = cam->getPosition();

// if world position is less than 1 block away from the captured
// if world position is less than 1 node 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;
Expand Down Expand Up @@ -84,9 +84,16 @@ DirectionalLight::DirectionalLight(const u32 shadowMapResolution,
farPlane(farValue), mapRes(shadowMapResolution), pos(position)
{}

void DirectionalLight::update_frustum(const Camera *cam, Client *client, bool force)
void DirectionalLight::updateCameraOffset(const Camera *cam)
{
if (dirty && !force)
createSplitMatrices(cam);
should_update_map_shadow = true;
dirty = true;
}

void DirectionalLight::updateFrustum(const Camera *cam, Client *client)
{
if (dirty)
return;

float zNear = cam->getCameraNode()->getNearValue();
Expand All @@ -106,16 +113,6 @@ void DirectionalLight::update_frustum(const Camera *cam, Client *client, bool fo
getPosition(), getDirection(), future_frustum.radius, 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.rotateAndScaleVect(
intToFloat(cam_offset - shadow_frustum.camera_offset, BS));
shadow_frustum.ViewMat.setTranslation(shadow_frustum.ViewMat.getTranslation() + rotated_offset);
shadow_frustum.player += intToFloat(shadow_frustum.camera_offset - cam->getOffset(), BS);
shadow_frustum.camera_offset = cam_offset;
}
}

void DirectionalLight::commitFrustum()
Expand Down
4 changes: 2 additions & 2 deletions src/client/shadows/dynamicshadows.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ class DirectionalLight
f32 farValue = 100.0f);
~DirectionalLight() = default;

//DISABLE_CLASS_COPY(DirectionalLight)
void updateCameraOffset(const Camera *cam);

void update_frustum(const Camera *cam, Client *client, bool force = false);
void updateFrustum(const Camera *cam, Client *client);

// when set direction is updated to negative normalized(direction)
void setDirection(v3f dir);
Expand Down
13 changes: 8 additions & 5 deletions src/client/shadows/dynamicshadowsrender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,14 @@ void ShadowRenderer::updateSMTextures()

// detect if SM should be regenerated
for (DirectionalLight &light : m_light_list) {
if (light.should_update_map_shadow || m_force_update_shadow_map) {
light.should_update_map_shadow = false;
m_current_frame = 0;
reset_sm_texture = true;
}
if (light.should_update_map_shadow)
m_force_update_shadow_map = true;
light.should_update_map_shadow = false;
}

if (m_force_update_shadow_map) {
m_current_frame = 0;
reset_sm_texture = true;
}

video::ITexture* shadowMapTargetTexture = shadowMapClientMapFuture;
Expand Down

0 comments on commit b861f0c

Please sign in to comment.