3
\$\begingroup\$

I have a mesh of some walls and a floor that I want to be visible from both sides. I duplicated the faces and flipped their normals in Blender, then exported it as an FBX to import in Unity. I've set up the texture and material in such a way that the faces that face inwards are green, and the ones that face outwards are red. This works somewhat well, but I'm getting a strange depth issue in some cases.

Animated gif of the issue

As you can see in the image, in the corner with the two narrow walls the red outward-facing polygons show through the green inward-facing walls, as if the green wall is transparent.

I checked the model and the normals are all pointing in the right direction. It somehow looks like some sort of depth buffer issue, where the renderer thinks the red wall is closer than the green one it's supposed to be obscured by.

I'm using Unity 2021.1.25f1 with the URP v11. The shader is just the standard URP/Unlit shader.

What could be causing this?

\$\endgroup\$
3
  • \$\begingroup\$ By any chance, have you configured this material with "Surface Type: Transparent"? \$\endgroup\$
    – DMGregory
    Commented Oct 21, 2021 at 16:23
  • \$\begingroup\$ I have, yes, because I want the red sides to be semitransparent at some point so you can see through them into the space. But all the colors in the texture are completely opaque right now. \$\endgroup\$
    – Bas
    Commented Oct 21, 2021 at 16:53
  • 1
    \$\begingroup\$ That'll do it. Transparent objects don't write to the depth buffer, to avoid strange-looking cutout artifacts. For a case like this where it's all one model, it's up to luck of the draw which polygon gets rendered last and thus "on top". \$\endgroup\$
    – DMGregory
    Commented Oct 21, 2021 at 17:29

1 Answer 1

3
\$\begingroup\$

When you set a material to be transparent, by default this also disables it from writing to the depth buffer.

This is important for avoiding ugly cut-out effects, where a transparent or faintly translucent part of a polygon closer to the camera completely blocks the rendering of a polygon further away, which just happened to render after it, leaving a visible hole in the more distant polygon.

Instead of making your mesh double-sided, with a copy of each polygon facing each way, you can instead leave it single-sided but render it in two passes:

  • The first pass is opaque (depth buffer writes enabled) and renders only the interior (front-facing) polygons.

  • The second pass is transparent (depth buffer writes disabled) and renders only the exterior (back-facing) polygons.

One quick way to test this is to set up two materials: one green, opaque, set to render front faces, and one red, transparent, set to render back faces. Add both materials to your MeshRenderer component.

I think you can also implement this with a single material using a custom shader with two passes, but I'd need to double check whether you can put two passes in different geometry queues (opaque geometry vs transparent).

\$\endgroup\$
1
  • \$\begingroup\$ This indeed did the trick, thanks! I hadn't thought about the transparent materials not writing to the depth buffer and it being just the luck of the draw which polygon got rendered last. I suppose writing a custom shader that does this in two passes would be way faster, but I don't think I'll be taxing any hardware with this particular project so I'll choose for ease of use over speed for now and just add two materials to the meshrenderers. Too bad you can't disable the warning message that shows up in the inspector, but oh well. \$\endgroup\$
    – Bas
    Commented Oct 21, 2021 at 19:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .