[RESOLVED] Z Layer Ordering Issue with URP Unlit Transparent Shader

I'm working on an experimental project while learning the ropes of the DOTS stack. The project was converted from an existing 2D GameObject project I had, and for the most part I have everything working (minus the 2D packages - see this thread )

The main problem I've been noticing is that no matter what I do, SOME of my textured quads are drawing in front of others when they are clearly behind them. The interesting thing is this only affects some of the entities at one time, not every one of them, which leads me to believe it's something to do with the under-the-hood bath rendering, but that's just a guess.

Some examples:

1) I have entities' z layer dynamically adjusted based on their position which is what I was doing with the GameObjects previously
8217309--1072938--upload_2022-6-19_10-45-58.png

2) Red circles are examples of incorrect overlap, green are correct
8217309--1072941--upload_2022-6-19_10-48-0.png

3) My material
8217309--1072944--upload_2022-6-19_10-49-5.png

4) My texture
8217309--1072947--upload_2022-6-19_10-49-55.png

5) The entity itself looks like the following: The parent entity has all the physics properties and is constrained to a 2D plane so everything is at Z 0. The child object has the renderer data, and is offset from the parent as seen in the screenshots above.
8217309--1072950--upload_2022-6-19_10-50-33.png

Things I've tried:

  • Setting variations of custom axes for the pipeline
  • Using different shaders - I can't find another transparent one that the hybrid renderer supports though
  • Using different meshes (planes or cubes instead of quads)
  • Putting more distance between the entities
  • Using alpha cutoff to make it behave more like a cutout shader
  • Using the latest entities package and Unity version possible (0.51 and 2021)
  • Setting the material sorting property to -1 to allow the shader to handle it

I may be forgetting something, but that's the gist. I know plenty about C#/OOP/etc, but next to nothing about shaders. Does this seem like something I can fix with a custom shader, or is this a bug with the hybrid renderer I'll have to wait for a fix for?

1 Like

*** UPDATE/TEMPORARY FIX ***

Well I don't like this since it prevents me from using ANY transparency in my entities (I think), but in the meantime, my workaround was to cut out a plane in Blender and change the material to use an opaque shader, so the model itself is the cutout instead of projecting a transparent image onto a rectangle.

8220429--1073466--upload_2022-6-20_17-20-7.jpg

8220429--1073463--upload_2022-6-20_17-19-43.png

For now, it works. But there is almost certainly a bug with using transparent shaders (at least while using textures) with the hybrid renderer. I'll keep an eye on updates and see if it is resolved in the future.

Hybrid Renderer should sort transparencies from back to front, using the entity's world position. However, in 0.50 and 0.51 it must do this using a special shared component (HybridBatchPartition) to break batches into single entity batches so the batches can be sorted. This should happen automatically when converting a GameObject with a transparent material is converted, unless you explicitly disable this behavior with the scripting define DISABLE_HYBRID_TRANSPARENCY_BATCH_PARTITIONING.

Are you by any chance creating your entities using a custom scheme? If so, then you might want to consider adding the HybridBatchPartition shared component to fix the sorting behavior. However, your cutout method is likely to have significantly better rendering performance on both CPU (instanced rendering) and GPU (no alpha blending), so from a performance standpoint it is probably a better approach.

1 Like

@JussiKnuuttila For the entity conversion, I'm using Resource.Load() on a prefab that is marked for conversion (plus a couple authoring scripts), storing the prefab on a spawner component using IDeclareReferencedPrefabs on the spawner authoring script, then using EntityManager.Instantiate() on N entities. So other than adding a few custom components, I'm letting it convert everything under the hood.

I double checked the DOTS hierarchy window, and the quads do have HybridBatchPartition components attached, along with the other typical components:

8222217--1073838--upload_2022-6-21_10-31-22.png

That's an interesting thing to know about my workaround being more performant though, thanks.

I think if you have unique HybridBatchPartition values (conversion computes these based on a hash), then Unity should sort all such entities back to front using their WorldRenderBounds values. Perhaps it's also worth to double check that the entity's bounds are not unexpectedly large, which could potentially cause Unity to sort things in a weird way.

Interesting! I checked through a few of the entities and they all seem to have the same partition value, even on multiple scene reloads. That must be the cause. Is it something to do with all these entities coming from the same prefab? What would I have to change to make sure a unique hash is calculated for each entity?

Edit: Manually updating one of the entities' partition value did fix the z layer ordering, at least for that entity. Is it safe to just set them all myself to a self managed ID?

Matching partition values could very well explain the sorting bug.

The HybridBatchPartition value does not matter, as long as they're unique. The value is not used for anything as such, except that ECS itself guarantees that entities with different values will be in different chunks, and Hybrid Renderer will not combine two chunks into a single batch if they have a different value, thus forcing entities into unique batches, which can then be properly sorted.

I think the GameObject conversion initializes it with a hash based on the entity ID and the scene section. Replacing the value with a custom generated value should work just fine.

Manually setting the partition value for each entity worked, thanks for your help!

8222589--1073925--upload_2022-6-21_12-44-48.png

I will note that I still have to place them about 0.5 z units apart from each other or I still get some bleed through, but that placing isn't a problem in my project.

Now, that does add a couple milliseconds of processing because, well, they are obviously no longer processing in batches. So from here I may look into grouping them by similar z levels, but that's another topic. I'll mark this as resolved.

2 Likes