Resolve overextended star rays in fragment shader (with aspect ratio)

I am trying to replicate the Art of Code’s shader tutorial. I’m trying to draw the shader on a plane geometry with a shader material.

The problem I have is that the star rays are not being cutoff when needed. Instead, they extend up until they reach the edges of the plane (background) either on x-axis, or on y-axis, or in both directions. However, when I slowly resize the window, sometimes, the star rays are cutoff as intended. I tried hardcoding the aspect ratio uniform in frag because I thought the aspect ratio was the culprit but it didn’t help. To be honest, I am out of ideas why this might be happening so I would appreciate any help.

Current result:

Result I want:


As an option, in the fragment.glsl:

    float rays = max(0.0, 1.0 - abs( centeredUv.x * centeredUv.y * 2000.0));
    rays *= smoothstep(0.25, 0., length(centeredUv)); // added line
    color += rays;

produces this:


To answer this specific question see this code:

float rays = max(0.0, 1.0 - abs( centeredUv.x * centeredUv.y * 2000.0));

The pixels for the rays have uv.x=0 or uv.y=0; so the result will always be rays=1. Cases that appear to work are, most likely, for special sizes of the canvas, when there is no screen pixel with uv coordinates (0,0) – for example, if the resolution is an even number, there is no middle pixel.

1 Like

Thanks, that clears it up for me a little.
I was wondering why 1920x969 was showing a horizontal line while 1506x750 worked perfectly.
It still bugs me that the same code worked well on ShaderToy.

I apologize. I thought I had it but then I didn’t. Does it mean that I need to ensure that the uv is always divisible by 2?
Also, I liked the smoothstep solution but it seems to have the same problem when resized. In the pic below, the rays are uneven. The resolution is 781x352.

My suggestion is to use screen coordinates, not NDC. Here is how the main function may look like:

void main() {
    vec2 centeredUv = (vUv - 0.5) * uAspectRatio; 
    centeredUv *= 3.0;

    vec3 color = vec3(0);

    float distanceToCenter = length(centeredUv);
    float circle = 0.02  / distanceToCenter;
    color += circle;

    // added section for the rays
    bool horz = floor(gl_FragCoord.x)==floor(uResolution.x/2.0);
    bool vert = floor(gl_FragCoord.y)==floor(uResolution.y/2.0);
    if( horz || vert ) color += max( 0.0, 1.0-2.0*distanceToCenter );

    gl_FragColor = vec4(color, 1.0);
1 Like