enter image description here

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.


1 Answer 1


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"
        _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)
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
            "PreviewType" = "Plane"
            "CanUseSpriteAtlas" = "True"

        Cull Off
        Lighting Off
        ZWrite Off
        Blend One OneMinusSrcAlpha

            #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;

This imitates the standard sprite shader, but adds an "Overlay" texture field you can assign in the material inspector for your black zigzag.

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.

  • \$\begingroup\$ 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 \$\endgroup\$ Commented Apr 4, 2019 at 2:34
  • \$\begingroup\$ So you tried using the SetTextureOffset method as instructed above, right? \$\endgroup\$
    – DMGregory
    Commented Apr 4, 2019 at 2:36
  • \$\begingroup\$ 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 \$\endgroup\$ Commented Apr 4, 2019 at 2:42
  • \$\begingroup\$ 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. \$\endgroup\$
    – DMGregory
    Commented Apr 4, 2019 at 2:44
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Apr 4, 2019 at 2:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .