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

Order In Layer 16 bit limit - Huge World in One Scene

Discussion in '2D' started by CarterG81, Jun 8, 2015.

  1. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I am having problems with layering my sprites correctly based on their position in the world.

    My original script simply, upon creating of the majority of stationary gameobjects, set its Order In Layer to be equal to its Z position. No problem, until I go beyond the 16 bit limitation of Order In Layer (32767, 32767).

    It works perfectly fine after it resets, except for that small bit inbetween (where all order in layering will mess up as one object will be OIL 32767 and the next 0+).

    My world is not enormous by any means, it simply goes beyond 32767 (but not much beyond that. It is under Unity's floating point limit so I don't have any other problems with my big world).



    To fix this, I tried to implement a Order In Layer script that updates based on the Camera.

    Code (csharp):
    1. if (spriteRenderer.isVisible)
    2. {
    3. spriteRenderer.sortingOrder = (int)Camera.main.WorldToScreenPoint(spriteRenderer.bounds.min).z * -1;
    4. }
    This kills performance. Especially when I enter a view with a lot of individual gameobjects (a field of grass the player can run through). I tried to lower how often it updates, but then I see flickering in some gameobjects. (Although this could be the fault of my script? I don't know.)

    My world is tile based, with massive tiles. However a lot of gameobjects exist on any single tile. My biggest problem is figuring out how to deal with the Order In Layer with that overlap between tiles or between (32767,32767) and that area around it where sprite order resets to 0.

    How do other Unity developers handle big, seamless worlds that go beyond the 16 bit limit (32767) and the depth sorting required for it?

    Thank you.
     
    Last edited: Jun 8, 2015
  2. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I'm thinking it may be best for me to use 3D Meshes instead of Unity's 2D Sprites?

    My game is already 3D, but with 2D Sprites tilted at an angle (Billboarded Sprites w/ Perspective Camera).

    I read that the renderer draws 3d meshes based on their z-position.

    Is there an easy way to change the way Unity renders 2D sprites, to render them like 3D meshes (based on their Z position)?
     
  3. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I found out (and successfully tested) not even using any Order In Layer (set everything to 0).

    From this post here

    So that seems to work (2D Sprites sorted by Z Depth) but with one major problem: I need Order In Layers. I need certain artwork to overlap other artwork, especially when it is all in the same rooted position. (i.e. A character having one Vector3 position, but composed of multiple body parts with varying Order In Layer.)

    I guess I can try to adjust the Z position by a very small value (<1.0f). This may just work!

    My biggest concern with this approach is Z-Fighting (flicker).

    edit: This doesn't work. Once my perspective camera goes down south of an object, the Z-Order fights (despite a greater z transform position) and the winner of the Z-Fighting is the wrong one. I can't increase the z position beyond a few integers max because of the perspective camera (going west/east will result in body parts falling apart or more z-fighting.)
     
    Last edited: Jun 8, 2015
    theANMATOR2b likes this.
  4. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    Wow, this was incredibly easy when I tried the method I kept delaying (for no reason at all- wtf I didn't try this first is beyond me. IQ fail today.)

    The max coordinates for the world (floating point limitations) isn't all that much. I get the warning at 99999 position. That is a little more than 3x the 16 bit limitation of Order In Layer.

    I thought it may not work because...well, I just didn't use my brain on this one. Er, quite the contrary- I used my brain too much and overthought it. I truly don't understand my own reasoning to not try this first- it was the simplest and quickest solution that would work great. I guess googling for answers can lead us down the wrong path (that, and I am super stubborn and tried to get each solution I thought of to work before trying another. Durrr me.)

    Change Order In Layer every 2 integers, doubles the limitation. To test it out, I did it to every 5 integers at first. Not at all a problem anywhere in the world. I'll tone it down to every 3 integers. The math is uber simple.

    Code (csharp):
    1. int pos = Mathf.RoundToInt(this.transform.parent.transform.position.z);
    2. pos /= 5; //Remember division of an INT and the modulus operator %? This isn't a float. We WANT to get rid of the remainder.
    3. spriteRenderer.sortingOrder = (pos * -1) + OrderOffset;
    4.  
     
    Last edited: Jun 8, 2015
    theANMATOR2b likes this.
  5. ljarbo

    ljarbo

    Joined:
    May 3, 2013
    Posts:
    44
    Did you find another method or strategy for this?

    I got it working. Just interested to know if this is all there is to it? I feel a bit uncomfortable with this solution.

    I have a 3D environment with 2D characters in it and I tweaked it some. I made a class that I dropped on the GameObject containing the 2D animation.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SpriteOffset : MonoBehaviour {
    5.  
    6.     private int maxSpritesPerObj = 10;
    7.  
    8.     //This could perhaps be removed?
    9.     public GameObject characterHolder;
    10.  
    11.     private SpriteRenderer[] spriteRenderer;
    12.     private int[] spriteOrder;
    13.  
    14.     void Awake () {
    15.         spriteRenderer = this.GetComponentsInChildren<SpriteRenderer>();
    16.         spriteOrder = new int[maxSpritesPerObj];
    17.  
    18.         //print(spriteRenderer.Length);
    19.         for(int i=0; i< spriteRenderer.Length; i++)
    20.         {
    21.             spriteOrder[i] = spriteRenderer[i].sortingOrder;
    22.         }
    23.     }
    24.  
    25.     void Update ()
    26.     {
    27.         //get screendistance to character object
    28.         Vector3 heading = characterHolder.transform.position - CameraController.MainCamera.transform.position;
    29.         int distance = Mathf.RoundToInt(Vector3.Dot(heading, CameraController.MainCamera.transform.forward));
    30.  
    31.         for(int i=0; i< spriteRenderer.Length; i++)
    32.         {
    33.             spriteRenderer[i].sortingOrder = 5000 + spriteOrder[i] - maxSpritesPerObj*distance;
    34.         }
    35.     }
    36. }
    37.  
     
  6. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    I'm sure there are other (more complicated) ways to handle this. Although I'm not so sure what they are.

    One option though I contemplated with (because it was very simple) was the Farnsworth Method.



    http://forum.unity3d.com/threads/a-realistic-huge-and-open-space-environment.37712/#post-244729
     
  7. ljarbo

    ljarbo

    Joined:
    May 3, 2013
    Posts:
    44
    Haha, and then some Quaternion rotations upon that, that would make my head spin :D

    I guess what I don't like is that I don't know how big the coordinate space is in my current project. But I found this method for figuring it out for anything with a mesh and a meshrender.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class ObjectSize : MonoBehaviour {
    5.  
    6.     void Start() {
    7.         print(this.name + ": " + this.GetComponent<Renderer>().bounds.size);
    8.     }
    9. }
    10.  
     
    CarterG81 likes this.
  8. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    Lmao, I didn't even think about that!

    Sorry I couldn't be of any real help. My world is just a tiny tiny bit too big, so the solution I found works for me. Unfortunately it doesn't work for a world more than just "a tiny bit too big".