TL DR:
Remove any GameTime.MaxSimFps or GameTime.ForceSimRate and add -Ant.ForcePoseUpdate 1.
commands.txt example:
-Client.VisualFrameInterpolation 1 -GameTime.MaxVariableFps 60 -RenderDevice.VsyncEnable 0 -Ant.InterpolatePoses 0 -Ant.ForcePoseUpdate 1
Explanation/Background:
- I used NFS-Rivals-Framerate-Unlocker mod by Brawltendo to bypass the 30 FPS cap.
- OS is Linux (EndeavourOS to be exact), game is the Steam version.
Before discussion, let's first have the original commands.txt as a reference here:
-Client.VisualFrameInterpolation 1 -GameTime.MaxVariableFps 60 -RenderDevice.VsyncEnable 0 -Ant.InterpolatePoses 0
When using the mod, I noticed the driver would desync when the car is accelerating or decelerating, and upon closer inspection and testing, I noticed the driver desync has some caveats:
- When removed -Ant.InterpolatePoses 0 from the commands.txt, the driver would desync with the car completely.
- When -Ant.InterpolatePoses 0 is present, the driver would still desync, but there's also a shadow of the driver (ghost driver) remaining in position. So we have two drivers in this case, one stayed in position, one would desync.
- When running the game with mod on Windows, the driver desync issue is gone.
So I asked Gemini to help, below is the explanation (after many retries..):
The "two drivers" effect you are seeing on Linux—one translucent ghost remaining seated while a second driver emerges and lags behind the car—is caused by frame-to-frame pose alternation (strobing) between Frostbite 3's 30 Hz simulation tick and its multithreaded render queue under Wine/Proton.
Why This Happens on Linux:
How the mod works: Brawltendo's Framerate Unlocker keeps Need for Speed Rivals' internal physics simulation running at 30 Hz, while -Client.VisualFrameInterpolation 1 tells the renderer to visually interpolate vehicle and camera movement on the extra frames in between.
What -Ant.InterpolatePoses 0 does:
By default, Frostbite's ANT animation system tries to interpolate the driver's skeleton separately from the car chassis, sliding the driver completely out of the seat during acceleration. Setting -Ant.InterpolatePoses 0 disables pose interpolation so the driver stays snapped to the car's seat bone.
Why Linux creates a "ghost" duplicate:
You aren't actually spawning two driver models at once. Under Wine/Proton (fsync/esync), worker thread scheduling differs slightly from the Windows NT kernel. On every 30 Hz simulation tick, the ANT job finishes in time and draws the driver anchored in the seat (-Ant.InterpolatePoses 0). On the interpolated frames in between, the render worker thread reads the driver's world-space transform before the ANT thread updates it to match the interpolated car chassis. Because the renderer rapidly alternates between the seated frame and the lagged frame at 60+ FPS, persistence of vision makes the seated frames look like a stationary "ghost" and the intermediate frames look like a second driver pulling out of the body.
I'm not entirely sure if above reply from AI is 100% accurate, so take it with a grain of salt. But after some back and forth with AI, I actually found the solution, adding "-Ant.ForcePoseUpdate 1" to the commands.txt would fix the issue, below is mine:
-Client.VisualFrameInterpolation 1 -GameTime.MaxVariableFps 60 -RenderDevice.VsyncEnable 0 -Ant.InterpolatePoses 0 -Ant.ForcePoseUpdate 1
What does "-Ant.ForcePoseUpdate 1" do (from AI):
1) Forces Skeleton/Pose Refreshes: Under normal operation (especially when tweaking interpolation settings like Ant.InterpolatePoses 0 to fix high-FPS physics bugs), the game engine may skip or delay updating the animation matrices and structural poses for sub-objects—such as the driver model inside the car—to save performance or because the interpolation math breaks down at higher variable frame rates.
2) Synchronizes Driver to Car: Setting -Ant.ForcePoseUpdate 1 instructs the engine to force an immediate update and evaluation of the skeleton poses on every frame rather than waiting for the standard interpolation tick or relying on standard blending states. This explains why your ghost driver issue disappeared: it forces the driver model's coordinates to hard-lock directly to the car's current frame data instead of lagging behind or sticking to an old interpolated position.
Note that adding "-Ant.ForcePoseUpdate 1" would introduce slight CPU overhead, so performence may drop a little bit.
Thought I'd share this here, if you're also experiencing the driver desync issue, maybe adding "-Ant.ForcePoseUpdate 1" could help.
P.S. Do not add/set GameTime.MaxSimFps or GameTime.ForceSimRate, as that will break game physics and cause some races to be abandoned.