Search Unity

Floating Origin (Position and Velocity) - Rotation problem when zeroing out velocity while low fps

Discussion in 'Physics' started by kzaurckichz, Nov 29, 2014.

  1. kzaurckichz

    kzaurckichz

    Joined:
    Nov 5, 2013
    Posts:
    52
    I am building a space simulator.
    I have made a FloatingOrigin script based on the one from the wiki, but I added a velocity reset too.

    Basically, I have a scene with two container objects at the root : Userspace and Universe.
    The Spaceship and the FirstPersonController are both direct children of the Userspace.
    The Universe contains all the other objects (planets, other spaceships, etc).

    * Userspace
    ---- FirstPersonController
    ---- Spaceship
    * Universe
    ---- Planet
    ---- Sun
    ---- SpaceStation

    When controlling the spaceship, the FirstPersonController's RigidBody is Kinematic and has a script to follow the spaceship :
    Code (CSharp):
    1. void LateUpdate() {
    2.   character.transform.position = spaceship.transform.position;
    3. }
    To make the spaceship accelerate, I check for WASD inputs in FixedUpdate() on a script attached to the spaceship.
    Exemple for forward :
    Code (CSharp):
    1. if (Input.GetKey (KeyCode.W)) {
    2.     rigidbody.AddRelativeForce(0, 0, 10000f);
    3. }
    Here everything works as expected, except for a shaking effect due to floating point precision.
    To fix that I have made a FloatingOrigin system which resets the spaceship to the origin and moves the Universe, both position and velocity.

    My FloatingOrigin script (shortened) :
    Code (CSharp):
    1. public float maxDistanceFromOrigin = 1000f;
    2. public float maxVelocity = 1000f;
    3.  
    4. public GameObject universe;
    5. public GameObject spaceship;
    6.  
    7. void LateUpdate() {
    8.     if (spaceship.rigidbody.velocity.sqrMagnitude > maxVelocity) {
    9.         universe.rigidbody.velocity -= spaceship.rigidbody.velocity;
    10.         spaceship.rigidbody.velocity = Vector3.zero;
    11.     }
    12.     if (spaceship.transform.position.magnitude > maxDistanceFromOrigin) {
    13.         universe.transform.position -= spaceship.transform.position;
    14.         spaceship.transform.position = Vector3.zero;
    15.     }
    16. }
    Now, the actual problem...
    When accelerating very fast and very far, and the FloatingOrigin script already reset the position/velocity a few times, at some point, with the forward key input pressed, the spaceship starts rotating on it's X axis for no reason.
    When trying to accelerate sideways, it actually rotates on it's Y axis.
    It seams to be happening on a very random base, but mainly (or maybe only) when the FPS drops much lower than 20 FPS, which is about half my Fixed Timestep of 0.02 I've set in the project settings.

    It seams to be caused by the velocity reset of the spaceship, doesn't matter if the position is also being reset or not.

    When I disable this FloatingOrigin script, everything works fine (except for that shaking effects of the floating point precision of course), it never rotates no matter how much I accelerate or how far I go from the origin.

    Anyone has a clue on this issue ? Is it a bug in Unity or in the way I'm using it ?
    Thanks for the help !


    Edit : FirstPersonController does not use the built-in scripts. It's homemade and it`s movement is disabled when attached to (controlling) the spaceship.
    Also, this FirstPersonController does not collide with the spaceship as it's position is forced in the middle of the spaceship (see script above), not touching the walls.

    The spaceship used for this test is simply 5 stretched cubes surrounding the FirstPersonController.
    spaceship.png
     
    Last edited: Aug 3, 2015
  2. RJ-MacReady

    RJ-MacReady

    Joined:
    Jun 14, 2013
    Posts:
    1,718
    Satellites in orbit will tumble around. There's no glitch or mistake, but I think an error in your spacecraft's design. You need some way of returning your rotation to the desired velocity, so stabilizers. When you're flying through space your ship may start to do just that same thing. If you want to do it cheaply, add angular drag.
     
  3. kzaurckichz

    kzaurckichz

    Joined:
    Nov 5, 2013
    Posts:
    52
    Thanks for your reply, but that was not the issue here.

    The rotation was NOT a simple angular imprecision that decays over time, but rather it was a sudden, quick and steady rotation, exacly like if I had manually set an angular velocity to a very big value, since it was rotating Very fast.

    Setting an angular drag simply makes the rotation to slow down after a while.. but when it starts to rotate it's instantaneous and happens suddenly.
    I guess I forgot to mention this small detail.

    I found out that calling the FloatingOrigin calculations on FixedUpdate instead of LateUpdate solved the problem (I think).
    Still not sure why...

    But anyways I'm still having issues with collision detection using 32bit floats... I'm going to use a Double precision physics system, if I find any, Or I would have to code it myself.
    Would you happen to know about a physics library in the asset store that supports 64bit floats ?
    Thanks
     
  4. RJ-MacReady

    RJ-MacReady

    Joined:
    Jun 14, 2013
    Posts:
    1,718
    No, and I'm still not sure what you're trying to do, either. I am trying to visualize the need for numbers larger than floats but I guess I don't see it.
     
  5. WagDan

    WagDan

    Joined:
    Nov 7, 2014
    Posts:
    37
  6. kzaurckichz

    kzaurckichz

    Joined:
    Nov 5, 2013
    Posts:
    52
    The problem has been solved for a while now, but thanks anyways.

    For others who experience the same problem, you simply need to put your ResetToOrigin script in the FixedUpdate instead of LateUpdate or Update like in the original script.

    The reason is simple :
    FixedUpdate is for everything physics related (both static objects movements and rigidbody stuff).
    Update and LateUpdate are for rendering.
    These two ARE NOT synchronized !

    When resetting a velocity in the rendering frame, two physics calculations can happen on the Same rigidbody WHILE resetting the velocity, especially while rendering FPS is low, thus the physics (FixedUpdate) FPS will be higher.
    Unity calculates every object using their Absolute positions, thus resetting a rigidbody's parent object's velocity will affect it's children's positions and rotations.
    This will cause "un-normalized" vectors on other physics parameters like torque, hence causing unexpected, sudden rotations, when the numbers are normalized by the physics engine.

    For my game I ended up creating my own server-side physics system in double-precision, and Unity simply receives positions of everything else in single precision relative to the camera.