Hello ! Using the stencil buffer, I’m able to mask things outside of the renderer bounds, but it doesn’t care about the alpha inside of the bounds. Any idea about how to proceed ?
(Left : Tilemap ; Right : Blood)
Shader Code
Shader "Custom/Custom Stencil"
{
Properties
{
[PerRendererData]_MainTex("Diffuse", 2D) = "white" {}
[PerRendererData]_MaskTex("Mask", 2D) = "white" {}
[PerRendererData]_NormalMap("Normal Map", 2D) = "bump" {}
[Header(Option)]
[Enum(UnityEngine.Rendering.BlendOp)] _BlendOp("BlendOp", Float) = 0
[Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("SrcBlend", Float) = 1
[Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("DstBlend", Float) = 0
[Enum(Off, 0, On, 1)]_ZWriteMode("ZWriteMode", float) = 1
[Enum(UnityEngine.Rendering.CullMode)]_CullMode("CullMode", float) = 2
[Enum(UnityEngine.Rendering.CompareFunction)]_ZTestMode("ZTestMode", Float) = 4
[Enum(UnityEngine.Rendering.ColorWriteMask)]_ColorMask("ColorMask", Float) = 15
[Header(Stencil)]
[Enum(UnityEngine.Rendering.CompareFunction)]_StencilComp("Stencil Comparison", Float) = 8
[IntRange]_StencilWriteMask("Stencil Write Mask", Range(0,255)) = 255
[IntRange]_StencilReadMask("Stencil Read Mask", Range(0,255)) = 255
[IntRange]_Stencil("Stencil ID", Range(0,255)) = 0
[Enum(UnityEngine.Rendering.StencilOp)]_StencilPass("Stencil Pass", Float) = 0
[Enum(UnityEngine.Rendering.StencilOp)]_StencilFail("Stencil Fail", Float) = 0
[Enum(UnityEngine.Rendering.StencilOp)]_StencilZFail("Stencil ZFail", Float) = 0
// Legacy properties. They're here so that materials using this shader can gracefully fallback to the legacy sprite shader.
[HideInInspector] _Color("Tint", Color) = (1,1,1,1)
[HideInInspector] _RendererColor("RendererColor", Color) = (1,1,1,1)
[HideInInspector] _Flip("Flip", Vector) = (1,1,1,1)
[HideInInspector] _AlphaTex("External Alpha", 2D) = "white" {}
[HideInInspector] _EnableExternalAlpha("Enable External Alpha", Float) = 0
}
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
ENDHLSL
SubShader
{
Tags {
"Queue" = "Transparent"
"RenderType" = "Transparent"
"RenderPipeline" = "UniversalPipeline"
"IgnoreProjector" = "True"
"CanUseSpriteAtlas" = "True"
}
BlendOp[_BlendOp]
Blend[_SrcBlend][_DstBlend]
ZWrite[_ZWriteMode]
ZTest[_ZTestMode]
Cull[_CullMode]
ColorMask[_ColorMask]
Stencil
{
Ref[_Stencil]
Comp[_StencilComp]
ReadMask[_StencilReadMask]
WriteMask[_StencilWriteMask]
Pass[_StencilPass]
Fail[_StencilFail]
ZFail[_StencilZFail]
}
Pass
{
Tags { "LightMode" = "Universal2D" }
HLSLPROGRAM
#pragma prefer_hlslcc gles
#pragma vertex CombinedShapeLightVertex
#pragma fragment CombinedShapeLightFragment
#pragma multi_compile USE_SHAPE_LIGHT_TYPE_0 __
#pragma multi_compile USE_SHAPE_LIGHT_TYPE_1 __
#pragma multi_compile USE_SHAPE_LIGHT_TYPE_2 __
#pragma multi_compile USE_SHAPE_LIGHT_TYPE_3 __
struct Attributes
{
float3 positionOS : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
float2 lightingUV : TEXCOORD1;
};
#include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/LightingUtility.hlsl"
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
TEXTURE2D(_MaskTex);
SAMPLER(sampler_MaskTex);
TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);
half4 _MainTex_ST;
half4 _NormalMap_ST;
#if USE_SHAPE_LIGHT_TYPE_0
SHAPE_LIGHT(0)
#endif
#if USE_SHAPE_LIGHT_TYPE_1
SHAPE_LIGHT(1)
#endif
#if USE_SHAPE_LIGHT_TYPE_2
SHAPE_LIGHT(2)
#endif
#if USE_SHAPE_LIGHT_TYPE_3
SHAPE_LIGHT(3)
#endif
Varyings CombinedShapeLightVertex(Attributes v)
{
Varyings o = (Varyings)0;
o.positionCS = TransformObjectToHClip(v.positionOS);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
float4 clipVertex = o.positionCS / o.positionCS.w;
o.lightingUV = ComputeScreenPos(clipVertex).xy;
if (v.color.a < .9) o.color = 0;
else o.color = v.color;
return o;
}
#include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/CombinedShapeLightShared.hlsl"
half4 CombinedShapeLightFragment(Varyings i) : SV_Target
{
half4 main = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
if (main.z < .0078431)
{
discard;
}
half4 mask = SAMPLE_TEXTURE2D(_MaskTex, sampler_MaskTex, i.uv);
return CombinedShapeLightShared(main, mask, i.lightingUV);
}
ENDHLSL
}
Pass
{
Tags { "LightMode" = "NormalsRendering"}
HLSLPROGRAM
#pragma prefer_hlslcc gles
#pragma vertex NormalsRenderingVertex
#pragma fragment NormalsRenderingFragment
struct Attributes
{
float3 positionOS : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
float4 tangent : TANGENT;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
float3 normalWS : TEXCOORD1;
float3 tangentWS : TEXCOORD2;
float3 bitangentWS : TEXCOORD3;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
TEXTURE2D(_NormalMap);
SAMPLER(sampler_NormalMap);
float4 _NormalMap_ST; // Is this the right way to do this?
Varyings NormalsRenderingVertex(Attributes attributes)
{
Varyings o = (Varyings)0;
o.positionCS = TransformObjectToHClip(attributes.positionOS);
o.uv = TRANSFORM_TEX(attributes.uv, _NormalMap);
o.uv = attributes.uv;
if (attributes.color.a < .9) o.color = 0;
else o.color = attributes.color;
o.normalWS = TransformObjectToWorldDir(float3(0, 0, -1));
o.tangentWS = TransformObjectToWorldDir(attributes.tangent.xyz);
o.bitangentWS = cross(o.normalWS, o.tangentWS) * attributes.tangent.w;
return o;
}
#include "Packages/com.unity.render-pipelines.universal/Shaders/2D/Include/NormalsRenderingShared.hlsl"
float4 NormalsRenderingFragment(Varyings i) : SV_Target
{
float4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
if (mainTex.z < 1)
{
discard;
}
float3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, i.uv));
return NormalsRenderingShared(mainTex, normalTS, i.tangentWS.xyz, i.bitangentWS.xyz, i.normalWS.xyz);
}
ENDHLSL
}
Stencil
{
Ref 0
Comp never
}
Pass
{
Tags { "LightMode" = "UniversalForward" "Queue"="Transparent" "RenderType"="Transparent"}
HLSLPROGRAM
#pragma prefer_hlslcc gles
#pragma vertex UnlitVertex
#pragma fragment UnlitFragment
struct Attributes
{
float3 positionOS : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainTex_ST;
Varyings UnlitVertex(Attributes attributes)
{
Varyings o = (Varyings)0;
o.positionCS = TransformObjectToHClip(attributes.positionOS);
o.uv = TRANSFORM_TEX(attributes.uv, _MainTex);
o.uv = attributes.uv;
o.color = attributes.color;
return o;
}
float4 UnlitFragment(Varyings i) : SV_Target
{
float4 mainTex = i.color * SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.uv);
if (mainTex.z < 1)
{
discard;
}
return mainTex;
}
ENDHLSL
}
}
}