Drawing multiple rings with a shader

Hi, I’ve been using this shader code to animate a ring on a plane:
Shader shape function: draw a ring with alpha transparency

however I need to support multiple rings. Can someone show me how to expand this code to support an array of rings? I have all the ring data sent to the shader, just don’t know how to apply it.

This is what I have so far:

Shader"Unlit/Rippler"
{
    Properties
    {  
        _maxRings("Max Rings", int) = 0
    }

    SubShader
    {
        Tags { "RenderType"="Transparent" }
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            float4 _colours[64];
            float _centerXs[64];
            float _centerZs[64];
            float    _sizes[64];
            float    _valid[64];

            struct appdata
            {
	            float4 vertex : POSITION;
	            float2 uv : TEXCOORD0;
            };

            struct v2f
            {
	            float2 uv : TEXCOORD0;
	            float4 vertex : SV_POSITION;
	            float4 position : TEXCOORD1;
            };

            int _maxRings;

            v2f vert(appdata v)
            {
	            v2f o;
	            o.vertex = UnityObjectToClipPos(v.vertex);
	            o.position = v.vertex;
	            return o;
            }

            fixed4 frag(v2f i) : SV_Target
            { 
                fixed3 finalColor = (0, 0, 0);
                float alpha = 0;
                float soften = 0.15;
                float inner;
                if (_valid[0] == 1.0)
                {
                    inner = _sizes[0] - 0.15;
                    i.position += float4(_centerXs[0], 0, _centerZs[0], 0);
                    alpha = smoothstep(inner, inner + soften, length(i.position.xz)) - smoothstep(_sizes[0], _sizes[0] + soften, length(i.position.xz));
                    alpha *= 0.40;
                    finalColor = fixed3(_colours[0].rgb);
                }
                return fixed4(finalColor, alpha);
           }
            ENDCG
        }
   }
}

(there’s an error with the color support, but that’s not consequential at the moment)

You can use for loops in a shader. You just need some unification function to return the color of all rings combined. You can use attributes [unroll] and [loop] to indicate whether you want the loop to generate code, basically “inline” the loop body, or to use actual flow control instruction. For variable loop count you always want to use the latter. Perhaps instead of using array of _valid, you could input a number of valid circles and only loop that many times.

const int ringCount = 64; // or use _RingCount property instead of using _valid array
fixed3 finalColor = 0;

for(int i = 0; i < ringCount; ++i)
{  
  if (_valid[i] == 1.0)  // if you want to use your _valid array approach
  {
      inner = _sizes[i] - 0.15;
      i.position += float4(_centerXs[i], 0, _centerZs[i], 0);
      float ringAlpha  = smoothstep(inner, inner + soften, length(i.position.xz)) - smoothstep(_sizes[0], _sizes[0] + soften, length(i.position.xz));
      ringAlpha *= 0.40;
      float ringColor = fixed3(_colours[i].rgb);

      // somehow combine your ring color to the final color, eg.
      finalColor = lerp(finalColor, ringColor, ringAlpha);
  }
}

You could even have a variable ring count if you used a texture as the array input. Just encode your center X/Y, size and color into pixel colors and sample them in a loop.

but we are only passed one fragment to work with. Does it not require something along the lines of:

i[x].position += float4(_centerXs[x], 0, _centerZs[x], 0);