The camera says whether it is tracking a staircase

Janky tracking on a Live Cam, and the rotation is a spring-damper on the
fixed simulation step, so it should glide. Which leaves the input rather
than the smoothing: the camera follows a REMOTE pod, whose position only
changes on this host when an update lands. If the watched point sits still
for most steps and then leaps, the camera is tracking a staircase
faithfully and nothing in the rotation can hide it.

So FollowGoal now reports, every five seconds: how many simulation steps
it ran, how many of those saw the target move at all, the largest single
jump in metres, and how many times the trackside camera was cut to a
different one. At 50 Hz that is about 250 steps per report, so:

  moved near 250      the target moves every step - look elsewhere for
                      the jank, most likely frame pacing
  moved near 50       the target changes about ten times a second and the
                      camera is stepping between arrivals
  biggest jump large  confirms leaps rather than drift
  several cuts        the trackside camera is flip-flopping, which snaps
                      rather than glides and is its own kind of jank

The cut count is worth having because timeOnCamera is 0 for a race - the
director sets it to 0 outside football - so the closest-camera choice is
re-evaluated every step and only hysteresis stops it oscillating.

Not baselined locally: FollowGoal only runs on a camera station with a
peer, so unlike the nav and copy traces this one goes out unverified
against real numbers. The counters are simple enough to trust; the
interpretation above is what to hold it to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-08-10 22:26:15 -05:00
co-authored by Claude Opus 5
parent 7a3b117f61
commit 55e751648f
+64
View File
@@ -12,6 +12,12 @@
//############################# CameraShip ################################ //############################# CameraShip ################################
//########################################################################## //##########################################################################
//
// Trackside camera cuts since the last RP412CAMLOG report - counted where
// the cut happens and drained where it is reported, both in FollowGoal.
//
static int gCameraCuts = 0;
//############################################################################# //#############################################################################
// Shared Data Support // Shared Data Support
// //
@@ -320,6 +326,63 @@ void
Point3D target; Point3D target;
target.Multiply(focusOffset, goalEntity->localToWorld); target.Multiply(focusOffset, goalEntity->localToWorld);
//
// RP412CAMLOG: is the thing we are following actually MOVING every
// step, or arriving in jumps?
//
// This runs on the fixed simulation step, so it is called at a steady
// rate whatever the frame rate. The entity it follows is a REMOTE pod,
// whose position only changes when an update lands - so if the watched
// point is identical on most steps and then leaps, the camera is
// tracking a staircase and no amount of smoothing here will hide it.
// Reported as: steps counted, how many of them saw any movement at
// all, the largest single jump, and how often the trackside camera was
// cut to a different one (a cut is a snap, not a glide, and would look
// like jank of a different kind).
//
if (RPCameraLog())
{
static Scalar next_say = 0.0f;
static Point3D last_target(0.0f, 0.0f, 0.0f);
static Logical have_last = False;
static int steps = 0;
static int moved = 0;
static Scalar biggest = 0.0f;
++steps;
if (have_last)
{
Vector3D step_delta;
step_delta.Subtract(target, last_target);
Scalar distance = step_delta.Length();
if (distance > 0.0f)
{
++moved;
}
if (distance > biggest)
{
biggest = distance;
}
}
last_target = target;
have_last = True;
if ((Scalar) Now() >= next_say)
{
if (next_say > 0.0f)
{
DEBUG_STREAM << "CamLog: follow - " << steps << " steps, "
<< moved << " moved, biggest jump " << biggest
<< "m, " << gCameraCuts << " cut(s)\n" << std::flush;
}
next_say = ((Scalar) Now()) + 5.0f;
steps = 0;
moved = 0;
biggest = 0.0f;
gCameraCuts = 0;
}
}
// //
//------------------------------------------------------------------------ //------------------------------------------------------------------------
// If time has not yet expired on this camera, keep with it if can see the // If time has not yet expired on this camera, keep with it if can see the
@@ -348,6 +411,7 @@ void
// //
if (currentCamera != old_camera) if (currentCamera != old_camera)
{ {
++gCameraCuts;
AimCameraAtPoint(target); AimCameraAtPoint(target);
lastSwitch = lastPerformance; lastSwitch = lastPerformance;
} }