Basically, for a racing game, I am setting a custom rotation each fixed update so that the car aligns with the ground. Obviously, setting a rigidbody’s rotation via rigidbody.rotation doesn’t allow it to interpolate, so I’m using MoveRotation() to do it.
Now, using rigidbody’s interpolation, the actual movement is silky smooth. And according to the docs, using MoveRotation should also smoothly interpolate between fixed updates.
However, this isn’t the result; instead, the car moves smoothly, but rotations look like they’re occurring at half the frame rate or in a very jerky fashion, suggesting interpolation isn’t working as intended. Is this a bug or am I doing something wrong?
(Oh, and inb4 “use addtorque,” that isn’t feasible here where I need precise control of the rotations)
The rigidbody should be kinematic for that scenario to work. Otherwise, both you and the physics are calculating different rotations, and the transform will be interpolated using the value calculated by the physics.
This is what’s happening right now:
FixedUpdate: you set a custom rotation.
Internal Physics Update: physics uses your custom rotation as current state, then calculates a new rotation out of it.
Visual Update cycle: the transform’s rotation is interpolated using the new rotation calculated by the physics, not yours.
Hence you have the jerky rotation.
Possible solutions:
Use a kinematic rigidbody and apply both position and rotation.
Set your rotation after the internal physics update and before the visual update. Currently, the only way to do this in a reliable way is is from the OnTriggerStay event, which is executed right after the internal physics update. It’s an ugly hack that requires you to have a large collider marked as trigger in your scene, so you could get the OnTriggerStay method triggered in your car’s rigidbody every fixed frame.
Continue as now, but interpolate the rotation yourself in the Update (LateUpdate?) method.
I could try that later when I get back to my PC, but due to wanting to use velocity for realistic acceleration, I generally stay away from kinematic stuff
EDIT: Kinematic also can’t collide so that’s out
2) as you said, ugly hack, so probably a big fat nope
3) This one I actually tried, but I just can’t get the interpolation factor right…
Just a side note: calling MovePosition in each FixedUpdate frame populates Rigidbody.velocity in a kinematic rigidbody correctly. Same with MoveRotation and angularVelocity.
I’ve been trying to get an angularVelocity update routine made to have it function like MoveRotation (give it a quaternion). I attempted a PID-like controller for quaternions, but either I can’t find the right values to give it or I’ve seriously misunderstood something here.
I can PID a Vector3 position by updating velocity with this algorithm, but for whatever reason I can’t seem to get it working with angularVelocity
When I have it try to keep something upright (Quaternion.identity) and move the x axis, it will spin for a moment and then twitch around the upright position as though it’s sorta working. Then, any sort of angular motion throws it into instability and it just spins out of control.
Just replying to say that I have a partial solution, and that is to split the mesh + particle systems into their own object, have colliders + rigidbody in another object, and interpolate the render object transform every update frame. (This also means disabling rigidbody interp completely)
It stutters a little sometimes, but it is a LOT better than before.
To benefit others, I will make a separate script that can be put on any object to do this
I’ve asked @yant (Unity Physics dev) and he pointed out another solution: set Physics.autoSimulation to false and write your own physics loop by calling Physics.Simulate yourself. There’s a handy sample code here:
So this seems the officially supported way of accessing the transforms right after being updated by the physics. The interpolation and everything else should work properly when modifying the rotation right after calling Physics.Simulate.
tfw you’re still using 5.4.3f1
Hence why I rolled my own interpolation.
For mine, the idea is to put all your visual objects like meshes, particle systems, etc. into their own object, put colliders and stuff into another object, then at runtime, detach the rendered object and fully control it via script.
An example of what I am roughly doing is this:
Obviously, for my case, I’ve gone and integrated this directly into my main vehicle script, rather than using a separate component.
Also, if you decide to use this (I’m putting this out for free, do whatever you want with it! :)) make sure to TURN OFF rigidbody interpolation as it is now handled by the script.
Yea, generally, I’d use Slerp, but I didn’t see any difference between it and lerp tbh.
That said, if you’re going to use that code, feel free to change it, I won’t stop you.
I had similar issues with jittering that I managed to resolve and wanted to share (hope it helps someone else).
I have a custom third person character controller that is physics based.
I use Cinemachine + ‘CinemachineInputProvider’ for controlling cameras.
When rotating camera, character is rotating towards the camera forward direction.
I use the new Input System.
Explanation of what you should be mindful of to eliminate jittering/stutter (if you have physics based controller):
You should read inputs in ‘Update()’
You should use ‘InputValueGain’ in Cinemachine camera aim section, to make Input framerate independent. CineMachine and Framerate
You should set appropiate values of acceleration and decceleration on Cinemachine camera aim section (it doesn’t fix jitter per se, but it makes overall feeling more smoothed)
You should apply movement by using ‘Rigidbody’ methods eg. ‘rigidbody.Move()’, ‘rigidbody.AddForce()’ and etc
You should NOT manipulate transform position directly, to move object
You should apply movement in ‘FixedUpdate()’
You should set ‘Interpolation’ mode on ‘Rigidbody’ to ‘Interpolate’
Because rotation of the player is depending on camera forward direction you need to apply player rotation AFTER camera has rotated. Camera is rotating on ‘Update’ calls, because of that you can not apply player rotation in
‘FixedUpdate()’ - ‘FixedUpdate()’ in Unity is called before ‘Update()’. So you need to create a delayed/late ‘FixedUpdate()’ and apply player rotation there (example provided below).
When rotating the player it is often that before the player fully rotates towards the camera forward direction, the camera will change to face a new direction.
In that case the player will start rotating to the newer forward direction of the camera (before the player finished his first rotation).
This could lead to some other type of jittering, that can be smoothed by using ‘SmoothDampAngle()’ or ‘SmoothDamp()’. Unity - Scripting API: Mathf.SmoothDampAngle Unity - Scripting API: Vector3.SmoothDamp
I previously just took a ready-made solution from the forums and used it in my projects. But now I am ready to leave my first comment to thank you for this solution!