0
\$\begingroup\$

I've a very sipmle Unity scene.

It has two objects in it, which is Sprites, and they both use sipmle black boxes as a textures.

Here's two shaders, one should act as a mask, and second as a object, that should be rendered only in pixels, specified by that mask.

Mask shader:

Shader "Unlit/StencilUnlitShader"
{
Properties
{
    _MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
    Tags { "RenderType"="Opaque"
    "Queue" = "Geometry" }

    Pass
    {
        //AlphaTest Greater 0.5 //Only render pixels whose alpha is greater than AlphaValue.
        Stencil{
        Ref 2
        Comp Never//Never - never pass the stencil test, Always - always pass the stencil test
        Pass Replace //write Ref value into the stencil buufer
        }

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

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
        };

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
        };

        sampler2D _MainTex;
        float4 _MainTex_ST;

        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = TRANSFORM_TEX(v.uv, _MainTex);
            return o;
        }

        fixed4 frag (v2f i) : SV_Target
        {
            // sample the texture
            fixed4 col = tex2D(_MainTex, i.uv);
            //if (col.a < 0.9) discard; //discard a pixel if it's transparent and don't draw it into a buffer
            return col;
        }
        ENDCG
    }
}
}

Object shader:

Shader "Unlit/GreenUnlitShader"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
    }
        SubShader
    {
        Tags{ "RenderType" = "Opaque"
              "Queue" = "Geometry+5" //to draw after stencil object
    }

        Pass
        {
        //AlphaTest Less 0.5
        Stencil{
        Ref 1
        Comp Less //Always, Less - if ref value is greater then current value in the stencil buffer
        Pass Keep
        }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

    struct appdata
    {
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };

    struct v2f
    {
        float2 uv : TEXCOORD0;
        float4 vertex : SV_POSITION;
    };

    sampler2D _MainTex;
    float4 _MainTex_ST;

    v2f vert(appdata v)
    {
        v2f o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = TRANSFORM_TEX(v.uv, _MainTex);
        return o;
    }

    fixed4 frag(v2f i) : SV_Target
    {
        fixed4 col = tex2D(_MainTex, i.uv);//fixed4(0,1,0.5,0.6);
        //if (col.a < 0.9) discard;
        return col;
    }
ENDCG
    }
    }
}

The problem is, this doesn't seem to work, and object doesn't seems to be rendered at all (why it should in the places where mask have it's pixels)

\$\endgroup\$
2
\$\begingroup\$

In your mask shader, change comp never to comp always.

You never write to the stencil because the comp fails.

\$\endgroup\$
  • \$\begingroup\$ Shouldn't parameter "Pass" specify if I write or ignore writing to stencil buffer? \$\endgroup\$ – PaulD May 17 '17 at 13:21
  • 1
    \$\begingroup\$ Pass only applies when the previous tests succeed. From unity's documentation: "(Pass) What to do with the contents of the buffer if the stencil test (and the depth test) passes. Default: keep." \$\endgroup\$ – Zebraman May 17 '17 at 13:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.