I am making a Klondike Solitaire game, with the intent of later expanding it to encompass other solitaire games and allow deck customization. As part of this, the playing card meshes I am creating programatically are mostly opaque, but require non-alphatest transparency in order to draw the pips (rank/suit icons) correctly.
The problem is this:
The z-sorting of the cards is the exact opposite of what it's supposed to be. I know that transparency is the problem because the z-sorting works properly when it's disabled (the #pragma alpha:fade
in the shader is removed):
...which obviously breaks how the cards' material is being rendered.
This is the shader I have:
Shader "Custom/Card" {
Properties {
_CardAtlasTex ("Card Atlas", 2D) = "white" {} // card atlas texture
_ColorUVZone ("Colour UV Zone", Vector) = (0,0,0,0) // texture zone inside which the pips are, and so the suit colour should be used
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert vertex:vert alpha:fade
sampler2D _CardAtlasTex;
float4 _ColorUVZone;
struct Input {
float2 uv_CardAtlasTex;
float3 vertexColor;
};
void vert (inout appdata_full v, out Input o) { // http://answers.unity3d.com/questions/923726/unity-5-standard-shader-support-for-vertex-colors.html
UNITY_INITIALIZE_OUTPUT(Input,o);
o.vertexColor = v.color;
}
void surf (Input IN, inout SurfaceOutput o) {
half4 card = tex2D (_CardAtlasTex, IN.uv_CardAtlasTex);
o.Albedo = card;
o.Alpha = 1; // make it opaque to start with
// if this is a pip, colourize it
if (IN.uv_CardAtlasTex.x >= _ColorUVZone.x && IN.uv_CardAtlasTex.y >= _ColorUVZone.y && IN.uv_CardAtlasTex.x <= _ColorUVZone.z && IN.uv_CardAtlasTex.y <= _ColorUVZone.w) {
o.Albedo *= IN.vertexColor; // colourized
o.Alpha = card.a; // transparented
}
}
ENDCG
}
FallBack "Diffuse"
}
Things I have tried:
- Changing the subshader's
RenderType
to things likeTransparent
orTransparentCutout
, or removing it entirely. No effect. - Changing the subshader's
Queue
to things likeTransparent
orAlphaTest
, or removing it entirely. No effect. - Adding a
ZWrite On
(just before theLOD 200
). Does nothing because the generated code forcesZWrite Off
due to having#pragma alpha:fade
(as far as I can tell), and putting the line after the pragma in hopes of re-overwriting it is a syntax error.
From #3, I'm guessing that if I can somehow force ZWrite On
despite the alpha:fade
, it should work as expected. But chances are there's something else I'm missing that could work.
Other notes:
- The problem is very consistent: the back-most cards are always drawn front-most, no matter what the shuffle is or whether the lower cards are ahead or behind.
- There is no alternative to using full transparency; pips can be any colour against any background. (The face card designs don't use transparency.)
- All cards use the same material, which uses a single texture atlas.
Answer
After doing some tests, it looks like this may be a bug in a recent version of Unity.
When you create a new material, under the hood its Custom Render Queue
property defaults to -1, meaning "use whatever queue is specified in the shader file," as we would expect.
But as soon as we change the material's shader to use a custom one (I've now tried this with newly-created Surface and Unlit shaders), Unity sets the Custom Render Queue
to 2000, meaning "ignore what the shader says and always render this in the opaque geometry queue"
That seems blatantly wrong, so I expect they'll fix that. In the meantime, as Toomai discovered in the comments above, we can fix this by...
- Switch the Inspector to Debug mode by opening the hamburger menu (≡) in the top-right corner and selecting "Debug"
- Replace the 2000 in the
Custom Render Queue
field with -1 instead
Your shader's queue settings should now be respected again.
No comments:
Post a Comment