Hi folks. I'm having issues with transparency on my custom shaders. The set up I have is two quad-spheres at the same position but one larger than the other. The shader for the inner/smaller quad-sphere is set to render during the geometry queue and is opaque, and the shader for the outer/larger quad-sphere is set to render during the transparency queue and has alpha blending on. The issue is that parts of the outer sphere are obscured by parts of the inner sphere incorrectly and thus it doesn't render completely. I've been messing around with z-write settings but no combination seems to fix the problem. You can see a screen grab of the issue here: Does anyone know what could be causing this and how I could go about fixing it? Cheers folks
Yes its the blue bands I'm meaning. Unfortunately it's not an issue with the textures. I've tested this by making the shader non-transparent which results in a perfect sphere being drawn with all the textures for the different faces of the quad-sphere joining and aligning correctly. Also, although you cant see it in a static image, when the camera is panned around the bands shift and change as if those pixels are being clipped against some of the faces behind them. You can kind of make that out in the screen grab since at the outer edges where the inner and outer spheres dont overlap, the outer transparent sphere is drawn correctly. Its only in the inner overlapping area where strangeness happens.
Wow ... amazing spot! I think you might have hit the nail on the head there. I'm using my own custom shaders but I think the issue is possibly in how I generate the quad-sphere geometry. I started this project off by creating a texture generator for the built in skybox shader but then decided I wanted to use my own skybox geometry so I odered the geometry generation so it would fit the same layout of textures as for Unity's skybox shader. When I came to creating the quad-spheres I used the same layout again, so that's probably it. I'll have a tinker and get back to you but I think you've got it. Cheers
Wow, extremely fustrating. I thought perhaps some parts of the geometry were inverted given the strange layout but it seems to not matter at all how the faces are generated, one face of the quad-sphere will always not alpha-blend correctly. To be absolutely sure I compared a super simplified custom transparency shader with Unity's built-in transparency diffuse shader, and sure enough the Unity shader works and the custom shader always fails to blend one face but manages the others fine. For the setup for this simple test I placed a standard unity sphere with a standard diffuse shader in the middle, and a quad-sphere around it for which I swapped the custom transparency shader and Unity's transparency shader back and forth to compare the results. Unity transparency diffuse shader: Custom transparency shader: As you can see the front face fails to blend with the custom shader (the quad-sphere is made up off 6 sub-meshes, one for each face). I can only imagine I'm doing something wrong in the custom shader then but I'm not sure what it is given it's simplicity, but then again I'm not very experienced with shaders. Here's the custom shader code: Code (csharp): Shader "Test/TestShader" { Properties { } SubShader { Pass { Name "TestShader" Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } Cull Back Blend SrcAlpha One CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); return o; } half4 frag(v2f i) : COLOR { return float4(1.0, 0.0, 0.0, 0.5); } ENDCG } } FallBack "Diffuse" } Does anyone have any ideas?
To be precise, it looks like your custom shader is blending properly, but the front right face of the quadsphere is being drawn before the inner sphere. Because your custom shader writes to the Z buffer, this prevents the inner sphere from being drawn at all behind that face. If that's the case, then turning off Z writing is unlikely to solve anything because the drawing will still be out of order. It's worth trying, though, just to narrow down the problem. At the moment I have no idea why a single face would be drawing before opaque geometry when it's in the same (Transparent) render queue as the other faces.
Ok I think I solved it and it looks like I might have discovered a bug in Unity. My theory is that when using fragment shaders with multiple sub-meshes, the first sub-mesh ignores the Queue and/or RenderType tag. Therefore what's happening in my test example is that the first quad-sphere face is getting rendered before the underneath unity sphere since it's ignoring the tags, hence it doesn't seem to blend correctly. I ran a couple of tests to try and verify this. The first was to alter the camera background colour whilst the setup was running and sure enough the first quad-sphere face is varying its colour which tells me that it is indeed alpha-blending but just that the diffuse sphere hasn't been rendered behind it yet. To be totaly sure I altered the quad-sphere mesh generation code to create 7 sub-meshes instead of 6 and just left the first one empty. In that instance all the quad-sphere faces rendered and blended correctly giving the right results. Edit: Thanks for the reply and the help Daniel, managed to post at the same time . I have a theory anyway, I'll forward it to the Unity guys and see what they make of it.
Rightio, another update. I've done some more experimenting and my theory was wrong. After playing around with more geometry using the 'empty sub-mesh fix' the problem started to resurface. Therefore it seems the issue isn't only to do with the first sub-mesh, it was just a coincidence that the change in the geometry in my simple test version resulted in them being rendered in the correct order. It seems that when using custom vertex / fragment shaders its just not actualy possible to control the render order by specifying queue and renderType tags, the resultant order will always come out randomly despite what you set. After further playing around it looks like the only way to get shaders in Unity to render in the correct order for transparency is to use surface shaders instead of vertex / fragment shaders. I knocked up a simple transparent surface shader which did the same as my simple vertex / fragment transparent shader and this worked correctly without any issues in all instances. I can only imagine that the Unity engine is doing something under the hood which makes transparent surface shaders render correctly but has been neglected for vertex / fragment shaders, or vice versa, something extra is being done under the hood for fragment shaders which is stopping them from working correctly.
Can you post the simplest reproduction project possible? Although the error you're seeing is definitely there, I think it's very unlikely that vertex/fragment shaders cannot be ordered properly. Surface shaders are the recommended method for integrating Unity's lighting, but they are all converted to vertex/fragment shaders before compilation.
Cheers for the offer to take a look. I've created a simple repro case project which you can grab here: http://dl.dropbox.com/u/15008558/Unity%20Transparency%20Repro.zip Let me know what results you get Cheers. PS: You'll have to rotate the camera around in the scene view to see the effect
Your assessment that the faces are being drawn in a seemingly arbitrary order is correct, but the problem is with the Tags being in the Pass block instead of the Subshader. Tags apply to Subshaders as a whole, so I hoisting the Tags into the Subshader fixes the issue: Code (csharp): Shader "Test/TestFragmentShader" { Properties { } SubShader { Tags { "Queue" = "Transparent" "RenderType" = "Transparent" } Pass { Cull Back Blend SrcAlpha One CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; }; struct v2f { float4 pos : SV_POSITION; }; v2f vert(appdata v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); return o; } half4 frag(v2f i) : COLOR { return float4(1.0, 0.0, 0.0, 0.5); } ENDCG } } } You have found a bug, though: Unity should complain when it finds Tags where it won't respect them instead of ignoring them silently like it does.
Thanks for all your help Daniel, I don't think I would have solved this one without your input. I've just gone back over the Unity documentation and I see the mistake I've made now that you pointed out. I hadn't realised that Unity shaders accept two distinct tag blocks, one for the sub-shader and one for the passes, each of which only accept certain tags. I'd made the assumption that all the tags should be placed within the same tag block. You learn something new every day . Thanks again for your input, you've been phenomenal, an absolute star.