(Case 949954) 2017.2b10 - Rigidbody interpolation "hiccups"

UPDATE 2: Issue status is back to “Active”! (previously was “Won’t fix”)

UPDATE: Issue has been successfully reproduced by Unity and has been sent to devs for resolution: Unity Issue Tracker - Rigidbody with Interpolate mode set to interpolate makes a small hiccups while rotating

In 2017.2 beta 10, kinematic rigidbody interpolation seems to have “hiccups” or “stutters” once in a while. To demonstrate this, I have created a simple scene (RotationTester.unity) where a camera orbits around a point at a given rotation speed, and a cube rotates on that point at the same rotation speed (making both the camera and the cube synchronized in their rotation). The stutters become very noticeable in this situation (especially in builds, which means perhaps this is framerate-related?).

Here are some additional notes:

  • This problem does not happen when running that exact same project in 2017.1
  • I haven’t tested with previous 2017.2 beta releases
  • This problem happens regardless of if Physics.autoSyncTransforms is turned on or off
  • The problem happens much less often with VSync on, but it still does happen.
  • Happens with non-kinematic rigidbodies too (by setting the angularVelocity)
  • Happens both in editor and in builds, but it’s much more frequent in builds
  • You can try setting the fixed timestep to a really high value (like 0.2) and you’ll really see that it’s as though the interpolated rotation “skipped” interpolation for a FixedUpdate once in a while.
  • I’ve tried Debug.Logging the deltaTime and the actual angles of the rotation I’m applying to the cube on every FixedUpdate, and I can confirm that they are always 100% constant even when a stutter occurs. I’ve also logged the Time.time of each FixedUpdate and there are no “gaps” where it seems like the update didn’t happen. This leads me to think that it’s really an interpolation problem

Look into the “RotationTester.cs” file for all the code that causes this:
Code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RotationTester : MonoBehaviour
{
    public float cameraDistance = 5f;
    [Range(0f, 1000f)]
    public float rotSpeed = 360f;

    public Transform cubeTransform;
    public Rigidbody cubeRigidbody;
    public Transform cameraTransform;

    private void FixedUpdate()
    {
        // Handle rotating the cube at rotSpeed
        Quaternion rotationThisFrame = GetRotationFromSpeed(Time.deltaTime);
        cubeRigidbody.MoveRotation(rotationThisFrame * cubeRigidbody.rotation);
    }

    private void Update()
    {
        // Handle rotating the camera around the cube's origin at rotSpeed
        Quaternion rotationThisFrame = GetRotationFromSpeed(Time.deltaTime);
        Vector3 finalCameraPosition = cubeTransform.position;
        Quaternion finalCameraRotation = cameraTransform.rotation;
        finalCameraRotation = rotationThisFrame * finalCameraRotation;
        finalCameraPosition = finalCameraPosition - (rotationThisFrame * cameraTransform.forward * cameraDistance);
        cameraTransform.position = finalCameraPosition;
        cameraTransform.rotation = finalCameraRotation;
    }

    private Quaternion GetRotationFromSpeed(float deltaTime)
    {
        float rotationSpeed = rotSpeed * Time.deltaTime;
        return Quaternion.Euler(Vector3.up * rotationSpeed);
    }
}

How to reproduce:

  • Open the project with 2017.2 beta 10
  • Make a Windows x64 build
  • Play the build and notice hiccups in the cube’s rotation relative to the camera
  • Open the project with 2017.1
  • Make a Windows x64 build
  • Notice the hiccups do not happen

3215612–246300–RotationTests.zip (19.4 KB)

4 Likes

Here’s an alternative version of the project that takes the camera’s rotation completely out of the equation and makes the problem very visible (it’s much more noticeable in a build than in this low-framerate gif). The camera doesn’t move, and the exaggeratedly high fixed timestep lets you clearly see that the cube stops once in a while

3215799–246308–RotationTests.zip (19.6 KB)

I have also seen similar types of problems when rotating kinematic rigidbodies. In my case I am rotating a rigidbody by 180 degrees. But it seems to rotate in a buggy way.

This doesn’t seem to happen on a mac for some reason.

@yant
I see the issue’s status has changed to “Won’t Fix”
…does this actually mean it won’t be fixed? Or is it just postponed for a patch?

2 Likes

I’d very much like to know that too, “Won’t Fix” really doesn’t sound right for this regression.

Yeah. For me personally, this bug pretty much means that Unity doesn’t support games that have character controllers in them anymore… which is arguably pretty serious.

I have submitted a kinematic rigidbody-based character controller package to the asset store recently, and at this point, its release will most likely coincide with 2017.2’s release. The problem is that even if this bug is fixed in a patch after the initial release, many people will download my asset for vanilla 2017.2 projects and then they’ll wonder why the movements are stuttering all over the place. I’ll have no choice but to put some kind of popup window in my asset that says “Please don’t use this with 2017.2; it’s broken”

Perhaps the bug is more serious than Unity QA realizes. In the example project I’ve submitted, it doesn’t happen THAT often. But I’ve tried moving an interpolated rigidbody around in a more complex scene ( like this for example, with several other interpolated rigidbody boxes lying around ) and the stuttering really happens all the time. It makes all movements look glitchy and jarring. I’m not upset about the fact that bugs like this happen in betas, but I’m a bit upset about the “Won’t Fix” situation (if it means what I think it means).

Anyway, I’ve emailed QA about this. Will post back here if there are any updates.


Additionally, I could be wrong, but I think this bug can actually be observed in one of the Unite presentations on Cinemachine (from 26:24 to 26:45). This is exactly how my character controller feels in 2017.2:

https://www.youtube.com/watch?v=eNFJXoMIFe4

Although it could be something else, too. But I hope it is understood that an engine cannot ship with this problem

6 Likes

I’m seeing a similar problem all the way back in 5.6. Was really hoping this would be fixed as its creates nasty issues in VR.

In this case, I’m pretty sure the issue was introduced in 2017.2 (as you can see on the issue tracker page; not reproduced in 5.6, 2017.1, or 2017.2 alpha)

Keep in mind there are many ways interpolation can break. The general guidelines are:

  • If your rigidbody is kinematic, do absolutely all movement through rigidbody.MovePosition / MoveRotation

  • If your rigidbody is not kinematic, do absolutely all movement through rigidbody.velocity / angularVelocity / AddForce / AddTorque

  • Doing any other sort of movement (such as moving transform.position, transform.rotation, rigidbody.position, using MoveRotation with a non-kinematic, etc…) will probably break interpolation

  • Make sure no parent objects are affected by transform.position, etc… either

  • Rigidbody constraints can break interpolation (edit: not true)

  • When working with kinematic bodies and MovePosition/Rotation, you must call those methods not more than once per FixedUpdate. (actually this shouldn’t affect interpolation, but it’ll result in somtehing you wouldn’t expect)

  • Just to be extra sure, don’t reparent stuff at runtime and don’t work with transform hierarchies of different moving objects. Keep everything as flat and simple as possible.

The most common culprit of interpolation-breakage when I look at other people’s character controllers is that they are moving with rigidbody.velocity and/or rigidbody.AddForce (which is fine for interpolation), but they’ll handle character rotations with transform.rotation or rigidbody.rotation. So every time the character has to change its orientation, interpolation is broken

4 Likes

Or rigidbody.velocity, that works fine too. Basically, do not touch the transform, the setter resets interpolation. Also, another very important thing, although it’s irrelevant to the point at hand, is if you are running any sort of movement control for an object, never use the position of the transform itself if interpolation is on for your feedback, it’s always “fun” to find and fix any such issues in a project…!

I was not aware of this one: “Rigidbody constraints can break interpolation” -this one is problematic. Is this being tracked as a bug or as expected behavior? Our interpolation is broke and we follow all of the above guidelines except for the fact that the rigidbodies rotation is constrained on two rotation axis.

Nevermind what I said about constraints. Just tested it and I couldn’t find any combination of constraints that broke interpolation (in 2017.2 at least). Maybe there was a bug at some point (I think I remember seeing constraint/interp problems in 5.6) but it’s fine now

I would suggest progressively rebuilding something that resembles your movement code until you find out what’s causing the problem. Start with a cube with X and Z constraints that moves and rotates with interpolation. Once you’ve got that, progressively add more stuff

This surprised me, so I did a quick test:

  • On a kinematic rigidbody, setting the velocity and angularVelocity does nothing at all
  • On a non-kinematic body, MovePosition/MoveRotation moves without any interpolation (in case that’s what you meant)

Oh, interesting, you are correct, it’s a difference between the 2D and 3D physics systems. I always drive 2D kinematic rigidbodies with velocities and it’s always worked, with the exception of a regression early in the 2017.2 beta cycle. I’m rather surprised that it does not with PhysX.

2017.3b1 - the problem is still there

2 Likes