Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Floating Point Errors and Large Scale Worlds

Discussion in 'World Building' started by Phelan-Simpson, Apr 15, 2018.

  1. Phelan-Simpson

    Phelan-Simpson

    Joined:
    Jan 1, 2014
    Posts:
    31
    Hello,

    I am currently working with a team on a project involving a large scale world.

    I currently believe Unity supports anything up to 99,999.99 meters away from the origin point (1 Meter = 1 Unity unit). This size gives precision up to 1cm, if I am thinking of this correctly. Up to 9999.999 meters away from origin gives you 1 millimeter precision. I am looking for conformation that this is in fact how it works, and to be informed if I am missing something in the calculations.

    Thank you in advance,
     
    MFKJ likes this.
  2. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    I remember the following post, where an animated model has been placed at different positions and starts to jitter/whobble quite noticeable around 5000 units away from the world origin.
    https://forum.unity.com/threads/making-an-open-world-map-could-use-some-input.484643/#post-3164102

    The forum contains tons of large world related posts and floating point accuracy as well as origin shifting comes up every time and then as well.

    I believe, the ultimate conclusion is:
    As of April 2018, there are other game engines that would be a better match for creating large worlds.
     
    Neiist, t2g4, BATTLEKOT and 4 others like this.
  3. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,896
    Agreed. Basically operating just beyond 5km mark will produce issues, depending on what you do. Knowing this limitation you put in place some world shifting when the action moves beyond certain threshold.

    I wonder if Unity has plans for 64 bit engine.
     
    MehO likes this.
  4. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    That does not mean what you think it means.

    64bit precision transforms is what you mean.

    The engine itself already supports 64bit architectures and did so for a long time.
     
    NIOS and Walter_Hulsebos like this.
  5. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,896
    Sure, that’s what I meant.
     
  6. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,896
    There’s a video of Starship Citizen that illustrate what you can get with 64bit math. I’ll post it here if I find it.
     
  7. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,896

     
    Last edited: Apr 15, 2018
    Westland, sj631, FlightOfOne and 2 others like this.
  8. buFFalo94

    buFFalo94

    Joined:
    Sep 14, 2015
    Posts:
    273
  9. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,896
    Yeah, it depends on the operation as well. For instance make a sphere of scale 5000 and move the camera near the surface and do a raycast on the mouse position. The hitPosition won’t be very accurate or if you do a Transform.TransformPoint it will just suffer or augment the precision issue.

    The 32 bit limitation makes you look for creative options which can work but well, make the system more complex to develop, maintain and prone to side effects in a large scale environment

    I wonder what prevents Unity to add support for 64 bit fields in Mesh, Transform and Vector structures - is it an underline platform compatibility issue?
     
    Last edited: Apr 15, 2018
    rakkarage likes this.
  10. buFFalo94

    buFFalo94

    Joined:
    Sep 14, 2015
    Posts:
    273
    Probably platform compatibility as you say. Since Unity support too many platforms I think it's hard for them to make such huge change I honestly think this will happen but we just need wait. Just look at how Unity evolved from 5.6 to 2018.1 that's a huge step they added some good features. And there's always solution like world origin shift if I don't mistaken UE4 use the same work around but it's built-in I guess.
     
    rakkarage likes this.
  11. Phelan-Simpson

    Phelan-Simpson

    Joined:
    Jan 1, 2014
    Posts:
    31
    I replicated the test, I whipped up a animation and a character mesh with decently high vertex count. The mesh is around 1.5 meters in height. I tested the mesh at 100, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, then 50000 and then 100000 units (Meters in this case).

    For close up shots on animated meshes there is visible vertex jitters at around 2000-3000 units. However, the jitters would be unnoticeable in medium and long range shot all the way to 10,000 units. Close range shots would be around 3000 units. Extreme close range shots would be around 1000 units.

    Although Star Citizen does have some very impressive tech, a similar multiplayer implementation has been around since, early 2000's when Guild Wars was in production.
     
    foobee likes this.
  12. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    From the top of my head...

    64 bit floating point operations are maybe not hardware-supported by all platforms they target, so it would get software emulated and this is slow.

    The "double" type consumes twice as much memory as "float". So every Vector3 would increase from 3*4=12 to 3*8=24 bytes. Which would render every existing Unity data format that currently contains these types, e.g. asset bundles, saved games, etc... incompatible.

    Larger data types causes more band-width usage as well. With all the cache-line optimization talks going on here lately, using larger data types is probably also counter-productive in this regard.
     
    Last edited: Apr 16, 2018
    chadfranklin47 likes this.
  13. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,896
    Yep, I can understand the trade off in performance though for some applications we’re already abusing of double data types. And it’s no fun to ping pong to float every time you need to translate the data to graphic entities.

    My question was more about the cost of adding native double precision as an option in the engine - I guess any change at so low level components will quickly trigger lot of dependency issues.

    A zero shifting builtin solution can help some scenarios but it’s kind of hack that works for some, but not ideal when you really need that precision in your data.
     
    AndreiMarian likes this.
  14. buFFalo94

    buFFalo94

    Joined:
    Sep 14, 2015
    Posts:
    273
    I really think a well implemented zero shifting can work perfectly since many open world uses UE4 which use that's hack
     
  15. Kronnect

    Kronnect

    Joined:
    Nov 16, 2014
    Posts:
    2,896
    Agreed, better than no support at all.
     
  16. sanjaykseriouslabs

    sanjaykseriouslabs

    Joined:
    Dec 4, 2017
    Posts:
    4
    Hello Guys,

    I am an Environment modeler, and I had a discussion with my level designer. He said that " I need to make stuff in clean number. For Example, If I am making a cube, it has to be in 1M in Height and Width. So he can use Grid snap" So the snap value will be 1M inside of unity because in unity 1 Unit = 1M.

    Which I understand. And I am fine with it. But he refuses to use vertex snap, I asked him why and he said: "Vertex snap give a value of 1.9899(just example -not exact number) which is bad for the game engine in terms of programming issues and it is also a bad level design to have unclean numbers".

    Unity created Vertex Snapping for a reason, to snap. It is just another snapping option to me. I see that there going to be an issue in a huge open world. But what we are doing here is a closed indoor environment.

    #Does this affect level design in any way?

    #Using Vertex snapping is a bad practice as he says??

    #If assets don't align using grid snapping, is it really bad to use vertex snapping??

    #So even if a real-world asset is 1.78 meter, should I have to round to 1.5M or 2M just to satisfy the need of Grid snapping?

    Please throw some light here. I am really tired of this argument with people around me about this whole conversation. IF there a best practices guide, that will be helpful.

    I also do understand the importance of Grid snapping when I do modular asset pieces or tilling assets. I make them in the increments of 1M grid's. But other than that I really need a clarification on this.

    Thank you.
    SK
     
  17. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Your designer should have been able to provide a better explanation. There are a lot of possible reasons why uniform sizing would be good. But absent any of those, it doesn't really matter.

    It's only bad for programming if you actually have a case where you have to deal with it in code. If that doesn't exist, then the argument is a red herring.
     
  18. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Ignacii likes this.
  19. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
  20. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,965
    To my knowledge double precision is supported by every major platform (at the very least that's all three desktop platforms as well as the consoles). ARM has had hardware support since ARMv6 which means mobile devices as far back as the original iPhone.

    Performance is a completely different story. You'd have to translate from double precision to single precision before you sent the data to the graphics card as even the most recent graphics cards are 32 times slower with doubles than they are with singles. Processors are generally at least half as fast with doubles.
     
    Last edited: Apr 20, 2018
  21. chrisfoster3d

    chrisfoster3d

    Joined:
    Jun 30, 2015
    Posts:
    6
    I don't know if its been posted yet but here's what I use. Its a simplified version of a solution I found after hours of searching. I tested it with 5000+ simple objects with a handful of physics objects and it seems to do the trick. Can't promise it will work for everyone, but its worth a shot. Slap it on your camera and set the threshold to the max distance you want.

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

    [RequireComponent(typeof(Camera))]
    public class FloatingOrigin : MonoBehaviour {

    public float threshold = 5000.0f;

    void LateUpdate () {
    Vector3 cameraPos = gameObject.transform.position;
    cameraPos.y = 0f;
    if (cameraPos.magnitude > threshold) {
    foreach (GameObject go in SceneManager.GetActiveScene().GetRootGameObjects()) {
    go.transform.position -= cameraPos;
    }
    }
    }
    }
     
  22. buFFalo94

    buFFalo94

    Joined:
    Sep 14, 2015
    Posts:
    273
    First of all thanks for sharing!
    1. About your scene setup : is there any static collider in the scene?
    2. Is Static batching work with this setup?
    3. Can you do benchmarks and post result here?
     
  23. Marcos-Elias

    Marcos-Elias

    Joined:
    Nov 1, 2014
    Posts:
    159
    Floating origin in Unity may work:

    http://wiki.unity3d.com/index.php/Floating_Origin

    But it is not well integrated with physics and other stuff. They should implement a native origin shifter (like Unreal does) to better support open world maps. Unfortunately Unity does not care about this so requested feature...

    After 4 years trying to make a driving Simulator in Unity I am almost giving up and going to Unreal just because of this problem. A native, physics integrated origin shifter. Same 32-bit float but with a native solution to move everything without interruption.

    Floating origin on Update (Late or Fixed) may work for simpler games but it will cause issues if you have lots of colliders or moving objects with physics (like cars in my project). The time to move everything may become many milliseconds, giving a temporary stop for the player, so bad for the overall experience... Also you may not use anything that depends on static flag. Navmesh does not work (even dynamic Navmesh, at least a few months ago when I tried). Lots of drawbacks.

    Also creating a system to handle scene loading is not that easy, Unity gives us a function (Load Level Async) but each game must implement its own solution. I managed to do that, but got stuck with floating origin limitations (user interruption to move everything in a single frame).
     
    Last edited: Sep 2, 2018
  24. RoCk3T_L

    RoCk3T_L

    Joined:
    Jan 12, 2018
    Posts:
    2
    Well, if it's just a game about cars or planes, you can easily fix that problem by duplicating the moving object. Then, you can put the duplicated one to the world origin, lock position x,y,z, copy the rotation x,y,z, and any inputs/gauges/reflection values from the original one. Finally, you can set the camera's culling mask and clear flag in the duplicated one to make sure it only renders the interior/ the moving object itself. And of course, set the camera in the original one exactly the opposite.

    By doing this, as long as you don't have too many other tiny moving objects in your game, the mesh shaking or twisting problem won't be identical.
     
  25. ristophonics

    ristophonics

    Joined:
    May 23, 2014
    Posts:
    32
    It works but its not cheap. It basically necessitates 'work-arounds' at all levels. For example: Projectiles that are raycasting for 'hit' must incorporate something to stay accurate after the floating origin move.

    Code (CSharp):
    1.     void FixedUpdate()
    2.     {
    3.  
    4.         RaycastHit hitInfo;
    5.         thisPos = transform.position;
    6.         stepDirection = m_rb.velocity.normalized;
    7.         stepSize = (thisPos - previousPos).magnitude;
    8.         if (stepSize > 0.1f)
    9.         {
    10.             if (stepSize > 500f) // to deal with floating point translations 500 is my current threshhold
    11.             {
    12.                 previousPos = ((Time.deltaTime * m_rb.velocity.magnitude) * -stepDirection) - thisPos;
    13.             }
    14.  
    15.             if (Physics.Raycast(previousPos, stepDirection, out hitInfo, stepSize, layerMask))
    16.             {
    17.                 Destruct(hitInfo.point, hitInfo.normal, hitInfo.transform.gameObject);
    18.             }
    19.             else
    20.             {
    21.                 previousPos = thisPos;
    22.             }
    23.         }
    24.     }
    Also the example in the link is a very heavy implementation (albeit works out of the box) in its use of Find.ObjectsOfType. I have found that it is better to attach a script to the parent gameobject needing to be moved that declares itself as needing to be moved.. Such as

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. public class OriginTransform : MonoBehaviour {
    5.  
    6.  
    7.     public static List<OriginTransform> OriginTransforms;
    8.     public Transform _ParentTransform;
    9.     public bool hasParticles = false;
    10.     public bool hasLineRender = false;
    11.     private bool onList = false;
    12.  
    13.     public ParticleSystem[] particles;
    14.     public LineRenderer[] lineRenderers;
    15.  
    16.     private void Awake()
    17.     {
    18.         _ParentTransform = transform;
    19.         if (hasParticles)
    20.         {
    21.             particles = gameObject.GetComponentsInChildren<ParticleSystem>();
    22.         }
    23.  
    24.         if (hasLineRender)
    25.         {
    26.             lineRenderers = gameObject.GetComponentsInChildren<LineRenderer>();
    27.         }
    28.     }
    29.  
    30.     private void OnEnable()
    31.     {
    32.         if (OriginTransforms == null)
    33.         {
    34.             OriginTransforms = new List<OriginTransform>();
    35.         }
    36.         if (!onList)
    37.         {
    38.             OriginTransforms.Add(this);
    39.             onList = true;
    40.         }
    41.     }
    42.  
    43.     //private void OnDisable()
    44.     //{
    45.     //  //OriginTransforms.Remove(this);
    46.     //}
    47. }
    Then you have an origin controller script do the actual moving without searching for which gameobjects to move in the first place. I have also added the hasParticles and hasLineRenders bools and arrays so the origin controller does not have to search for these children either. It just gets the list and move everything it needs to and nothing more.

    Code (CSharp):
    1.     private void MoveToOrigin()
    2.     {
    3.         int count = OriginTransform.OriginTransforms.Count;
    4.         //Transform[] tList = new Transform[count];
    5.         //ListCount = count;
    6.         //Debug.Log("COUNTIS" + count.ToString());
    7.         for (int i = 0; i < count; i++)
    8.         {
    9.             //Transform t = activeTransforms[i];
    10.             Transform t = OriginTransform.OriginTransforms[i]._ParentTransform;
    11.  
    12.             if (!t.gameObject.activeInHierarchy)
    13.             {
    14.                 //Debug.Log("DID NOT MOVE INACTIVE" + t.gameObject.name.ToString());
    15.                 continue;
    16.             }
    17.  
    18.             //Debug.Log("MOVING TRANSFORM" + t.gameObject.name.ToString());
    19.  
    20.             t.position -= controllerPos.transform.position;
    21.  
    22.             if (OriginTransform.OriginTransforms[i].hasLineRender)
    23.             {
    24.                 //LineRenderer[] linerenderers = t.gameObject.GetComponentsInChildren<LineRenderer>();
    25.                 foreach (LineRenderer item in OriginTransform.OriginTransforms[i].lineRenderers)
    26.                 {
    27.                     Vector3[] points = new Vector3[item.positionCount];
    28.                     for (int l = 0; l < points.Length; l++)
    29.                     {
    30.                         points[l] -= controllerPos.transform.position;
    31.                     }
    32.                     item.SetPositions(points);
    33.                 }
    34.             }
    35.  
    36.             if (OriginTransform.OriginTransforms[i].hasParticles)
    37.             {
    38.                 //ParticleSystem[] systems = t.gameObject.GetComponentsInChildren<ParticleSystem>();
    39.                 foreach (ParticleSystem item in OriginTransform.OriginTransforms[i].particles)
    40.                 {
    41.                     MoveParticles(item);
    42.                 }
    43.             }
    44.         }
    45.  
    46.     }
    One thing it took me a while to figure out and I can WARN everyone against, if they dont know already is this: Moving many Colliders with the floating origin will cause a huge hit to performance.
    We cant use static occlusion either.

    Have a prototype space dogfighter that uses this if anyone is interested.
     
    Omti1990, iceandstorm, Rond and 2 others like this.
  26. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,247
    In HDRP there is a great feature called Camera Relative Rendering to translate all rendering aspects into the camera position instead of the world origin which gives much higher precision rendering in large worlds, but you still have to deal with physics origin shifting... however in Unity 2018.3 you can also shift physics origin in settings: https://docs.unity3d.com/Manual/class-PhysicsManager.html and in code: https://docs.unity3d.com/ScriptReference/Physics.RebuildBroadphaseRegions.html

    P.S. 1 unit = 1 meter: https://forum.unity.com/threads/wil...new-quality-in-rendering.512495/#post-3357172
     
  27. ristophonics

    ristophonics

    Joined:
    May 23, 2014
    Posts:
    32
    Good stuff but I still have a lot of concerns. Camera relative Rendering appears to be exactly a floating origin solution but it is unclear exactly whats going on in the background. It also might necessitate using HDRP which may be hard for many people on 5.6 etc

    Also the Physics.RebuildBroadphaseRegions has a limitation:
    "In this mode, the boundaries of the world have to be set and then the physics engine would subdivide the volume into a flat grid in the XZ plane, with each cell containing a set of objects that belong to the cell."

    The limitation to the XZ plane is problematical for a spherical worlds unless you are using a procedural generated flat ground that would be contained by the XZ plane. Second is the limitation of only 256 cells or 16 sub-divisions. This is essentially a limitation on the resolution of the space and not at all spherical. Not sure how this would effect a workflow but maybe it would be for the better? Anyone used this?

    There is also an inherent issue with Note that the physics objects located outside of the world boundaries will not detect collisions at all. This might mean that a physics based object, like a projectile, will not detect collision in an adjacent 'outside' subdivided cell, even if the player is closer to that cell's boundary then the center of the cell in which they currently are operating. Combined these potential limitations would seem to create just as many issues as the original problem.

    The Physics Manager is great however for issues like large orbits with huge velocity changes the solution has been to go on 'rails', like in Kerbal, where physics computation is replaced by an algorithm using doubles instead of floats to keep track of position and velocity.

    All that said I love the idea of Unity building these functions in but are they going to make sense and work well with one another?
     
  28. savagecodes

    savagecodes

    Joined:
    Jun 5, 2017
    Posts:
    18
    To solve this exact problem, in Airburner i made a tool to divide my terrain into smaller chunks, and store it in a custom database made with Scriptable Objects.

    In runtime, my tool will only load the chuncks closer to the player and when the player move to another chunk, the tool moves that chunk to the origin.

    https://forum.unity.com/threads/wip-airburner-air-combat-game.523751/

    But also i had to make a tool to load the terrain in the editor by sections, and make a proxy system for the transform.

     
    wolfblack111 likes this.
  29. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,967

    Actually if you combine it with chunk loading (which is a necessity in any floating origin solution anyway) then it will not be too heavy at all. Ideally your world is cut into chunks that are authored with your games specific performance requirements in mind. So as long as you set your chunks up right, you will never be moving too many things to give you a hiccup.

    That way the floating origin is really just telling your chunk loading grid where abouts you are, and the chunk loader is handling all the loading and unloading and moving, which wont be heavy at all as really your just moving the one active (maybe 2-3 if your by a boundary) chunks to origin.
     
  30. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,247
    Did anyone try the new Physics Origin shift in 2018.3 along with the camera relative rendering in HDRP? I mean does it really solve the floating point errors for transform calculations and physics?
     
  31. GorkaChampion

    GorkaChampion

    Joined:
    Feb 6, 2018
    Posts:
    103
    I tried some in 2018.3 HDRP and my feedback was:
    - Shadows now perform good at up to 10.000m far from the origin, so shadows flickering is (almost) gone. No need to increase the low clipping pane on the camera.
    - Floating point errors keep the same as I didn't notice anything better (objects keep flickering and so..)
     
    TerraUnity likes this.
  32. Kriszo91

    Kriszo91

    Joined:
    Mar 26, 2015
    Posts:
    181
    Hello!

    Is there any way to change the origion to around the player? so if i travel 5000-10000 or more set the origion point to these cordinates?
     
  33. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    3,967
    Did you google? http://wiki.unity3d.com/index.php/Floating_Origin

    That is the main script people use as a base, but bare in mind it is very heavy and can be optimized better
     
    looki666 likes this.
  34. PearShape

    PearShape

    Joined:
    Apr 5, 2019
    Posts:
    2
    Unity does not support double data types for world coordinates only floating point, that would fix it right off the bat, I do believe Space Engine has a way around this.

    I made the Sun and the Earth actual size and distances and those pesky precision errors popped up continuously whilst in runtime.
     
  35. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,910
    It's a nonsensical argument since about 2004. Before then, we would use BSP to build levels and it would have light baking errors if things were off-grid, but now we use regular meshes for everything, so it's irrelevant. Building to a grid is still a good idea to avoid small gaps between objects, but there are no performance concerns unless it affects occlusion culling. After using vertex snapping, you can always type in rounded value, or make a script that corrects it.

    On the topic, here's the most no frills floating point origin script I use.
     
  36. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    Phelan-Simpson, Have you tried to apply the floating origin shift to the whole scene using a parent root node?
    It keeps all objects in the same spatial relationship so that there is no need for making special-case code to handle raycasting, physics, etc: it all occurs normally. And you don't move colliders separately either.
     
  37. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    A simple example is demonstrated here:

    for which I used the code below. I explain the resoning behind this in https://www.researchgate.net/public...ng_Cracks_in_Cyberspace_towards_best_practice and also compare with the type of implementation you are using: threshold-based periodic shift floating origin. The paper should be a fairly easy read.

    Code (CSharp):
    1.  
    2. /*
    3. * Performs simple Floating Origin player movement by reverse transforming the scene
    4. * Floating origin movement only happens if there is
    5. * a change in navigation input and it is above a minimum threshold.
    6. *
    7. * Assumptions:
    8. * Player object has camera attached, player object is position at the origin and
    9. * player object is tagged "playerCapsule".
    10. * This script is attached to the scene root parent object.
    11. */
    12. public class PlayerMove : MonoBehaviour
    13. {
    14.  
    15.     // Minimum player viewpoint collision detection distance
    16.     private const float COLLISION_DISTANCE = 2f;
    17.     // Multiplier for when bouncing back from collisions
    18.     private const float COLLISION_ADJUST = 1.2f;
    19.     // Threshold for detecting navigation changes
    20.     private const float NAV_THRESHOLD = 0.0001f;
    21.     // Distance for detecting collisions
    22.     private const float RAYCAST_DISTANCE = 10f;
    23.  
    24.     // Multiplier to each movement input
    25.     private readonly float speed = 7f;
    26.     private GameObject player;
    27.     // Layer mask for ray casting
    28.     private int layerMask;
    29.     // Horizontal movement deltas
    30.     private float deltaX;
    31.     private float deltaZ;
    32.     // Current reverse transform
    33.     private Vector3 reverseMovement;  
    34.     // Rotated reverse transform
    35.     private Vector3 rotated_transform = new Vector3(0,0,0);
    36.     private readonly Vector3 player_position = new Vector3(0, 0, 0);
    37.     private RaycastHit rayCollision;
    38.  
    39.     void Start()
    40.     {
    41.         //initialise once only
    42.         reverseMovement = new Vector3(deltaX, 0, deltaZ);
    43.  
    44.         // Use Physics.Raycast to cast a ray forward into scene to check for collisions
    45.         // create a bit mask for 7 layers with 0 for player layer to use in Raycast
    46.         layerMask = 1 << 8;
    47.         layerMask = ~layerMask;
    48.  
    49.         // turn off cursor display in game window
    50.         Cursor.visible = false;
    51.  
    52.         // Get access to the player object
    53.         player = GameObject.FindGameObjectWithTag("playerCapsule");
    54.     }
    55.  
    56.     // update is called once per frame
    57.     void Update()
    58.     {
    59.         // Get the horizontal movement changes from keyboard and
    60.         // negate them so we can move scene in reverse
    61.         deltaX = -Input.GetAxis("Horizontal");
    62.         deltaZ = -Input.GetAxis("Vertical");
    63.  
    64.         // Only process floating origin movement if there is navigation input
    65.         // change and it is above threshold.
    66.         if ((Mathf.Abs(deltaX) + Mathf.Abs(deltaZ)) > NAV_THRESHOLD)
    67.         {
    68.             // scene reverse transform for floating origin navigation
    69.             reverseMovement = new Vector3(deltaX, 0, deltaZ);
    70.  
    71.             // make movement delta proportional to time since last move and speed factor
    72.             reverseMovement = reverseMovement * Time.deltaTime * speed;
    73.  
    74.             // if player collided with close object then ...
    75.             if (Physics.Raycast(player_position, player.transform.TransformDirection(Vector3.forward), out rayCollision, COLLISION_DISTANCE, layerMask)
    76.                 && (rayCollision.distance < COLLISION_DISTANCE))
    77.             {
    78.                 /// ... bounce back a little from collision
    79.                 transform.Translate(-rotated_transform*COLLISION_ADJUST);
    80.             }
    81.             else // no collision, so move scene in reverse
    82.             {
    83.                 // use player camera rotation to modify reverse movement vector so that player forward corresponds to forward movement input
    84.                 rotated_transform = Quaternion.Euler(player.transform.localEulerAngles) * reverseMovement;
    85.  
    86.                 // Move the scene to the new position by changing scene parent object transform -
    87.                 //   this script is attached to the scene root parent object
    88.                 transform.Translate(rotated_transform);
    89.             }
    90.         }
    91.     }
    92. }
    93.  
     
    Last edited: Aug 30, 2019
    Art-Leaping and Omti1990 like this.
  38. razzraziel

    razzraziel

    Joined:
    Sep 13, 2018
    Posts:
    395
    putting everything on one parent? no, thank you.
     
  39. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    It all goes through the transform hierarchy you already have set up and ends up going through the same view and perspective transformation matrix per frame. Adding a single transform above your existing hierarchy makes no measurable difference in performance. Having multiple extra loops and code for handling colliders, physics, and moving thousands of objects leads to glitches each time the threshold is reached and unnecessarily complex code. The player capsule and some other things (direction light) do not, of course, go under the root node.
     
  40. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    This is the hierarchy for the example above:
    Screen 2019-08-30 08_42_06-60pc.jpg
     
  41. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    I mean no disrespect but that is a misleading statement because all rendering is camera relative by definition, including rendering that jitters. You can only get higher accuracy, less jitter, by translating objects closer to the origin where the coordinate resolution is higher. The description for HDRP rendering should be clarified so it is not so misleading. BTW: translation changes resolution, not precision: precision remains unchanged at float/double unless you explicitly change some float variables and operations from float to double.
     
    Last edited: Aug 30, 2019
  42. TerraUnity

    TerraUnity

    Joined:
    Aug 3, 2012
    Posts:
    1,247
    @cosmochristo Did you ever read my reply to the end? I was definitely talking abt rendering as an example for such implementation and mentioned you still need origin shifting for more accurate physics.

    And what made you think your script is better? The code in the Wiki does have a checking if translating object is a parent in this line:

    Code (CSharp):
    1. if (t.parent == null)
    2. ...
    Also we have an extended version of Floating Origin Shifting in our streaming system in TerraLand for years which re-positions a lot of gameobjects unnoticeably. What we are looking for here is a more robust and accurate precision through a rather built-in system in engine such as the Camera Relative Rendering in HDRP I mentioned.
     
    Recon03 likes this.
  43. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    I am replying to one question at a time, for clarity.

    The advantages of CFO are:
    1. Closing the last mile to zero yields orders of magnitude greater base accuracy than POS, before error propagation and magnification by calculations.

    2. CFO can be supported by the vendor of any scenegraph based system by using the scene root transform method and a double to single precision floating origin subtraction method to preserve accuracy when positioning/instancing objects. It can also be supported by vendors of non-scenegraph systems by providing a floating origin subtraction method that executes before the perspective and viewing transformation.

    3. It is optimal.

    4. Implementation is easy and yields immediate results.

    5. It adheres to the Keep It Simple but Sufficient principle. The algorithm is as simple as it gets but does the heavy lifting effectively.

    6. It performs at least as well as POS, and better in some cases, based on empirical testing to date. Caveat: I am investigating a case where CFO may be slower, see below.
    Notes:
    In my tests I have not been able to prove any advantages of POS over CFO but that does not mean there aren't any where CFO performs slower, or has some other disadvantage, and I am corresponding with one colleague on a possible use case in this regard. Empirical testing and analysis is required before any conclusions can be drawn.

    There have been anecdotal references to developers choosing POS because of a perception that it performs better. I have found no quantitative or qualitative results supporting this perception but have published results contradicting it. Evidence points to the perception stemming from the misconception that CFO must be implemented by explicitly moving all objects a common source of this misconception is a 2010 implementation that was widely copied and repurposed.

    With respect to point 1: a significant consideration is that, as the distance from the origin is reduced, the resolution within a fixed span of space increases in exponential proportion. This point should be of interest to scientists and engineers working with equations highly sensitive to error because the CFO method will optimally minimise error from positional jitter.

    There are three disadvantages of the periodic method, it:
    • is less accurate,

    • exhibits occasional glitches - discontinuities in the frame rate,

    • has greater complexity.
    The Keep It Simple but Sufficient principle (my version of the Keep it Simple, Stupid!) is an important design principle to me and algorithms that satisfy it are always my preference.

    Request:
    My survey on these and related algorithms is ongoing and I would appreciate any input from those who are using a floating origin (or origin-centric) method. Reproducible empirical tests are best but also code or pseudo code algorithms are worthwhile.
     
  44. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    If you are saying this test means that objects are not shifted unnecessarily, then yes, I agree.

    I am not sure what you mean by "origin shifting": is it POS, CFO, or something else? I could not find a reference to origin shifting in those links. Update: are you referring to World Bounds field?

    I would like to know more about how this works and get some performance and accuracy testing done.
     
    Last edited: Sep 1, 2019
  45. razzraziel

    razzraziel

    Joined:
    Sep 13, 2018
    Posts:
    395
    measurable difference in performance? in that scene? thats no close to a real world project. put there 10k objects with most of them different prefabs, materials, textures & colliders and measure then.

    unity checks every hiearchy tree if its dirty in that frame. if something is dirty, then it checks all children transforms(which is a lot of work). if a parent is not dirty, it bypasses in terms of optimisation. so if you put 10k objects in same parent, unity checks every one of transforms every frame = no optimisation. if you move a single primitive in that kind of scene, it will check all 10k objects.
     
  46. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    Correct, it is not meant to model a real-world project example. That example was not a demo of performance on large data set, really just showing the CFO method working. I did not close down other apps and run it offline.

    In the performance tests for the paper: https://www.researchgate.net/public...ng_Cracks_in_Cyberspace_towards_best_practice
    I actually used 10k objects. I measured differences in execution performance, and was careful to isolate it from rendering and physics load. Tests were on a core i5 laptop. I was quite surprised how well Unity handled them.

    update: BTW it is not every frame but only when user does some translation input change.

    This is interesting. I will add this to the cons against CFO, via a single root transform, once I can verify. The transform response to navigation changes (i.e. not every frame) still has to be applied to all vertices at some point.
    So are you saying that if I modify the root transform then it causes an additional processing hit on all 10k object transforms underneath it (and not just the root)? I will need to do a separate test to measure this. Or are you talking about a form of optimisation where the transforms are set up in a structure and each frame, only top level trans are checked, then it descends down dirty trees and only updates the transforms (within this structure) if they have changed.
    As all the transform hierarchy must be composed for each object each frame (to correctly position) anyway, perhaps you are saying there is some pre-composition (combining multiple transforms into one), which makes sense.
    Is there a detailed explanation of this you can refer me to?
     
    Last edited: Sep 1, 2019
  47. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
  48. razzraziel

    razzraziel

    Joined:
    Sep 13, 2018
    Posts:
    395
    chadfranklin47 likes this.
  49. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250
    I have reviewed the link from @Peter77, thank you. It seems this all depends on the transform.hasChanged event.
    @Peter77, @razzraziel, @TerraUnity: can you please review and correct/comment on my interpretation below (I have a question at the end):

    Continuous Floating Origin (CFO) navigation, when implemented with a CFO root transform node (parent for scene), does not cause any scene objects to move relative to other parts of the scene. Changing the CFO transform, therefore, should not cause a transform.hasChanged event to propagate down the scene hierarchy.

    As Unity does not appear to have an explicit disable flag for transform changed event propagation, the developer should at least:
    1. Not register any BroadcastMessage, SendMessage methods against the CFO root node.

    2. Not have any childtren with “if (transform.hasChanged)” referencing the CFO root node.
    If objects/scripts have not subscribed to the CFO root transform.hasChanged will Unity not “send” the transform.hasChanged messages – as there are no registered receivers?
     
    Delforce likes this.
  50. cosmochristo

    cosmochristo

    Joined:
    Sep 24, 2018
    Posts:
    250