Character selection circle over the ground but under anything else

Hi!

I’m trying to draw a circle around a character if it is selected. I have got a ground mesh, some character, trees, rocks, etc. The circle should be drawn over the ground, but under everything else. Currently the circle object is a plane with a transparent circle texture, and it is works great with a flat ground. But if the ground isn’t flat, sometimes near a rise half of the circle is covered by it, like on the first screenshot.

What I have tried so far:

  • Draw the circle with projector, it works, but i don’t want it to follow the ground’s geometry.
  • Multiple cameras with layers and culling masks set up: first layer is for the ground, the second is for the circle, and the third is for everything else. This way the circle was rendered correctly, but ground could not receive shadows because it was rendered by a different camera than the shadow casters.
  • Custom shader (I don’t know anything about shader programming btw) to the ground with “Queue” = “Geometry-10” tag. It did nont changed anything, the result was zhe same as on the first screenshot.

What it should looks like (edited screenshot):

How could i achive this?

Most common way is to just raise the circle up a little.

A more complex way is to use stencils. You’ll need a customized material for your character (or anything you want to render above) that writes to the stencil, and your ground circle needs to use a shader that reads the stencil and won’t render there.

A slightly less complex way is similar to what you were doing with the queues, but you can actually do this without as many custom shaders. You’ll want to set the custom queue on the characters’ materials to be geometry+2 (or 2002). Then your circle needs to have “Queue”=“Geometry+1” and ZTest Always. This will cause it to render after the terrain / other ground geometry and always render. Then then the characters and anything else will render after that. You can set custom queues on materials using the debug inspector; right click on the inspector tab and select debug.

Thank you for your reply.

I tried raise the circle up a little already, but sometimes it get covered there too.

Now i’m trying to solve the problem with the custom render queue method you suggested. Changed it in the inspector to 2001 to the circle and 2002 to the character. The problem is transparency and ZTest always does not work together well.

The result with no alpha & no ZTest always

No alpha but ZTest always (this is what i want, but with transparency)

Alpha & ZTest always

As you can see, when i enable alpha in the shader, it looks like the custom render queue value is not used.

Here is my shader:

Shader "Custom/Circle" {
    Properties{
        _MainTex("Texture", 2D) = "white" {}
    }
       
    SubShader{
        Tags{"Queue" = "Geometry+1" }

        ZTest always

        CGPROGRAM
        #pragma surface surf Lambert alpha

        struct Input {
            float2 uv_MainTex;
        };
        sampler2D _MainTex;

        void surf(Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
            o.Alpha = tex2D(_MainTex, IN.uv_MainTex).a;
        }
        ENDCG
    }
       
    Fallback "Diffuse"
}

I switch transparency on and off by add / remove “alpha” to #pragma surface.

That’s because setting “alpha” in the #pragma line does some extra stuff. Try using “keepalpha” and add “Blend SrcAlpha OneMinusSrcAlpha” just below tags, or don’t use a surface shader.

Now my shader looks like this:

Shader "Custom/Circle" {
    Properties{
        _MainTex("Texture", 2D) = "white" {}
    }
       
    SubShader{
        Tags{"Queue" = "Geometry+1" }
        Blend SrcAlpha OneMinusSrcAlpha
        ZTest always

        CGPROGRAM
        #pragma surface surf Lambert keepalpha

        struct Input {
            float2 uv_MainTex;
        };
        sampler2D _MainTex;

        void surf(Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
            o.Alpha = tex2D(_MainTex, IN.uv_MainTex).a;
        }
        ENDCG
    }
       
    Fallback "Diffuse"
}

This way the transparency doesn’t work, the result is the same as the middle screenshot from my previous post (No alpha but ZTest always).

Right … yeah, you’ll want to use a non-surface shader. Forgot that doesn’t work.

You should try using the Unlit-Alpha.shader included in the shader source as your starting point.

I changed my shader to this:

Shader "Custom/Circle" {
    Properties{
        _MainTex("Base (RGB) Trans (A)", 2D) = "white" {}
    }

        SubShader{
        Tags{ "Queue" = "Geometry+1" "IgnoreProjector" = "True" }
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite Off
        ZTest always

        Pass{
        Lighting Off
        SetTexture[_MainTex]{ combine texture }
    }
    }
}

Now transparency works, but the circle is rendered over everything, like the third picture previously :frowning:

It’s working now, looks like it’s wrong in the scene view, but ok in the game. My final settings: render queue is set to 1990 for ground’s material (still from the inspector), 1995 to to circle, everything else is at default. The shader:

Shader "Custom/Circle" {
    Properties{
        _Color("Color Tint", Color) = (1,1,1,1)
        _MainTex("Base (RGB) Trans (A)", 2D) = "white" {}
    }

    SubShader{
        Tags{ "Queue" = "Geometry+1" "IgnoreProjector" = "True" }

       
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite Off
        ZTest always

        Pass{
            Lighting Off
            SetTexture[_MainTex]
            {
                ConstantColor[_Color]
                Combine Texture * constant
            }
        }
    }
}

Thanks a lot for your help.