Search Unity

precision: combining visibility to 30,000m, w/ fine details near camera

Discussion in 'Editor & General Support' started by Tony-Lovell, Jul 24, 2014.

  1. Tony-Lovell

    Tony-Lovell

    Joined:
    Jul 14, 2014
    Posts:
    127
    I am converting a first-person perspective naval simulation project to Unity. The game hinges on scenes in which distant ships might be as far as 20-30,000m away and yet geometry will have to be precisely positioned and represented within feet of the player on his own ship. In conventional terms, using 1 unit = 1 meter, the camera's near clipping plane would have to be at about 0.2, and the far clip plane about that 20,000 or 30,000 figure.

    This means I must keep the camera near the engine's origin to maintain good floating point precision for the near items, and I must either use a different camera to draw the distant ships than to draw the items on the player's own ship (so that different clip planes can be used) or I must carefully avoid fine geometry at a distance to avoid Z-fighting. I will leave the issue of two cameras for below and outline how I've previously dealt with precision in large coordinate spaces while asking for other ideas.

    During previous prototyping on another platform, I found that when my camera was far from the origin, geometry near the camera jittered terribly, wrestling with the granularity of a float, I guess, at the appreciable coordinates where the camera was.

    I overcame this by employing a bit of a "hack". I used the engine's nominal "world space" as a "scene space", and my app used a Vector3 to keep track of the "scene offset" -- where, in the world, the visible scene was centered. One each Update(), the root objects in the scene graph would be moved, together, to force the camera back to the origin, like so:

    Code (CSharp):
    1.  
    2. static Vector3 sceneOffset = new Vector3();
    3. void Update() {
    4.     Vector3 pos = camera.position;
    5.     sceneOffset += pos; // scene is now shifted forward
    6.  
    7.     // slide root objects backward in scene graph to place camera back at engine's geometric origin
    8.     for (GameObject obj : all_game_objects_with_no_parents)
    9.         obj.transform.position -= pos;
    10. }
    11.  
    Depending on the engine, this approach can cause problems with particles that are already emitted (which can get ugly), and some minor things like skyboxes and such have to be ignored (which is not very bad). The nice part of the approach is that you manipulate items in 3-space pretty much as the engine intends you to, and this ensures that any third party scripts would still work fine.

    Would this approach work in Unity? A limited test seemed to suggest my ship could be a RigidBody and handle Forces and yet still be something I can shove about by directly forcing its position in Update(). But will I be able to bump particles about in the manner I'd require? Are there other approaches I should consider?

    As to using two cameras to render a single scene into the same window, have others done this? I've not. I imagine it is done by having one camera with clip planes of near/far of about 10f, 25,000f draw vessels other than the one the player is on and have one of .1f/400f draw his own ship and its equipment.

    tone
     
    Last edited: Jul 24, 2014
  2. www_3dart_es

    www_3dart_es

    Joined:
    May 24, 2013
    Posts:
    219
    If I don´t remember bad, the "3D platformer tutorial" show this. I think that it isn´t now available, I will see if I can find it.

    Regards.
     
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Might be a bit offtopic, but:
    Code (csharp):
    1. for(GameObject obj : all_game_objects_with_no_parents)
    Is that pseudocode, or is it some bizarre for-loop syntax I've never seen before?
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Now, back on-topic: yes, this sort of thing is possible in Unity. Kerbal Space Program famously does this (to solve a bug known as "the Kraken" among the community, which prior to 0.17 or so would shake ships apart due to physics imprecision) with both position and velocity - anytime the camera is more than 6000m away from the origin it shifts everything to bring the camera back to the origin. (Which is better than doing it every frame by far, since that's a lot of objects to loop through - only do the loop when pos.magnitude > some_value.) And they do have some glitches with particles (when you get to 6km altitude during launch, you will catch the occasional "engine smoke" particle coming from in front of you). It's possible the particle glitches might be solved by switching off "simulate in worldspace" when you move the object (untested), or by looping through the particles and changing all their positions the same way.
     
  5. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    One other thing you should do is have two cameras. One faraway camera (near clip plane ~100m, far clip plane ~30000 m) to maximize the precision far away (to minimize Z-fighting out there); one nearby camera (far clip plane ~100m, near clip plane ~0.1m, and clear flags set to depth only or don't clear, and the "Depth" higher than the other camera so it renders on top). You can use layers to make things more efficient, too; make the faraway camera not render layers of things that wouldn't be visible at that distance, etc.
     
  6. Tony-Lovell

    Tony-Lovell

    Joined:
    Jul 14, 2014
    Posts:
    127
    StarManta, thanks -- I actually had done the re-centering exactly as you mention, by waiting for a displacement from origin to grow "too large" before doing it. On my last platform (JME3), I had to rewrite some of the engine to allow me to grab the emitted particles and bring them along for the ride. Will I find an in-built means within Unity to do this, or might I have to make a feature request? It's ugly to have the smokestacks emitting oddly zig-zagged plumes as the ships recenter and the smoke does not!

    I will look into the two-camera approach for the near/far rendering.

    PS: the pseudo-code is actually what such a loop looks like in Java now.
     
  7. darkAbacus247

    darkAbacus247

    Joined:
    Sep 7, 2010
    Posts:
    251
    In my current project i use multiple cameras combined with transform repositioning to counteract floating point errors while on foot (similar to what you've described), once in a vehicle (helicopter) I'm able to disable transform repositioning and fly up to 100,000 without getting jittery, still using two cameras to handle near and far clipping. Depending on the vehicle view i add additional camera overlays for interior viewing, these are on a separate layer at vector3.zero so they may be hidden from view by unwanted cameras.

    So far everything working perfectly fine doing it this way. One note is i always have the player object, whether it's the on foot character or current vehicle unparented from the master gameobject (in which contains everything in scene but player), if you get in a vehicle i then shut off the on foot gameobject until you get out. once you get out I then reparent the vehicle, reposition on foot character object, then decide whether you're within safe floating point range, if not quickly correct this by setting player to v3.0, and adjusting master gameobject respectively. leaving my now on foot character next to the helicopter in the respective world position.

    Doing this this way i haven't yet noticed any major issues, hopefully this helps :)