Glow around point in ScreenSpace

Hello, everyone!

I’m trying to write a shader for UI elements that would highlight them around given point (global shader variable) - the closer the pixel is to the screen point, the more _GlowColor is added to it.

However, I can’t get it working. This is my shader code:

ShaderCode

Shader "Custom/UI/UI - Glow around point"
{
    Properties
    {
        [PerRendererData]_MainTex("Static texture (can be empty)", 2D) = "white" {}
        _Color("Main color", Color) = (0,0,0,0)
        _GlowColor("Glow color", Color) = (0,0,0,0)
        _GlowDistance("Glow distance", float) = 5

        [Space(30)]

        _StencilComp("Stencil Comparison", Float) = 8
        _Stencil("Stencil ID", Float) = 0
        _StencilOp("Stencil Operation", Float) = 0
        _StencilWriteMask("Stencil Write Mask", Float) = 255
        _StencilReadMask("Stencil Read Mask", Float) = 255
        _ColorMask("Color Mask", Float) = 15
    }

        SubShader
    {
            Tags
        {
            "Queue" = "Transparent"
            "IgnoreProjector" = "True"
            "RenderType" = "Transparent"
            "PreviewType" = "Plane"
        }

            Stencil
        {
            Ref[_Stencil]
            Comp[_StencilComp]
            Pass[_StencilOp]
            ReadMask[_StencilReadMask]
            WriteMask[_StencilWriteMask]
        }

            ColorMask[_ColorMask]
            Cull Off
            ZWrite Off
            ZTest[unity_GUIZTestMode]
            Blend SrcAlpha One

            Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            uniform sampler2D _MainTex;
         
            uniform Vector _PointPosition;

            uniform float4 _MainTex_ST;
            uniform float4 _Color;
            uniform float4 _GlowColor;

            uniform float _GlowDistance;

            uniform float _GlowIntensity;

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

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

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

                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {

                fixed4 color = _Color * tex2D(_MainTex, i.uv*_MainTex_ST)*i.color;

                float dist = distance(_PointPosition, i.vertex) / _GlowDistance;

                color.rgb += (_GlowColor*_GlowIntensity) / dist;

                return color;
            }
            ENDCG
        }
    }
        Fallback "Mobile/VertexLit"
}

And in a test script that is attached to a point I do this, to get the coordinates of the point game object:

    void Update () {
        Vector4 screenPos = Camera.main.WorldToScreenPoint((gameObject.transform.position));
        Shader.SetGlobalVector("_PointPosition", screenPos);
        Shader.SetGlobalFloat("_GlowIntensity", (Mathf.Sin((Mathf.PI*Time.time))+1)*0.5f);

        Debug.Log("target is " + screenPos.x + " pixels from the left");
        Debug.Log("target is " + screenPos.y + " pixels from the bottom");
    }

Everything seems to work, but for some reason the y coordinate of screen gets mirrored around the screen center… I can’t figure out why for few hours already, so I’m asking for help: what am I missing? Here’s a video of what’s happening: Monosnap

1 Like

This looks totally like the case, but for some reason, flipping y-uv-coordinate doesn’t change anything as well as y-vertex coordinate. What fixed my issue was flipping points Y coordinate:

 var pos = gameObject.transform.position;
        pos.y *= -1;
        Vector4 screenPos = Camera.main. WorldToScreenPoint((pos));
        Shader.SetGlobalVector("_PointPosition", screenPos);

Is it a platform-specific dependency? Doesn’t look like that…
And it wasn’t working if I flipped that coordinate inside shader…