Ich habe einen FPS-Messcode in WebGL eingerichtet (basierend auf dieser SO-Antwort ) und einige Merkwürdigkeiten mit der Leistung meines Fragment-Shaders entdeckt. Der Code gibt nur ein einzelnes Quad (oder besser gesagt zwei Dreiecke) auf einer Leinwand von 1024 x 1024 wieder, sodass die ganze Magie im Fragment-Shader geschieht.
Betrachten Sie diesen einfachen Shader (GLSL; der Vertex-Shader ist nur ein Durchgang):
// 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);
}
Das ergibt also nur eine weiße Leinwand. Auf meinem Computer sind es durchschnittlich 30 fps.
Erhöhen wir nun die Anzahl und berechnen jedes Fragment anhand einiger Oktaven positionsabhängigen Rauschens:
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);
}
Wenn Sie den obigen Code ausführen möchten, habe ich diese Implementierung von verwendetsnoise
.
Das bringt die fps auf so etwas wie 7. Das macht Sinn.
Nun der seltsame Teil ... lassen Sie uns nur eines von 16 Fragmenten als Rauschen berechnen und die anderen weiß lassen, indem Sie die Rauschberechnung in die folgende Bedingung einschließen:
if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
// same noise computation
}
Sie würden erwarten, dass dies viel schneller ist, aber es sind immer noch nur 7 fps.
Für einen weiteren Test filtern wir stattdessen die Pixel mit der folgenden Bedingung:
if (x > 0.5 && y > 0.5) {
// same noise computation
}
Dies ergibt genau die gleiche Anzahl an Rauschpixeln wie zuvor, aber jetzt sind wieder fast 30 fps möglich.
Was geht hier vor sich? Sollten die beiden Methoden zum Herausfiltern eines Sechzehntels der Pixel nicht genau die gleiche Anzahl von Zyklen ergeben? Und warum ist der langsamere so langsam wie das Rendern aller Pixel als Rauschen?
Bonusfrage: Was kann ich dagegen tun? Gibt es eine Möglichkeit zu arbeiten rund um die schreckliche Leistung , wenn ich tatsächlich tue meine Leinwand Sprenkel mit nur wenigen teueren Fragmenten will?
(Zur Sicherheit habe ich bestätigt, dass die Modulo-Berechnung die Bildrate überhaupt nicht beeinflusst, indem jedes 16. Pixel schwarz statt weiß dargestellt wird.)
quelle