This article will demo the shader I used in Curse of the Pinyaata (2022). It's a VR game where the player is blindfolded, and has to use echolocation to find their way around the level. They can slam their baseball bat around the level to send out echolocation ping sweeps to get brief glimpses of the level, and must break as many things as they can in 2 minutes.
This was originally a Twitter thread from March 2022, back when the site was better. I've copied the contents here with some alterations, mainly formatting.
The main concept is to create a signed distance field (SDF) to mask out a repeating pattern of rings around a point in world space. From here, we ignore all texels any further than the distance of the first ring. Then, we apply color to the whole mask.
In case you need a refresher about masks - we can multiply some color (or texture) against the mask, and only the white part will take on that color/texture. Here, the mask has a value in the range of [0, 1], where the values represent a gradient from black to white.
So let's start with making the SDF.
First, we'll create a mask that represents the distance from a point in world space. The ring distance represents the distance that the rings have traveled from the origin.

Now let's add the module operator to make the rings.
We can adjust the modulo denominator (ringSize) to play with the density of the rings. Notice how the rings behave when we increase the ringDistance value - there's a big hole in our mask!

Note that I've also put in a parameter for ring size here, both as an addition to the "distance from ping origin", and as input to the modulo node. This increases the value of the mask across the board, effectively increasing the area the mask covers.
We only want to keep this first ring in our mask.
Let's add a comparison node that tests if a texel's distance from the origin point is greater than the current ring distance. If true, return a value of 0. This essentially discards the texel from our mask.

Now that our mask is complete, we apply color via the multiply node. I'm also using the saturate node here to clamp the mask's value between 0 and 1, to make sure our colors look as expected along the edge of the ring.

I also use the alpha of the color as a way to dampen the color, using the multiply node.
The muted color palette is much less jarring in VR, especially with how these rings pop out suddenly in Curse of the Pinyaata.

And that's the main concept! From here, you would create a subgraph for each ring that your shader can support, and add them all together in a parent graph.
(You'll need unique variables for each ring, representing the position source, distance, and color)

Note that there's other ways to combine these rings. You probably want to saturate the final result before outputting it (I forgot that part!). You may also find it better to lerp the colors together, which would make the rings overlap instead of mixing their colors.
Here's a pair of screenshots for the final shader. The first screenshot represents a single ring, and is a subgraph. The second screenshot represents the actual shader, and contains a handful of instances of the subgraph.


There's a few other things I added to the shader that are worth mentioning.
Between this, and the flat ringSize addition, we have fine control over the size of the ring's gradient, and hard-edge border.

For Curse of the Pinyaata, this meant transitioning from regular gameplay to blindfolded gameplay.
To make this happen, I lerped between a texture map and a flat color, based on the alpha channel of my base color.

As an aside, since I used an asset pack for my models, all of the models in the pack shared the same texture map, which was super convenient. This meant only having to update one material instance in my "ping manager" script.
I did this by outputting no color if the ringColor's alpha channel had a value of 0. The parameters of my material were updated dynamically via a C# script, so this made it easy to cut down on unnecessary processing

I added that optimization because I was worried that supporting too many rings in my shader would be very GPU intensive - especially for a game where most of the screen is grey.
I ended up supporting an arbitrary # of 6 rings, although it could have been bumped up quite a bit
I didn't see my GPU struggle via the frame inspector, but I'm also running a 2070. For such a simple game (low-poly assets, most of the scene being a flat color most of the time) - it would be reasonable to expect this to run on a standalone headset.
Overall the shader worked as expected. It performs well on desktop, and I suspect it also would on mobile headsets, although I don't have one that I could confirm that with.
I think if I were to reuse this, I would try to get it working as render passes, instead of a material that has to be assigned to every mesh in the scene. This was just something that I unfortunately didn't have enough time to get working
Anyways, that's all from me! You can play Curse of the Pinyaata on any SteamVR compatible headset for free here.