Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am trying to pass an array of vec3 as uniform and then iterate through them on each pixel. The size of array varies on situations so I can't make the loop with constant number of iterations.

Here is the code:

precision highp float;
precision highp int;

varying vec4 v_fragmentColor;

varying vec4 v_pos;

uniform int u_numberOfParticles;

const int numberOfAccumsToCapture = 3;
const float threshold = 0.15;              
const float gooCoeff = 1.19;

uniform mat4 u_MVPMatrix;
uniform vec3 u_waterVertices[100];

void main()
{
    vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);

    vec2 currPos = v_pos.xy;

    float accum = 0.0;
    vec3 normal = vec3(0, 0, 0);

    for ( int i = 0; i < u_numberOfParticles; ++i )
    {
        vec2 dir2 = u_waterVertices[i].xy - currPos.xy;
        vec3 dir3 = vec3(dir2, 0.1);
        float q = dot(dir2, dir2);

        accum += u_waterVertices[i].z / q;
    }

    float normalizeToEdge = 1.0 - (accum - threshold) / 2.0;

    if (normalizeToEdge < 0.4)
        finalColor = vec4( 0.1, normalizeToEdge + 0.5, 0.9-normalizeToEdge*0.4, 1.0);

    if ( normalizeToEdge < 0.2 )
    {
        finalColor = vec4( 120.0/255.0, 245.0/255.0, 245.0/255.0, 1.0);
        float shade = mix( 0.7, 1.0, normal.x);
        finalColor *= shade;
    }

    gl_FragColor = vec4(finalColor);
}

The problem is here:

for ( int i = 0; i < u_numberOfParticles; ++i )
{
    vec2 dir2 = u_waterVertices[i].xy - currPos.xy;
    vec3 dir3 = vec3(dir2, 0.1);
    float q = dot(dir2, dir2);

    accum += u_waterVertices[i].z / q;
}

When I make the for-loop like this

for ( int i = 0; i < 2; ++i )
{
    //...
}

I get double the framerate even though u_numberOfParticles is also 2

Making it like this

for ( int i = 0; i < 100; ++i )
{
    if (i == u_numberOfParticles)
        break;
    //...
}

gives no improvement.

The only way I know to cope with this situation is to create multiple shaders. But The size of array may vary from 1 to 40 and making 40 different shaders just because of the for-loop is stupid. Any help or ideas how to deal with this situation ?

share|improve this question
1  
When you use a constant, specially a short one like 2, the shader is actually unrolling the loop, avoiding the need to jump or branch, so that's the reason it's faster. If you set it to 100 but use an if to jump out, the loop can't be unrolled, so that's the reason. –  Gonzalo Quero Apr 3 '13 at 16:26
    
@GonzaloQuero, I know that, but I believe, people somehow manage to have for-loops depending on uniforms, not just predefined constants... There are situations in game when I have e.g. 30 particles, as well as there are situations where I have 15 particles and I don't need to stress the GPU so hard when not needed.. –  Terko Apr 3 '13 at 16:33
    
Unrolling is done during compilation, so I don't think that is possible. A cursory search on Google doesn't shed much light on the issue either. Does that array change for every pixel? If it doesn't, could you precalculate it in the cpu and send it to the shader so it doesn't need to recalculate it every pixel? –  Gonzalo Quero Apr 3 '13 at 16:43
    
@GonzaloQuero, Calculating this value on the cpu will be not good because, I need to make screenWidth * screenHeight iterations each frame, and it will be a headache for iDevice. Even having render texture smaller will be still much more than 17 ms to calculate. The solution may be to create a grid, but I thought shaders are much better for doing some perpixel calculations, and I still think that they are. –  Terko Apr 3 '13 at 23:16
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.