Search Unity

Dynamic draw order or '2D Z-buffer'?

Discussion in '2D' started by oferkap, Dec 31, 2013.

  1. oferkap

    oferkap

    Joined:
    Dec 24, 2013
    Posts:
    8
    Hi,
    In a 2D isometric game, how do you handle the draw order of the character and objects like walls and crates?
    Wall sections/ a building or things like that, are just sprites and have no real depth, and our character as well, but it needs to draw on top of them when standing in front, and draw behind when standing behind... How is this handled?

    Thanks.
     
  2. Zenity

    Zenity

    Joined:
    Dec 19, 2013
    Posts:
    12
    You can still use the Z position value for this, no?
     
  3. Kurius

    Kurius

    Joined:
    Sep 29, 2013
    Posts:
    412
    Use the Order In Layer variable
     
  4. oferkap

    oferkap

    Joined:
    Dec 24, 2013
    Posts:
    8
    OK, I can change the Order In Layer technically, but how do you detect when the player, or anything else, is behind or in front of the object?
    Maybe you can model a proxy mesh to fit the object, or define two regions on the ground for collision and for culling?
    Think about games like commandos, everything is hand-drawn, but you ca still go behind trees, houses and such.
     
  5. Kurius

    Kurius

    Joined:
    Sep 29, 2013
    Posts:
    412
    Well why do you want to "detect" when one object is behind another object?
    Note that alternatively you can establish several "Sorting Layers". This is different than Order In Layer.
     
  6. oferkap

    oferkap

    Joined:
    Dec 24, 2013
    Posts:
    8
    Ok, to be honest Im not sure I understand you. Maybe I'm not explaining myself very good.
    The best way would be with an image:
    $problem.jpg

    If the house is our sprite, and the character walks around it, the draw order should change when the character goes under the roof. This is not so simple, unless I miss something. I guess a combination of separating the house to multiple sprites, and using the Y position of the character as a fake Z can do the trick, but its not very elegant
     
  7. Kurius

    Kurius

    Joined:
    Sep 29, 2013
    Posts:
    412
    Looks like you should be using the 3D engine, not the 2D engine. You can still lock the camera to a side view perspective, so that it appears 2D, but functionally it will be 3D, and therefore more naturally and easily handle objects walking around other objects.
     
  8. oferkap

    oferkap

    Joined:
    Dec 24, 2013
    Posts:
    8
    OK, do you think thats how it works in games like Commandos and Desperados? Every building is represented by a proxy mesh with textures? Modelling the entire assets is very time consuming/requires too many polygons to reach painted quality no?
    Sorry if this is just basic stuff that I don't understand, I'm new to this...
    Thanks a lot.
     
  9. Kurius

    Kurius

    Joined:
    Sep 29, 2013
    Posts:
    412
  10. dasbin

    dasbin

    Joined:
    Jan 14, 2012
    Posts:
    261
    The way I do this is to put a trigger zone behind the object, so when the player (or some other character) walks into that area, you can either move the object forward or move the player back. Previously I was doing this by setting the Z-value but now you could probably just edit the order in layer.

    It is time-consuming, especially tweaking the trigger to be the exact right shape that you don't notice the change when walking on corners etc. But with some art styles it is basically impossible to make a 3D representation of an object so I'm not sure what other choice there is than to leave it 2D and do this.
     
    Last edited: Jan 4, 2014
  11. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    I find setting Z values works well. Sometimes you need to split a sprite into two or more pieces with different depth values, but it's not as much trouble as creating an entirely 3D model - they're still just layers. Using triggers is an interesting approach but also feels kind of complicated, and awkward to get working with multiple characters wandering around.
     
  12. ijj

    ijj

    Joined:
    Jan 7, 2014
    Posts:
    1
    gfoot~ Could you tell me How to set the Z value ?
    It seems the z value in the inspector is not working.
     
  13. technos

    technos

    Joined:
    Jan 6, 2014
    Posts:
    5
    Hi, I think we are facing exactly the same problem.
    With the search I have done, I think you should use the 3D engine with a fixed camera like explained above.
    You cannot handle changing sorting layers on real-time. If you had only one moving character, it would be possible but for 50 units... and one time you will be in the case where a character is in front of the building and one on the back at the same time.

    You can then apply your 2D "texture" on a 3D block and move it in a 3D coordinates system which will hande the Z-Depth.

    If the result is successful please write it here :) With a screenshot... I love real example ;)
     
  14. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    ijj, it just works flawlessly for me. I do use sorting layers for most things, but have used Z depth for other things without problems.

    I just tested it again to make sure, and it works fine. This test was in a project which was started from the beginning in 2D mode, so there are no 3D remnants. The sprites are just normal sprites - PNG files in the assets folder, dragged into the scene. The sprites with lower transform.position.z values render in front of sprites with higher Z values, in both the scene view and the game view, including when the position is changed from script at runtime.

    All these sprites must be in the same sorting layer and with the same 'order in layer' value. Put another way, the sorting layer is the highest priority control over these overlaps; then order in layer comes next; then actual Z depth from the camera. So you can freely mix the techniques, sticking to sorting layers for most things (e.g. making the ground render behind the house and characters, and making UI elements render on top of everything else), but using Z depth as a last resort for more dynamic, continuous order changes.

    Remember again that for some sprites you might want some parts to have different depth to other parts. In an isometric game, with the grid X and Y axes inclined at equal angles to the screen horizontal, this would happen for objects with a rectangular profile on the grid - the left extent of the object in screen-space would be at a different distance from the camera, in a true 3D world, than the right extent. In that case you may want to cut the sprite down the middle and render it as two pieces with different Z values. Another approach is to rotate the sprite about the camera's up axis and scale it up a bit, to have a linear depth gradient across the sprite. This should work fine for almost any object in an isometric game.
     
  15. TaewYn

    TaewYn

    Joined:
    Jan 30, 2013
    Posts:
    19
    Hey, I just posted this in another thread as well but since it's the same question I'll answer here as well:

    The render order determined this way : Sorting Layer > Order in Layer > Z transform . That's why I decided to do things this way:

    -all foreground elements are on the same Sorting Layer
    -each element has a script attached, that changes the Order in Layer according to the Y position of it's feet/base
    -if I have a gameobject that consists of multiple sprite child objects (character limbs or so), I assign the same Order in Layer for all components and then adjust the sorting of the children via the z transform

    This also leaves you with the ability to use the Z transform in animations (limbs moving behind other limbs and so on).
     
  16. technos

    technos

    Joined:
    Jan 6, 2014
    Posts:
    5
    Do you think, without cutting each sprite in two parts, that it can solve the following :

    $Unity_human_Back.jpg
    $Unity_human_In_Front.jpg

    My little boy is moving around the castle, and everything is fine all the time...
    If you try to change the Sorting layers by script depending of the position of the guy, it won't work if you have one guy back, and one front at the same time...

    Is 2D still a real solution ?
     
  17. TaewYn

    TaewYn

    Joined:
    Jan 30, 2013
    Posts:
    19
    As I said, I don't change the sorting layers, but the Order in Layer.

    Let's say the center of the castle has a Y coordinate of 10. That sets the Order in Layer to -10
    If the player moves lower than the center of the castle, his Y coordinate would be something like 8, making his order in Layer -8, thus rendering him in front of the castle.
    If the player moves above the center of the castle, his Y coordinate will be something like 12, making the Order in Layer -12 and rendering him behind the caslte.
    This works with as many characters as you want, because each character updates it's own Order in Layer.


    In this case you wouldn't have to split the sprite, just take the center diagonal as the castles "base", and the character's feet as the character's "base. If you have more complex structures, you might have to split them up at some point. (the drawbridge here might cause issues for example)
     
    ecv80, littlesten and JoeStrout like this.
  18. TaewYn

    TaewYn

    Joined:
    Jan 30, 2013
    Posts:
    19
    Code (csharp):
    1. void LateUpdate () {
    2.  
    3.                 spriteRenderer.sortingOrder = (int)Camera.main.WorldToScreenPoint (spriteRenderer.bounds.min).y * -1;
    4.         }
    5.  
    This is basically what I do. This script assumes the base of the character is at the bottom of the sprite though, which isn't the case in isometric 2D.
    With base I mean the horizontal line at which you decide what is in front and what is behind. In isometric it should usually be the horizontal diagonal of the sprite, so just change the script according to that.
     
    Last edited: Jan 7, 2014
    Jamisco, ChiuanWei, diaosuyi and 4 others like this.
  19. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    TaewYn, your technique is interesting - I hadn't had to deal with the characters themselves requiring multiple overlapping layers. Certainly a problem with doing it with transform.position.z is that you're sensitive to Z buffer resolution - not a major problem but you do need to be careful to use large enough offsets between "layers".

    technos, as TaewYn said I think you should be able to use these techniques, but as I said before the ground is going to cause you problems unless you separate it into a separate sprite on a more distant layer. To see why, look at the case where your character is behind the castle, and imagine moving him towards the castle so that his sprite needs to be rendered on top of the surrounding ground, but behind the castle itself. It means that you need the ground and castle to be rendered separately, unless this is prevented by your collision detection - but your other image shows the character with his foot on the castle's tile, so I guessed your collision detection isn't so strict.
     
  20. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,051
    Indeed, what TaewYn described is the usual approach to this. Whether using Unity or not. If you want to use ground textures (apart from the base ground), treat them separately from objects that will cull the characters. Additionally, if you want to have elements that characters walk through (arches/doorways/etc), just cut them logically along the Y and place one in front of the other.
     
  21. MoschPitt

    MoschPitt

    Joined:
    May 11, 2014
    Posts:
    1
    TaewYn, you are a genius! I put this little script on all of my "unit" type game objects and your approach works flawlessly every time.

    Code (JavaScript):
    1. var tempRend : SpriteRenderer;  //allows to adjust for sorting within the unit layer, for visuals
    2.     function Awake(){
    3.             tempRend = gameObject.GetComponent(SpriteRenderer);
    4.     }
    5.     function LateUpdate(){
    6.             tempRend.sortingOrder = Camera.main.WorldToScreenPoint(tempRend.bounds.min).y * -1;
    7.     }
     
    schouffy likes this.
  22. schouffy

    schouffy

    Joined:
    Mar 8, 2015
    Posts:
    10
    Thanks MoschPitt (and Taewyn), works great.

    Just for performance, i checked visibility to change order only on useful sprites
    if (tempRend.isVisible)
    tempRend.sortingOrder = ...
     
    CarterG81 likes this.
  23. IdeaMoose

    IdeaMoose

    Joined:
    Jul 29, 2015
    Posts:
    2
    Thanks for this! I'm a complete Unity rookie and this is my first post! :) Using Taewyn's method my characters move around objects perfectly. I'm just using a 2D scene (nothing isometric). Though I've run into the problem where if I use a different aspect ratio than what I set my Order In Layer values at (hitting Maximize on Play for example after setting values in the main game window) then everything gets thrown out of wack. I'm guessing something is changing with my camera values so that makes everything a little out of place when changing aspect rations.

    Like I said I'm a new user here so I'm guessing I did something silly or forgot something with my setup. Any ideas what could be causing this? Sorry if it's vague.
     
  24. IdeaMoose

    IdeaMoose

    Joined:
    Jul 29, 2015
    Posts:
    2
    I managed to fix this by just getting the y co-ordinates of the character from the transform rather than a camera point in the world (which might be the wrong thing to do but at least now the values don't change depending on the screen resolution) :)

    tempRend.sortingOrder = (int)transform.position.y * -1;

    This is what the code looks like now.

    Thanks!
     
  25. JamsRamen

    JamsRamen

    Joined:
    Sep 13, 2015
    Posts:
    1
    Ok, I know this question is pretty old, but I found a solution (that is pretty obvious with the newer versions of Unity). Just create a canvas for each object that needs sprites to be rendered. Make sure the render mode on each canvas is world space. Add your sprites as image components as children of the canvases.
    If you are curious: http://unity3d.com/learn/tutorials/topics/user-interface-ui
     
  26. Aedous

    Aedous

    Joined:
    Jun 20, 2009
    Posts:
    244
    Not quite sure you should be doing this, because you are essentially creating multiple UI canvas's in your game, which could bring you some performance issues down the road, especially if every sprite in the game is under a Canvas.
    Taewyn's method actually works great and should give you a basic setup of how to sort your sprites, the only problem I've encountered is with Isometric games and tilesets that may be long in length, for example a wall.
    The way I've solved this is by having a trigger collision infront of the wall and also an enum that determines whether an object which is touching this trigger should be infront or behind. I then take the walls sorting order and the object touching the trigger and make sure the objects sorting layer does not end up going behind / infront of the wall.
    So far so good, but the only problem is more collisions everywhere, and there's not enough collision layers to play with :(.
     
  27. fabian_rensch

    fabian_rensch

    Joined:
    Aug 8, 2015
    Posts:
    1
    I know this is super old but I can't get it to work. I always get a Null Reference Exception.It seems like my sortingOrder isn't referenced as I can't debug t in the console, too. Any ideas? My code looks basically exactly like the one posted above:

    Code (CSharp):
    1.     private SpriteRenderer tempRend;
    2.  
    3.     void Start () {
    4.         tempRend = GetComponent<SpriteRenderer>();
    5.     }
    6.  
    7.  
    8.     void LateUpdate () {
    9.      
    10.         tempRend.sortingOrder = (int)Camera.main.WorldToScreenPoint (tempRend.bounds.min).y * -1;
    11.     }
    EDIT: Okay, I'm stupid. Got the Null error because the camera wasn't tagged as mainCamera /facepalm

    Btw @Aedous I love your game :)
     
    Last edited: Dec 30, 2015
  28. theredace

    theredace

    Joined:
    May 30, 2013
    Posts:
    7
    So i'm using this Y-coordinate technique in my 2D isometric game. The code sets the order in layer only in the editor, so the ordering of environment objects does not occur in realtime, but rather my character's order in layer changes in realtime based on the Y-coordinate. So it's dependent on the pivot point positioning of each object to determine at which Y-coordinate my character flips between being rendered in front/behind that object.

    I've run into the issue with the position of that pivot point being difficult to place for diagonal objects (which are pretty common in isometric view). Imagine a fence displayed at a 45-degree angle. If the pivot point is in the "center" of that fence, and my character is walking on the side of the fence closer to the camera (where we want the character rendered in front of the fence), as soon as the character gets higher than the middle of the fence (where the pivot is), the character will switch to being layered behind the fence, which is not correct. Some of you have mentioned just cutting the sprite into multiple pieces. This is certainly an option, though this issue occurs on nearly anything displayed diagonally (even smaller objects), so all my assets would likely have to be cut into 3+ pieces. A long fence like this would probably be 10+ separate pieces and it would be very difficult to ensure that when the character switches layering he's not at all overlapping the edge of the piece that you just switched with, which would look bad.

    I feel like there must be a better solution to this. Anyone found a more elegant way to deal with this issue?
     
    vexe likes this.
  29. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,924
    The Y-coordinate method is indeed what was/is used in 2D isometric (ish) games. Certain games like the old Zelda/FF series avoid this issue you mention by just dropping isometric view altogether and aligning the camera with one axis, so that diagonal objects just aren't used.

    If you really want isometric perspective with correct z-ordering and arbitrarily shaped objects, you must use full 3D. Put your camera in orthographic mode, an rotate it correctly (45 degrees in y axis, and anything from 30 to 60 degrees in x or z) to get a 2D isometric effect. Then, the zbuffer will automatically take care of correct ordering of your objects. No asset-chopping needed.
     
  30. theredace

    theredace

    Joined:
    May 30, 2013
    Posts:
    7
    To be clear, you're talking about actually rendering everything in 3D models, right? Because I don't see how that would fix the issue if the art was still flat sprites. Of course having full 3D models gets around this issue, but it's just a lot more work and I prefer working with 2D art, so I'm trying to avoid that if at all possible.
     
  31. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,924
    Yes and no. I´m talking about rendering 2D art in 3D. This is how things worked in Unity before 2D mode was available, which is just a convenient switch that sets up a few things for you. Nothing radical changes internally, the rendering pipeline is the same.

    Use flat planes in the xz axis (assuming y is upwards) for your floor tiles. Then, use flat planes perpendicular to it for your walls and fences, and planes parallel to the floor for your roofs and intermediate floors . Your art is still 2D, but mapped to flat 3D surfaces. You just have to either:

    - Strip perspective effects from your art, as the camera now does the work to make it look isometric. Think of your sprites as "posters" that get glued to 3D walls.

    - If you absolutely want to create your art in perspective, use a special shader to project your art from the camera, instead of relying on regular UVs.

    Hope that makes sense.
     
    vexe likes this.
  32. me_mania

    me_mania

    Joined:
    Aug 12, 2013
    Posts:
    3
    So I'm using the method explained by TaewYn but I'm having issues with a rigged character (multiple limbs as child objects).
    1. I've ordered the limbs using their Z transform as suggested,
    2. set them to the same Order in Layer,
    3. and attached the Sorting Layer script (contains the code written by TaewYn) that updates sorting order using Y coord.
    Here's the issue! Since the limbs each have a unique Y position their sorting order gets completely messed up when it runs, since it's now updating order using the Y instead of just the Z.

    I know I'm missing something here! Maybe I'm not understanding how this works. I need to still have the functionality of changing my sorting order according to Y position but also keep my rigged character's sorting order tied to their Z position. Can anyone help with this? Thanks!
     
  33. theredace

    theredace

    Joined:
    May 30, 2013
    Posts:
    7
    Oh, yes we'd considered this also. I guess we'd been referring to it as "projection mapping". It's just a lot more complicated so we're trying to avoid it.
     
  34. mikest

    mikest

    Joined:
    Feb 23, 2015
    Posts:
    29
    Assuming the "limbs" are all parented to the gameobject with the rigidbody2d you can do something like this:

    Code (CSharp):
    1. sr.sortingOrder=((-1*Mathf.RoundToInt((transform.parent.position.y*100)))*10)+getLimbSortingOrder();
    You'll need some way for the limb to know the order it should appear in. I am doing something similar in my game and it works well. This will give you values in the 1000's for the sorting order but it used consistently in your project should allow for very fine grain control of the sprite order.

    Also note that I adjusted the approach from the earlier post slightly to get a more accurate sorting when game objects are close together. Just using the rounded Y was often not good enough. For example, two close items might both get a value of 5 when one was 4.778 and the other was 5.111.
     
  35. DynamoGeek

    DynamoGeek

    Joined:
    Sep 4, 2016
    Posts:
    1
    This worked perfectly. Thanks for that, if you ever see this message!

    I created a script containing the C# code below and added it to the game objects I wanted to give a dynamic sorting order to, as described by the OP.

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class DynamicSortingOrder : MonoBehaviour {
    5.    private SpriteRenderer spriteRenderer;
    6.  
    7.    void Start () {
    8.        this.spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
    9.    }
    10.  
    11.    void LateUpdate () {
    12.       this.spriteRenderer.sortingOrder = (int)Camera.main.WorldToScreenPoint (this.spriteRenderer.bounds.min).y * -1;
    13.    }
    14. }
    EDIT:
    It's worth noting one more time that the objects that you want to put in front of/behind each other need to be on the same sorting layer.
     
    Last edited: Sep 4, 2016
  36. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    One solution to this is that you need to give every pixel of the artwork a Z depth value, which would happen if the object (e.g. the castle) were actually made from 3d geometry as a model/mesh. Each individual PIXEL would have written something into the z buffer and then the SHADER would have determined whether to draw other objects 'in front of' or 'behind' that object, based on that objects own Z coordinate. To do this though, with 2D art, you can't really treat the entire castle as having just one Z coordinate. Each pixels needs one, which means you really need a 'depth texture' for all of your artwork. And then to feed this into a shader. But I think also to get those depths into the graphics pipeline properly, you'd need a mesh with as many vertices as pixels, so each vertex can get its vertex position modified on the fly with a vertex shader, to position it at the appropriate Z coord. Unless a shader can manipulate and output the z buffer data in some other way. So basically here you'd be emulating 3D but using 2D art with sort of 'pre-baked' z coordinates. Then the normal ZTest of 'LEqual' or whatever would automatically cull pixels that are in front of other objects.
     
    JamesArndt and Raseru like this.
  37. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,924
    Yep, it is possible to output depth directly from the fragment shader. Instead of returning float4, fixed4, or any other "color" type, you declare a struct that contains both color and depth values, like this:

    Code (CSharp):
    1.  
    2.  
    3. struct fout {
    4. half4 color : COLOR;
    5. float depth : DEPTH;
    6. };
    7.  
    8. fout frag( v2f i )
    9. {
    10.     fout fo;
    11.  
    12.     fo.color = //whatever
    13.     fo.depth = //whatever
    14.  
    15.     return fo;
    16. }
    You could have an overall depth value for each object passed as a vertex attribute, or directly calculated in the vertex shader from the world-space Y coordinate, and then store depth offsets in textures to modify this overall depth per-pixel.
     
    Last edited: Sep 6, 2016
    imaginaryhuman likes this.
  38. Rainbirth

    Rainbirth

    Joined:
    Aug 3, 2013
    Posts:
    110
  39. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,924
    Nice, but it seems you need to split your art into several objects to be able to sort them independently (which is fine for animated characters, not so fine for scenery). The solution given by ImaginaryHuman would work for one-piece sprites, and you'd have per-pixel sorting granularity.
     
    Last edited: Sep 6, 2016
  40. Rainbirth

    Rainbirth

    Joined:
    Aug 3, 2013
    Posts:
    110
    Sure, that's one approach, but don't understimate the solutions 2D isometric games have been using since long, drawing your items depending on the Y axis is powerful enough to order your stuff (imho). Having a depth texture for each asset can be tricky, once you start having multiple assets one in front of the other... imagine a tree in front of the castle and then the player in between... etc...
     
  41. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,924
    The beauty of having depth textures is that it just works in all cases, no matter how complex. Even if you have a castle made of just one sprite with a drawbridge the player can go under, it will behave correctly. You don´t have to split the drawbridge to a separate sprite and sort them.

    A tree in front of the castle and the player in between would work either way. But using depth textures you don´t have to sort sprites at all, which leaves you more CPU power to burn doing other things.

    Moreover, if your artists are lazy and leave all depth textures blank, the method is fully equivalent to simple Y-axis layer sorting. So I don´t really see any disadvantages to it.
     
  42. radiowaves

    radiowaves

    Joined:
    Jan 20, 2017
    Posts:
    12
    I am not a programmer, but the easiest way would be to use a grid. Each horizontal line of grid corresponds to depth in layer. Top is 0, second from the top is 1 and so on. Each object checks the position it is on, on the grid and sets the z value accordingly. Easy to do with a formula and check is only when object is moved.
    In fact you do not even need a grid, but can tie it directly with Y position on the layout. The pivot of objects needs to be where the two angles meet in isometric view. Characters collision is only at the feet.
     
    Last edited: Jan 20, 2017
  43. Brogan89

    Brogan89

    Joined:
    Jul 10, 2014
    Posts:
    244
    Thanks, this forum helped a lot with z depth issues with objects on the same layer. I'll add a script to solve using this same idea but with sprite meshes that Anima2D use. The script can be added to your parent object of your spriteMeshInstances.

    Code (CSharp):
    1. using Anima2D;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class DynamicSortingLayer_SpriteMesh : MonoBehaviour
    6. {
    7.     [SerializeField]
    8.     private int heightID;
    9.  
    10.     private Dictionary<SpriteMeshInstance, int> spriteMeshDict = new Dictionary<SpriteMeshInstance, int>();
    11.  
    12.     private void Start()
    13.     {
    14.         for (int i = 0; i < transform.childCount; i++)
    15.         {
    16.             var smi = transform.GetChild(i).GetComponent<SpriteMeshInstance>();
    17.             if(smi != null)
    18.                 spriteMeshDict.Add(smi, smi.sortingOrder);
    19.         }
    20.     }
    21.  
    22.     private void LateUpdate()
    23.     {
    24.         heightID = (int)Camera.main.WorldToScreenPoint(transform.position).y * -1;
    25.         foreach (var spriteMesh in spriteMeshDict.Keys)      
    26.             spriteMesh.sortingOrder = spriteMeshDict[spriteMesh] + heightID;      
    27.     }
    28. }
     
  44. rage39a

    rage39a

    Joined:
    Sep 14, 2018
    Posts:
    1
    So the above answer got me 95% of the way the only unfortunate issue i had was when i was jumping my sprite would appear behind other sprites. I have a game in progress similar to castle crashers where the graphics are 2D but exist in a 3D world (2.5D) so you can go up and down (Z axis) and then left and right (X axis) and jump (Y axis). So for me i need to render the sprites based on their position along the Z axis regardless of the Y axis. Super happy i finally managed to get it working after a few hours of frustration (was trying many different methods), hope this helps someone :)

    Code (CSharp):
    1. using Anima2D;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityStandardAssets.CrossPlatformInput;
    5.  
    6. public class DynamicSortingLayer_SpriteMesh : MonoBehaviour
    7. {
    8.     [SerializeField]
    9.     private int positionPrecision = 1000;
    10.  
    11.     private Dictionary<SpriteMeshInstance, int> spriteMeshDict = new Dictionary<SpriteMeshInstance, int>();
    12.     private void Start()
    13.  
    14.     {
    15.         for (int i = 0; i < transform.childCount; i++)
    16.         {
    17.             var smi = transform.GetChild(i).GetComponent<SpriteMeshInstance>();
    18.             if(smi != null)
    19.                 spriteMeshDict.Add(smi, smi.sortingOrder);
    20.         }
    21.  
    22.     }
    23.  
    24.     private void LateUpdate()
    25.     {
    26.         foreach (var spriteMesh in spriteMeshDict.Keys)
    27.             spriteMesh.sortingOrder = spriteMeshDict[spriteMesh] + (int)(spriteMesh.transform.position.z * -positionPrecision);
    28.     }
    29.  
    30. }
    You can change positionPrecision if you need a higher level of z axis precision but i think to 3 decimal places should be fine for almost all cases
     
    Last edited: Nov 3, 2018
    ChiuanWei likes this.
  45. craig4android

    craig4android

    Joined:
    May 8, 2019
    Posts:
    124
    Just some improvements: Don't change it on update for static object you only have to change their Z on start.

    however I wonder if there is a build in Solution for this?
     
  46. brunordeangelis

    brunordeangelis

    Joined:
    Jul 30, 2020
    Posts:
    4
    For anyone coming here, Unity has an already implemented way of doing this, you don't need to code anything. Just go to Edit > Project Settings > Graphics > Transparency Sort Mode: Custom Axis and set Y to 1. You then need to set every Sprite Renderer to use the Pivot instead of its Center. Assuming you possitioned your pivot correctly when slicing your sprites, Unity will now automatically sort sprites based on the Y axis.
     
  47. jorgefelico

    jorgefelico

    Joined:
    Nov 11, 2020
    Posts:
    1
    In case no-one has said it, Thank you for this!
     
  48. Mr-Jun

    Mr-Jun

    Joined:
    Jul 1, 2015
    Posts:
    9
    Yup, this is the way! Thanks for this.
    For my case I Just had to set the custom axis Z instead because it's in a 3D space.
    camera.transparencySortAxis = new Vector3(0, 0, 1);