diff --git a/src/client/camera.cpp b/src/client/camera.cpp index 4abe062d7..76e914b80 100644 --- a/src/client/camera.cpp +++ b/src/client/camera.cpp @@ -26,7 +26,8 @@ #include #include -#define CAMERA_OFFSET_STEP 200 +static constexpr f32 CAMERA_OFFSET_STEP = 200; + #define WIELDMESH_OFFSET_X 55.0f #define WIELDMESH_OFFSET_Y -35.0f #define WIELDMESH_AMPLITUDE_X 7.0f @@ -281,6 +282,20 @@ void Camera::addArmInertia(f32 player_yaw) } } +void Camera::updateOffset() +{ + v3f cp = m_camera_position / BS; + + // Update offset if too far away from the center of the map + m_camera_offset = v3s16( + floorf(cp.X / CAMERA_OFFSET_STEP) * CAMERA_OFFSET_STEP, + floorf(cp.Y / CAMERA_OFFSET_STEP) * CAMERA_OFFSET_STEP, + floorf(cp.Z / CAMERA_OFFSET_STEP) * CAMERA_OFFSET_STEP + ); + + // No need to update m_cameranode as that will be done before the next render. +} + void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio) { // Get player position @@ -366,6 +381,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio) m_headnode->updateAbsolutePosition(); } + // Compute relative camera position and target v3f rel_cam_pos = v3f(0,0,0); v3f rel_cam_target = v3f(0,0,1); @@ -397,12 +413,11 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio) v3f abs_cam_up = m_headnode->getAbsoluteTransformation() .rotateAndScaleVect(rel_cam_up); - // Separate camera position for calculation - v3f my_cp = m_camera_position; - // Reposition the camera for third person view if (m_camera_mode > CAMERA_MODE_FIRST) { + v3f my_cp = m_camera_position; + if (m_camera_mode == CAMERA_MODE_THIRD_FRONT) m_camera_direction *= -1; @@ -434,27 +449,19 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio) // If node blocks camera position don't move y to heigh if (abort && my_cp.Y > player_position.Y+BS*2) my_cp.Y = player_position.Y+BS*2; + + // update the camera position in third-person mode to render blocks behind player + // and correctly apply liquid post FX. + m_camera_position = my_cp; } - // Update offset if too far away from the center of the map - m_camera_offset.X += CAMERA_OFFSET_STEP* - (((s16)(my_cp.X/BS) - m_camera_offset.X)/CAMERA_OFFSET_STEP); - m_camera_offset.Y += CAMERA_OFFSET_STEP* - (((s16)(my_cp.Y/BS) - m_camera_offset.Y)/CAMERA_OFFSET_STEP); - m_camera_offset.Z += CAMERA_OFFSET_STEP* - (((s16)(my_cp.Z/BS) - m_camera_offset.Z)/CAMERA_OFFSET_STEP); - // Set camera node transformation - m_cameranode->setPosition(my_cp-intToFloat(m_camera_offset, BS)); - m_cameranode->updateAbsolutePosition(); + m_cameranode->setPosition(m_camera_position - intToFloat(m_camera_offset, BS)); m_cameranode->setUpVector(abs_cam_up); - // *100.0 helps in large map coordinates - m_cameranode->setTarget(my_cp-intToFloat(m_camera_offset, BS) + 100 * m_camera_direction); - - // update the camera position in third-person mode to render blocks behind player - // and correctly apply liquid post FX. - if (m_camera_mode != CAMERA_MODE_FIRST) - m_camera_position = my_cp; + m_cameranode->updateAbsolutePosition(); + // *100 helps in large map coordinates + m_cameranode->setTarget(m_camera_position - intToFloat(m_camera_offset, BS) + + 100 * m_camera_direction); /* * Apply server-sent FOV, instantaneous or smooth transition. diff --git a/src/client/camera.h b/src/client/camera.h index 3715bebad..de6f753a0 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -147,6 +147,9 @@ public: // Update the camera from the local player's position. void update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio); + // Adjust the camera offset when needed + void updateOffset(); + // Update render distance void updateViewingRange(); diff --git a/src/client/game.cpp b/src/client/game.cpp index e88b5d1d1..34e157a68 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -564,6 +564,7 @@ protected: void updatePauseState(); void step(f32 dtime); void processClientEvents(CameraOrientation *cam); + void updateCameraOffset(); void updateCamera(f32 dtime); void updateSound(f32 dtime); void processPlayerInteraction(f32 dtime, bool show_hud); @@ -988,6 +989,12 @@ void Game::run() m_game_ui->clearInfoText(); updateProfilers(stats, draw_times, dtime); + + // Update camera offset once before doing anything. + // In contrast to other updates the latency of this doesn't matter, + // since it's invisible to the user. But it needs to be consistent. + updateCameraOffset(); + processUserInput(dtime); // Update camera before player movement to avoid camera lag of one frame updateCameraDirection(&cam_view_target, dtime); @@ -1005,6 +1012,7 @@ void Game::run() processClientEvents(&cam_view_target); updateDebugState(); + // Update camera here so it is in-sync with CAO position updateCamera(dtime); updateSound(dtime); processPlayerInteraction(dtime, m_game_ui->m_flags.show_hud); @@ -2919,8 +2927,6 @@ void Game::updateCamera(f32 dtime) ToolCapabilities playeritem_toolcap = playeritem.getToolCapabilities(itemdef_manager); - v3s16 old_camera_offset = camera->getOffset(); - if (wasKeyPressed(KeyType::CAMERA_MODE)) { GenericCAO *playercao = player->getCAO(); @@ -2945,26 +2951,36 @@ void Game::updateCamera(f32 dtime) camera->update(player, dtime, tool_reload_ratio); camera->step(dtime); - f32 camera_fov = camera->getFovMax(); - v3s16 camera_offset = camera->getOffset(); - - m_camera_offset_changed = (camera_offset != old_camera_offset); - if (!m_flags.disable_camera_update) { - v3f camera_position = camera->getPosition(); - v3f camera_direction = camera->getDirection(); - - auto &env = client->getEnv(); - env.getClientMap().updateCamera(camera_position, - camera_direction, camera_fov, camera_offset, player->light_color); - - if (m_camera_offset_changed) { - env.updateCameraOffset(camera_offset); - clouds->updateCameraOffset(camera_offset); - } + client->getEnv().getClientMap().updateCamera(camera->getPosition(), + camera->getDirection(), camera->getFovMax(), camera->getOffset(), + player->light_color); } } +void Game::updateCameraOffset() +{ + ClientEnvironment &env = client->getEnv(); + + v3s16 old_camera_offset = camera->getOffset(); + + camera->updateOffset(); + + v3s16 camera_offset = camera->getOffset(); + + m_camera_offset_changed = camera_offset != old_camera_offset; + if (!m_camera_offset_changed) + return; + + if (!m_flags.disable_camera_update) { + env.getClientMap().updateCamera(camera->getPosition(), + camera->getDirection(), camera->getFovMax(), camera_offset, + env.getLocalPlayer()->light_color); + + env.updateCameraOffset(camera_offset); + clouds->updateCameraOffset(camera_offset); + } +} void Game::updateSound(f32 dtime) {