WebGL: Loop index cannot be compared with non-constant expression

This happens because on some hardware, GLSL loops are un-rolled into native GPU instructions. This means there needs to be a hard upper limit to the number of passes through the for loop, that governs how many copies of the loop's inner code will be generated. If you replace numBlurPixelsPerSide with a const float or even a #define directive, and the shader compiler can then determine the number of passes at compile time, and generate the code accordingly. But with a uniform there, the upper limit is not known at compile time.

There's an interesting wrinkle in this rule: You're allowed to break or call an early return out of a for loop, even though the max iterations must be discernible at compile time. For example, consider this tiny Mandelbrot shader. This is hardly the prettiest fractal on GLSL Sandbox, but I chose it for its small size:

precision mediump float;
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
varying vec2 surfacePosition;

const float max_its = 100.;

float mandelbrot(vec2 z){
    vec2 c = z;
    for(float i=0.;i<max_its;i++){     // for loop is here.
        if(dot(z,z)>4.) return i;      // conditional early return here.
        z = vec2(z.x*z.x-z.y*z.y,2.*z.x*z.y)+c;
    }
    return max_its;
}


void main( void ) {
    vec2 p = surfacePosition;
    gl_FragColor = vec4(mandelbrot(p)/max_its);
}

In this example, max_its is a const so the compiler knows the upper limit and can un-roll this loop if it needs to. Inside the loop, a return statement offers a way to leave the loop early for pixels that are outside of the Mandelbrot set.

You still don't want to set the max iterations too high, as this can produce a lot of GPU instructions and possibly hurt performance.


Sometimes you can use my very simple solving of issue.

My fragment of the shader source code:

const int cloudPointsWidth = %s;
for ( int i = 0; i < cloudPointsWidth; i++ ) {
   //TO DO something
}

You can see '%' : syntax error above. But I am replace %s to a number in my javascript code before use my shader. For example:

vertexCode = vertexCode.replace( '%s', 10 );

vertexCode is my shader source code.

Everytime if I want to change cloudPointsWidth, I am destroying my old shader and creating new shader with new cloudPointsWidth .

Hope sometimes my solving can to help you.


Try something like this:

const float MAX_ITERATIONS = 100.0;

// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= MAX_ITERATIONS; i += 1.0) { 
    if (i >= numBlurPixelsPerSide){break;}
    avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;         
    avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;         
    coefficientSum += 2.0 * incrementalGaussian.x;
    incrementalGaussian.xy *= incrementalGaussian.yz;
}

Tags:

Glsl

Webgl