He configurado un código de medición de FPS en WebGL (basado en esta respuesta SO ) y he descubierto algunas rarezas con el rendimiento de mi sombreador de fragmentos. El código solo representa un único quad (o más bien dos triángulos) sobre un lienzo de 1024x1024, por lo que toda la magia ocurre en el sombreador de fragmentos.
Considere este sombreador simple (GLSL; el sombreador de vértices es solo un paso):
// some definitions
void main() {
float seed = uSeed;
float x = vPos.x;
float y = vPos.y;
float value = 1.0;
// Nothing to see here...
gl_FragColor = vec4(value, value, value, 1.0);
}
Entonces, esto solo representa un lienzo blanco. Tiene un promedio de alrededor de 30 fps en mi máquina.
Ahora aumentemos el número y calculemos cada fragmento en función de unas pocas octavas de ruido dependiente de la posición:
void main() {
float seed = uSeed;
float x = vPos.x;
float y = vPos.y;
float value = 1.0;
float noise;
for ( int j=0; j<10; ++j)
{
noise = 0.0;
for ( int i=4; i>0; i-- )
{
float oct = pow(2.0,float(i));
noise += snoise(vec2(mod(seed,13.0)+x*oct,mod(seed*seed,11.0)+y*oct))/oct*4.0;
}
}
value = noise/2.0+0.5;
gl_FragColor = vec4(value, value, value, 1.0);
}
Si desea ejecutar el código anterior, he estado usando esta implementación desnoise
.
Esto reduce los fps a algo así como 7. Eso tiene sentido.
Ahora la parte extraña ... calculemos solo uno de cada 16 fragmentos como ruido y dejemos los otros blancos, envolviendo el cálculo del ruido en el siguiente condicional:
if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
// same noise computation
}
Es de esperar que esto sea mucho más rápido, pero sigue siendo solo 7 fps.
Para una prueba más, filtremos los píxeles con el siguiente condicional:
if (x > 0.5 && y > 0.5) {
// same noise computation
}
Esto proporciona exactamente la misma cantidad de píxeles de ruido que antes, pero ahora hemos vuelto a casi 30 fps.
¿Que esta pasando aqui? ¿No deberían las dos formas de filtrar un décimo sexto de los píxeles dar exactamente el mismo número de ciclos? ¿Y por qué el más lento es tan lento como representar todos los píxeles como ruido?
Pregunta extra: ¿Qué puedo hacer al respecto? ¿Hay alguna forma de trabajo en torno a la actuación horrible si yo en realidad no quiero moteado mi lienzo con sólo unos pocos fragmentos caros?
(Solo para estar seguro, he confirmado que el cálculo del módulo real no afecta la velocidad de fotogramas, al renderizar cada 16 píxeles en negro en lugar de en blanco).