Show Sprites on Overlap (Shader Graph) [2D]

I have a character sprite mesh and mesh renderer (The black wavy box). I am hoping to be able to overlay the black box onto the character covering the sprites but I am not sure how to do that.

I looked at this question : Unity: How do I only show parts of objects that overlap [2D]

But this works more as a cover that you can see through. I am hoping to have the variable black mask the sprites of the character but I cant seem to layer these correctly. Is there a way to do this using the LWRP and shader graph?

The over arching idea is to use this as a damage marker. Moving the black box up or down depending on the health lost.

This is a little trickier to achieve than it looks, because each part of a sprite - by the time it reaches the GPU - is just a lone triangle that knows nothing about the other triangles in the scene, including the positions & sizes of other sprites.

So, we have to fake it a little. We can assign a new material to our sprite renderers for the character's sprite(s) (this will also work if you have a multi sprite character like a Spine / Puppet 2D animated character), using a shader like the one below:

Shader "Unlit/WorldspaceBlend"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
// Add a texture field for our overlay image.
_Overlay("Overlay", 2D) = "white" {}
_Color("Tint", Color) = (1,1,1,1)
}
{
// Duplicate normal sprite shader behaviours.
// (I skipped implementing pixel snap / split alpha though)
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}

Cull Off
Lighting Off
ZWrite Off
Blend One OneMinusSrcAlpha

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

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

struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
float2 uv : TEXCOORD0;
float2 overlayUV : TEXCOORD1;
};

sampler2D _MainTex;
float4 _MainTex_ST;

fixed4 _Color;

// Allow sampling from the overlay image.
sampler2D _Overlay;
float4 _Overlay_ST;

v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.color = v.color * _Color;

// Compute what part of the overlay image we should sample.
float2 worldPos = mul(unity_ObjectToWorld, v.vertex).xy;
o.overlayUV = (worldPos - _Overlay_ST.zw)/_Overlay_ST.xy;

return o;
}

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv) * i.color;

// Sample our overlay image.
fixed4 overlay = tex2D(_Overlay, i.overlayUV);
// Blend it with our base image.
fixed4 output = lerp(col, overlay, overlay.a);
output.a = col.a;
// Convert to pre-multiplied alpha, as used by sprite shaders.
output.rgb *= output.a;

return output;
}
ENDCG
}
}
}


The material's scaling & transform parameters for this texture will determine how large & where it's drawn in worldspace. So, you'll want to add a script that sets the following each frame:

Vector4 overlayAlignment = character.transform.position + overlayOffset;

material.SetTextureOffset("_Overlay", overlayAlignment);


You can then vary the overlayOffset vector to slide your overlay texture around relative to the character's position.

• I think this is close to what I was hoping. The overlay works correctly as in I can set the overlay to a different sprite and move the Game object around and it is obscuring the main sprite with the overlay. I am having issues though adjusting the overlay. Right now it takes up one square on the screen with its edges protruding outward. I also coded the overlay script and adjusting it makes no change. I may be using it incorrectly. I also wondered if instead of using a texture for the overlay I code use a different mat. I was hoping to dynamically change the overlay textures position – Thomas A. Bosler Apr 4 '19 at 2:34
• So you tried using the SetTextureOffset method as instructed above, right? – DMGregory Apr 4 '19 at 2:36
• I believe so. I have: ' void Start() { mat = GetComponent<Renderer>().material; } void Update() { Vector4 overlayAlignment = gameObject.transform.position + overlayOffset; mat.SetTextureOffset("_Overlay", overlayAlignment); }' The over lap looks as follows and adjusting the offset doesn't effect it. imgur.com/a/oN3b340 – Thomas A. Bosler Apr 4 '19 at 2:42
• And you don't observe that to be changing the overlay's position? It's hard for us to diagnose the issue if you don't describe the symptoms in full. – DMGregory Apr 4 '19 at 2:44
• Sorry if I am not being clear. Adjusting the Offset does not move or change the overlay at all. And the overlay looks strange. I edited the above comment and added a photo. – Thomas A. Bosler Apr 4 '19 at 2:50