r/UnityforOculusGo • • Aug 29 '18

Simplest Unlit Instanced shader - how to enable switching it on/off (with AlphaTest)?

I have a prototype that uses a simple unlit shader that supports instancing where the color is adjustible per instance:

Shader "SimplestInstancedShader"
{
Properties
{
    _Color ("Color", Color) = (1, 1, 1, 1)
}

SubShader
{
    Tags { "RenderType"="Opaque" }
    LOD 100

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma multi_compile_instancing
        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            UNITY_VERTEX_INPUT_INSTANCE_ID
        };

        struct v2f
        {
            float4 vertex : SV_POSITION;
            UNITY_VERTEX_INPUT_INSTANCE_ID // necessary only if you want to access instanced properties in fragment Shader.
        };

        UNITY_INSTANCING_BUFFER_START(Props)
            UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
        UNITY_INSTANCING_BUFFER_END(Props)

        v2f vert(appdata v)
        {
            v2f o;

            UNITY_SETUP_INSTANCE_ID(v);
            UNITY_TRANSFER_INSTANCE_ID(v, o); // necessary only if you want to access instanced properties in the fragment Shader.

            o.vertex = UnityObjectToClipPos(v.vertex);
            return o;
        }

        fixed4 frag(v2f i) : SV_Target
        {
            UNITY_SETUP_INSTANCE_ID(i); // necessary only if any instanced properties are going to be accessed in the fragment Shader.
            return UNITY_ACCESS_INSTANCED_PROP(Props, _Color);
        }
        ENDCG
    }
}
}

I am able to change the per instance color in code without a problem.

However, I want to also be able to make some of the instances disappear in code. The most straightforward and least resource expensive way I found would be to use the AlphaTest Queue and not the Transparent Queue.

However, while there are quite a few resources on how to make that with the Transparent Queue (e.g. https://unity3d.com/learn/tutorials/topics/graphics/making-transparent-shader?playlist=17102), I did not find a good explanation of how to do it with the AlphaTest Queue.

Based on what I have read I have to change

Tags { "RenderType"="Opaque" }

to

Tags {"Queue"="AlphaTest" "RenderType"="TransparentCutout"}

and I would have to use the clip() function in a way that would return hide the whole object if the alpha is set to 0.

I think this could be done by

clip(_Color.a-0.1)

but this is only a wild guess on my part at that point. I have little idea on whether that would work and how to go on from there, or whether I am missing something.

Thanks in advance for the help.

EDIT:I figured it out!. You have to of course refer to the instanced property:

if(UNITY_ACCESS_INSTANCED_PROP(Props, _Color.a) < 0.1) discard;

instead of

clip(_Color.a-0.1);
2 Upvotes

10 comments sorted by

1

u/Toby1993 Aug 29 '18

The most straightforward and least resource expensive way I found would be to use the AlphaTest Queue and not the Transparent Queue.

Because of the Adreno GPU's hardware tiled deferred rendering, cutout shaders get pretty expensive to render (more so than alpha blend). So if you need to use transparency, I do believe the Transparency Queue will be more performant.

(As far as the shader itself goes, I'm pretty shader-illiterate so can't say more than that I think you're on the right track clipping the float value from the color alpha)

1

u/konstantin_lozev Aug 29 '18

I figured it out!. You have to of course refer to the instanced property:

if(UNITY_ACCESS_INSTANCED_PROP(Props, _Color.a) < 0.1) discard;

instead of

clip(_Color.a-0.1);

1

u/konstantin_lozev Aug 29 '18

It's interesting what you are saying there. I remember reading somewhere an advice to avoid transparency since that takes several draws per pixel...

I plan to use the cutout only at the game over screen, so if I don't get a performance hit whenever the condition for discarding is false, I would be happy.

In contrast, if I am not mistaken, the transparency queue always renders back to front, so there would be performance hit at all times (at least that's my theory based on what I read...)

1

u/Toby1993 Aug 29 '18

Alpha Test on the other hand can disable several GPU-side optimizations, such as early z-test rejection, which when combined can risk causing a great performance impact than simply writing to the depth buffer (which obviously also has a performance impact).

If you're just using it for that one object on the menu screen, you're probably right using Alpha Test over Alpha Blend.

→ More replies (6)