Skonfigurowałem trochę kodu mierzącego FPS w WebGL (w oparciu o tę odpowiedź SO ) i odkryłem pewne dziwactwa w działaniu mojego modułu cieniującego fragmenty. Kod po prostu renderuje pojedynczy quad (a raczej dwa trójkąty) na kanwie 1024x1024, więc cała magia dzieje się w module cieniującym fragmenty.
Rozważ ten prosty moduł cieniujący (GLSL; moduł cieniujący wierzchołek to tylko przejście):
// 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);
}
To po prostu renderuje białe płótno. To średnio około 30 fps na moim komputerze.
Teraz zwiększmy liczbę pęknięć i obliczmy każdy fragment na podstawie kilku oktaw hałasu zależnego od pozycji:
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);
}
Jeśli chcesz uruchomić powyższy kod, korzystałem z tej implementacjisnoise
.
Sprowadza to fps do czegoś takiego jak 7. To ma sens.
Teraz dziwna część ... obliczyć tylko jeden z 16 fragmentów jako hałas, a pozostałe pozostawić białe, zawijając obliczenia hałasu w następujący warunek:
if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
// same noise computation
}
Można się spodziewać, że będzie to znacznie szybsze, ale wciąż jest to tylko 7 fps.
Dla jeszcze jednego testu przefiltrujmy piksele według następującego warunku:
if (x > 0.5 && y > 0.5) {
// same noise computation
}
Daje to dokładnie taką samą liczbę pikseli szumu jak poprzednio, ale teraz wracamy do prawie 30 fps.
Co tu się dzieje? Czy dwa sposoby filtrowania 16 pikseli nie powinny dawać dokładnie takiej samej liczby cykli? I dlaczego wolniejszy jest tak wolny, jak renderowanie wszystkich pikseli jak szum?
Pytanie dodatkowe: Co mogę z tym zrobić? Czy istnieje jakiś sposób, aby obejść okropnym wydajności gdybym rzeczywiście nie chcą speckle moje płótno tylko kilka drogich fragmentów?
(Dla pewności potwierdziłem, że faktyczne obliczenia modulo w ogóle nie wpływają na częstotliwość klatek, renderując co 16 pikseli na czarno zamiast na biało).