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.


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\$ – Thomas A. Bosler Apr 4 '19 at 2:34
  • \$\begingroup\$ So you tried using the SetTextureOffset method as instructed above, right? \$\endgroup\$ – DMGregory Apr 4 '19 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\$ – Thomas A. Bosler Apr 4 '19 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 Apr 4 '19 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\$ – Thomas A. Bosler Apr 4 '19 at 2:50

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.