Jitter, stutter and input lag: diagnosis
Separate physics motion, long frames and input lag; verify settings through measurements.
Identify the symptom
| Symptom | What to measure first |
|---|---|
| Fine shaking during steady movement, camera and background move differently | Camera/object update order, physics step and interpolation |
| Occasional freezes or skipped motion | Individual frame times, CPU/GPU, resource loading and pipeline compilation |
| Input visibly precedes the on-screen response | Input handling, physics step, frame queue and path to the display |
These problems can coexist. Average FPS hides occasional long frames: a 60 FPS target has a frame budget of about 16.67 ms. Compare frame-time distribution and spikes with the moment the defect occurs.
Obtain a reproducible result
- Fix the build, scene, camera route, resolution and quality settings. Start with the smallest section that reproduces the issue.
- Compare editor play and the exported game on the same device. Record the actual renderer, driver, window mode, display refresh rate, V-Sync and FPS cap.
- Measure frame time and CPU/GPU costs. Compare first and repeated passes: a hitch only on the first new effect warrants checking loading and compilation, but does not prove one particular cause.
- Change one setting at a time, repeat the same route and retain the result.
Use performance measurement and profiling. Lowering resolution can test a GPU-cost hypothesis, but does not by itself identify the exact bottleneck.
Jitter: coordinate physics and the camera
Move physics bodies in _PhysicsProcess(double delta). Physics and rendering have different frequencies; moving a camera in _Process(double delta) using a body's raw position can expose those steps.
Enable and configure physics interpolation. It smooths presentation between physics states; it does not speed up physics calculations or guarantee smoothness at every frame time.
Check parent and child interpolation modes. After teleporting, set the new transform, then call ResetPhysicsInterpolation() to avoid drawing a transition from the previous position. For a manually controlled 3D camera, consider the target's GetGlobalTransformInterpolated() rather than mixing an interpolated image with a raw physics position.
Engine.PhysicsTicksPerSecond controls physics frequency, not rendering FPS. Increasing it shortens each step but increases simulation cost and can change outcomes. It is not a universal cure for jitter, tunneling or network divergence. Test gameplay at the chosen frequency, especially for competitive network simulation.
Occasional stalls: locate work in the long frame
| When the stall occurs | Where to look |
|---|---|
| Loading a level or model | Synchronous reading, parsing, resource and instance creation |
| First display of a material or effect | Graphics-pipeline creation and compilation; compilation checks |
| Creating many objects | Scripts, allocations, garbage collection, physics/render registration |
| Consistently in a complex frame | CPU/GPU profile, shadows, geometry, transparency and resolution |
Showing every effect for one frame does not guarantee that all future compilation is eliminated: variants depend on passes, materials and configuration. Check the actual route and counters. Toggling V-Sync does not remove synchronous file reads or expensive calculations.
Input lag: change a specific stage
Input.UseAccumulatedInput merges compatible events, such as several mouse motions, preserving total displacement. It does not promise to combine every event type into one or call every handler exactly once per frame.
Disabling accumulation can help drawing or precise motion tracking, but increases delivered-event count. With input_devices/buffering/agile_event_flushing=true, buffering remains even with Input.UseAccumulatedInput=false. Toggling the property does not flush an already queued event.
Input.FlushBufferedEvents() delivers queued events; the engine also flushes during its execution loop. Explicit flushing is for algorithms needing controlled delivery: it can invoke input handlers during the call itself. Do not add it everywhere as a universal speed improvement.
| Setting | What to check |
|---|---|
| V-Sync | Tearing, frame time and latency on the target display; do not assume disabling is always better |
FPS cap / Engine.MaxFps | Frame-time stability and load; separate from physics frequency |
| Swapchain image count | Renderer/driver support and actual queue; the requested count does not guarantee identical behavior on all devices |
| VRR and window mode | Actual display mode and measurement, rather than the option name |
For launch comparisons, use --disable-vsync and --max-fps <fps>; the driver can enforce V-Sync. See the command line for launch details. Do not apply one FPS-cap formula to every display and driver.
What to include in a report
Record the build, OS, GPU/driver, actual renderer, resolution, display refresh rate, window mode, V-Sync, FPS cap, physics frequency and interpolation settings. Include a minimal project, exact steps and frame-time recording marking the problem.
For input-to-display latency, use a recording showing the input device and screen together. FPS and software event-processing time do not measure this entire path. State the recording frame rate and precision limit; do not promise millisecond latency based solely on project settings.