How do you render points as circles rather than squares?

Currently I have a script that I attach to a parent mesh object that essentially runs the mesh.topology command and sets the mesh to points at run time. The points show up as squares (planes, not cubes) that are “view-plane” aligned horizontally not vertically. I looked at the HLSL Microsoft docs,and it makes sense as to why they’re showing up as squares. How would I render them as circles (or spheres), rather than squares?

I also have a basic shader attached to the meshes that colors the points by vertex (the imported models have per vertex colors). I’m feeling like this is a shader question based on the research I’ve done so far, so I can add a solution to my existing one if need be.

The only thing reasonable answer I figured out was to use a geometry shader to render a billboard quad at each vertex with a texture. The texture was a square image, with a circle in the middle, and alpha values around it. It works but the performance is poor, and there is weird behavior where I can actually see the outline of the quad off-axis where it is supposed to be transparent. I will try to post images to demonstrate the behavior.

I’ve also tried to render points as circles. I used the VPOS semantics, which is similar to gl_Fragcoord in my understanding: Unity - Manual: Shader semantics

Here is a snippet of the shader I’m using:

        // It's hard to have both the SV_POSITION and VPOS in the same vertex-to-fragment structure.
        // So the vertex shader outputS the SV_POSITION as a separate “out” variable.
        v2f vert(appdata v, out float4 vertex : SV_POSITION)
        {
            v2f o;
            vertex = UnityObjectToClipPos(v.vertex);
            o.center = ComputeScreenPos(vertex);
            o.size = _PointSize;

            return o;
        }

        // vpos contains the integer coordinates of the current pixel, which is used
        // to caculate the distance between current pixel and center of the point.
        fixed4 frag(v2f i, UNITY_VPOS_TYPE vpos : VPOS) : SV_Target
        {
            float4 center = i.center;

            // Converts center.xy into [0,1] range then mutiplies them with screen size.
            center.xy /= center.w;
            center.x *= _ScreenWidth;
            center.y *= _ScreenHeight;

            float dis = distance(vpos.xy, center.xy);
            if (dis > _PointSize / 2)
            {
                discard;
            }

            return _Color;
        }