Ho impostato un codice di misurazione FPS in WebGL (basato su questa risposta SO ) e ho scoperto alcune stranezze con le prestazioni del mio shader di frammenti. Il codice esegue semplicemente il rendering di un singolo quad (o meglio due triangoli) su una tela di 1024x1024, quindi tutta la magia avviene nello shader di frammenti.
Considera questo semplice shader (GLSL; lo shader di vertice è solo un pass-through):
// 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);
}
Quindi questo rende solo una tela bianca. La mia macchina ha una media di circa 30 fps.
Ora aumentiamo il numero di scricchiolii e calcoliamo ogni frammento in base a poche ottave di rumore dipendente dalla posizione:
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);
}
Se vuoi eseguire il codice sopra, sto usando questa implementazione disnoise
.
Questo porta il fps a qualcosa come 7. Questo ha senso.
Ora la parte strana ... calcoliamo solo uno di ogni 16 frammenti come rumore e lasciamo gli altri bianchi, avvolgendo il calcolo del rumore nel seguente condizionale:
if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
// same noise computation
}
Ti aspetteresti che questo sia molto più veloce, ma è ancora solo 7 fps.
Per un altro test, filtriamo invece i pixel con il seguente condizionale:
if (x > 0.5 && y > 0.5) {
// same noise computation
}
Questo fornisce lo stesso numero esatto di pixel di rumore di prima, ma ora siamo tornati a quasi 30 fps.
Cosa sta succedendo qui? I due modi per filtrare un sedicesimo dei pixel non dovrebbero fornire lo stesso numero esatto di cicli? E perché quello più lento è lento quanto il rendering di tutti i pixel come rumore?
Domanda bonus: cosa posso fare al riguardo? C'è un modo per aggirare la prestazione orribile se io in realtà non voglio speckle mia tela con solo pochi frammenti costosi?
(Per essere sicuro, ho confermato che l'attuale calcolo del modulo non influenza affatto la frequenza dei fotogrammi, rendendo ogni 16 pixel nero anziché bianco.)