I’ve just started getting into Shaders, so I’m a bit new to this.
I’m working in 2D mode, with a Camera set as Orthographic, and a spot light to give me light.
I have a mesh that I’ve created in code that is like the attached picture, its just a square which is split into smaller squares (with 2 triangles each) which I then tile an image on each square from a material ‘atlas’ using the UVs. This all works fine.
I also have in the mesh another 2 triangles that I put on top of the top right square, but with an Z of -1, so that it is in front of the other square. I’m basically trying to ‘overlay’ it, and make the transparency work.
From reading other posts, I read that I needed to turn on ZWrite so that the shader processes the depth of the mesh, which I have done.
The code below seems to work in the editor as you can see in the picture (on the left), but when I run it (on the right), it seems to render the transparent pixels as black.
Can anyone tell me what I’m doing wrong in the shader, and how to get the 2 extra triangles to be infront of the other ones?
Well, I’ve not been able to find a solution to this
The problem seems to only happen if you use a SpotLight on the Mesh. A Directional Light works fine.
But that doesnt help me, as I need to use Spots.
I can only presume this is some Unity bug?
I had 2 workarounds, 1 was to do 2 passes, where one pass does the pixels that had a Z of 0, and then another pass for the pixels that had a Z of -1… it then rendered correctly.
The other idea, was to have 2 separate meshes, ontop of each other back in Unity, and use SortOrder to make them display ontop of each other, with no special Shader changes.
Both these work, but obviously have performance impacts of either more passes or more DrawCalls. And, the 2 pass shader was going to have to do even more passes as I wanted a 3rd and maybe 4th layer (Z level) also.
So, I guess its currently not possible to have a mesh with overlapping triangles, transparency, and light them correctly, using just shaders.
Z-depth can’t really be used with transparency. That’s a general thing. The z-buffer only maintains 1 depth value for each pixel, which works fine for opaque objects. With transparency you have to make sure the render order is back to front. You usually do this by changing the render queue of the shader or material.
In your case I understand the front and back are together in one mesh. Then the good news is that nothiing changes the order of the triangles. So if you make sure the triangles in the back have a lower index than the triangles in the front, you should get the result you want. They are simply rendered in the order they are in.
Not a bug, just an artifact of how Unity current does forward lighting. If you have multiple lights in your scene Unity renders anything after the first (brightest) directional light as additional additive render passes of the mesh.
This works fine with opaque objects as the fact they write to z allows all passes to properly sort. With transparency this causes issues with overlapping parts of a single mesh where either you get black areas, like you’re seeing, or you only see one layer at a time, or things look like they’re rendered in the wrong order or too transparent.
There are two solutions. The first one, and this is the “Unity way”, is to break up the model and render them separately. This sucks for the obvious reason of additional draw calls. The second is to render all lights in a single pass.
For Unity by default the only way to do that second option is to use vertex lit shaders. Otherwise you need to completely replace Unity’s lighting system, ala Valve’s The Lab Renderer. In some future version of Unity they’ll be introducing a new render path that does all lighting in a single pass and this will stop being a problem.