FollowCamera requires CNA link

Easy3D / Cameras / FollowCamera

Easy3D::FollowCamera is a camera position that smoothly chases targetPosition + offset. It holds its own current position and lerps toward the desired position each Update(), with a smoothing model that is frame-rate independent: the same smoothing value behaves identically at 30, 60, or 144 fps.

#include <Easy3D/FollowCamera.hpp>

namespace Easy3D { class FollowCamera; }

Type aliases

AliasRefers to
FollowCamera::Vector3Microsoft::Xna::Framework::Vector3

Defaults

PropertyDefaultNotes
Position(0, 0, 0)The camera's own current position
Offset(0, 5, 10)Above and behind the target
Smoothing0.15Closes 15% of the remaining gap per 1/60 s

API

[[nodiscard]] const Vector3& GetOffset() const noexcept
void SetOffset(const Vector3& value) noexcept
The offset added to the target position to get the desired camera position.
[[nodiscard]] float GetSmoothing() const noexcept
void SetSmoothing(float value) noexcept
Smoothing factor in (0, 1]; higher follows more tightly. See "How smoothing works" below for the exact semantics.
[[nodiscard]] const Vector3& GetPosition() const noexcept
void SetPosition(const Vector3& value) noexcept
The camera's current (smoothed) position. Set it directly to teleport the camera, e.g. after a level change.
void Update(const Vector3& targetPosition, float deltaSeconds)
Advances the follow position toward targetPosition + offset, scaling the smoothing by the elapsed frame time. Requires linking CNA (uses CNA Vector3 math).
void ApplyTo(Camera3D& camera, const Vector3& targetPosition) const
Pushes the current position into a Camera3D and aims it at targetPosition. Requires linking CNA.

How smoothing works

The smoothing value is defined as the fraction of the remaining gap to the desired position that is closed in one reference tick of 1/60 s, independent of the actual deltaSeconds passed to Update(). For example, 0.15f closes 15% of the gap per 1/60 s of elapsed time whether the game runs at 30, 60, or 144 fps — only the reference rate used to interpret the value is fixed at 60.

Internally, Update() re-derives an exponential decay for the elapsed time:

remainingFraction(dt) = (1 - smoothing) ^ (dt * 60)
t(dt)                 = 1 - remainingFraction(dt)
position              = Vector3::Lerp(position, target + offset, t)

This makes two consecutive Update(dt1) + Update(dt2) calls converge to the same position as one Update(dt1 + dt2) call — unlike the naive t = smoothing * deltaSeconds, which drifts with frame rate.

Smoothing valueBehavior
≥ 1.0Snap — the camera jumps straight to target + offset every update.
(0, 1)Exponential chase; higher = tighter. 0.15 is a comfortable default.
≤ 0.0Frozen — the camera never moves.
The reference rate of 60 fps is part of the smoothing value's contract, kept for continuity with tuning done when the project's game loop targeted 60 fps. It is not a tunable — changing it would change the meaning of every existing SetSmoothing() call site.

Example — a game update loop

#include <Easy3D/Camera3D.hpp>
#include <Easy3D/FollowCamera.hpp>

Easy3D::Camera3D     camera;
Easy3D::FollowCamera follow;
follow.SetOffset({0.0f, 6.0f, 12.0f});   // above and behind the player
follow.SetSmoothing(0.15f);

// Each frame (deltaSeconds from your CNA game loop):
follow.Update(player.Position, deltaSeconds);
follow.ApplyTo(camera, player.Position);   // position = smoothed, target = player

const auto view = camera.GetViewMatrix();
On level start or teleport, call SetPosition(target + offset) once so the camera does not visibly fly across the level to catch up.