Hi, I’m working on 2D project. We use usual sprites, usual particle systems and spine animations.
But then I have a problem:
Let’s say I have a Tree and Character, and when character moves he is either behind or in front the Tree. And then I want to play some particles above Character, but behind the Tree.
Dynamic sprite sorting only works if they are on the same layer. And then I simply can’t fit anything else between them. I can put particles behind Character or above Tree, so it’s behind all of them or above of all them, there’s no other option it seems.
Are there any solutions to this problem?
One I could think of is custom shaders, but that’s not an option for me (one day I’ll learn them).
Maybe Render Queue on material could work, but copying materials for specific objects to define their draw order is kinda hacky, complex and error prone and I’m not even sure it will fix the problem entirely.
Any ideas? Maybe anyone solved such cases too? Thanks in advance.
Three (3) primary ways that Unity draws / stacks / sorts / layers / overlays stuff:
In short, as far as the Standard Rendering Pipeline,
The default 3D Renderers draw stuff according to Z depth - distance from camera.
SpriteRenderers draw according to their Sorting Layer and Sorting Depth properties
UI Canvas Renderers draw in linear transform sequence, like a stack of papers
If you find that you need to mix and match items using these different ways of rendering, and have them appear in ways they are not initially designed for, you need to:
identify what you are using
search online for the combination of things you are doing and how to to achieve what you want.
There may be more than one solution to try.
For instance, you may even use multiple co-located cameras to more-explicitly control apparent draw ordering.
Additional reading in the official docs:
And SortingGroups can also be extremely helpful in certain circumstances:
Other rendering pipelines may have other ways of layering (HDRP and URP). Go see the latest docs for details.
There’s lots of third party open source packages available as well, such as this:
OPTION1:
You can use sprite masks to hide the area particle system overlaps with the tree(the tree will have a sprite mask; the vfx will have mask interaction:Not Visible Under Mask).
I am not sure if particle systems have a mask option. If particle systems cant be masked, you’ll have to use 2d spritesheet style vfx’s or something. OPTION2:
You can render the tree with a separate camera to a render texture, use that render texture in the vfx’s shader as a filter(set alpha to 0 or use clip etc. when the rgb isnt black in that pixel of the render texture – dont forget to use screen uv’s when sampling the render texture). [u]OPTION3:[/u]
Try to put everything in the same layer as sildeflask suggested. This still might cause sorting issues for you depending on your vfx because the vfx will still be sorted regularly. [u]OPTION4:____[/u]
You can also try to fiddle with render textures for whole layers; it gets rather complex and I dont recommend it for this(example of this method here) OPTION5:
Not a solution but maybe ignore the sorting and just move on to other things. You can maybe work on it in the polish stage.
Let’s imagine:
Character has layer 0
Tree has layer 0
Particles have layer 0
Particles will render somehow, above all of them or behind all of them. I can ensure that it’s rendered above or behind by setting Particles layer to -1 or 1, for example.
But I can’t in any obvious way put Particles inbetween Player and Tree.
If I move Player and Tree to separate layers (e.g. 0 and 2) then sprite sorting by position won’t work.
Are the particles moving along with player? Do you want it to always be in front of or behind the player? Do you want it to be in front of the tree when the player is in front of the tree and behind the tree when the player is behind the tree? If so, check out sorting groups
For me it would be enough if particles had static layer and rendered always above something or always behind something, like always above Character and always behind Tree. I can already to that if Tree is also rendered above Character, but I need sorting by custom axis.
Create sorting group on empty gameobject (parent). Give it a child gameobject. Put the particle system on the child.
Now the sorting group will sort consistently based on the parent’s gameobject location (and thereby your custom axis), so you can place it between tree/character as you like.
One of problems was RenderQueue on some VFX materials.
Some was 2750, so they was rendered always below something unless you increase their layer.
I made them 3000 on par with everything else and they now work like sprites, they are above some sprites or below some sprites depending on their Z position (that’s my custom axis).
If anyone has the same problem as me, just be sure that everything has the same RenderQueue.
Render priority in 2D works like that: Layer → RenderQueue → Custom Axis.
Rendering by custom axis can be achieved only for objects with the same Layer and the same RenderQueue, you don’t want to change them unless necessary.
And I found that particles sorting work by their transform position (correct me if I’m wrong).
So if some particles still render behind object they are parented to, you can change their transform.postion so their pivot is changed and they are rendered above, then you change their emission point in Shape module so their result position isn’t changed, while rendering order is modified.
Also pay attention to Sorting Fudge in Render module. This parameter basically offsets Particle System pivot along custom axis. If you make it -0.5 for example, particles will still be sorted by custom axis, but rendered above sprite unless sprite position difference is bigger than 0.5 units or more along custom axis. So you can use it too to kinda control particles pivot which is used for sorting.
And yep, it’s possible to sort 3D objects by custom axis. Just create default material and set it to Transparent. Tried it with default cube and it’s rendered above or below some sprites while you move it above or below their position.