Are these edges a result of display color accuracy, computational accuracy, or something else? I was messing with glowing lighting when I noticed an odd artifact in my first try.

For some reason I can see three defined edges inside of the glowing pattern. I downloaded the image and marked where I see the edges.


I am just curious why they appear to be there as I can see no mathematical reason why they should be there. Is it just the way I am displaying it, or is there some sort of computational precision issue? 

For reference here is the ShaderToy code that created this:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;
    float disty = abs(uv.y - 0.5);
    float distx = abs(uv.x - 0.5);
    distx *= 100.0;
    disty *= 100.0;
    fragColor = vec4(0.0, 1.0 / pow(abs((1.0 - distx) + (1.0 - disty)), 0.5), 0.0, 1.0);
}


Although I am not sure it is physically accurate to have those spikes on the edges of the diamond I sure do like the effect that creates.
Updated answer, now that pow is getting valid arguments:

What you are seeing is called "banding" and it comes from the fact that the color channels are quantized into 8 bits - in other words, it comes from the fact that there are only 256 different shades of green, even though the math generating the colors is capable of much larger resolution.

The banding on my system isn't as bad as what you are describing but it's still present.  The reason it isn't as bad on my system is because you and I have different displays.

Some computer displays don't actually even have a full 256 different shades of green.  For instance, instead of having 8 bit color, they may only have 6 bit color, and they either dither it, temporally dither it, or neither and just let it look worse.

One way to get around this problem is by dithering.  There are various algorithms for dithering, with different computation and quality trade offs.

A good modern dithering algorithm is called "interleaved gradient noise" which is fairly close to blue noise - which is the ideal - and is pretty cheap to calculate.

Check out this link for more detailed information on different types of dithering, and how they compare:

https://bartwronski.com/2016/10/30/dithering-part-three-real-world-2d-quantization-dithering/

First answer, from when pow was getting a negative value parameter:

The issue is that you are passing a negative value to pow for the first argument, which has undefined behavior.

What shows up on my screen is completely different than what shows up on yours.



You shouldn't rely on the behavior of anything in the red pixel areas in this image:



More info:

https://www.opengl.org/sdk/docs/man4/html/pow.xhtml