Eu configurei algum código de medição de FPS no WebGL (com base nesta resposta do SO ) e descobri algumas curiosidades com o desempenho do meu shader de fragmento. O código apenas renderiza um único quadrilátero (ou melhor, dois triângulos) sobre uma tela de 1024x1024, para que toda a mágica ocorra no shader de fragmento.
Considere este sombreador simples (GLSL; o sombreador de vértice é apenas uma passagem):
// 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);
}
Então isso apenas renderiza uma tela branca. A média é de 30 fps na minha máquina.
Agora vamos acelerar o processamento de números e calcular cada fragmento com base em algumas oitavas de ruído dependente da posição:
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 você deseja executar o código acima, eu tenho usado esta implementação desnoise
.
Isso reduz os fps para algo como 7. Isso faz sentido.
Agora a parte estranha ... vamos calcular apenas um de cada 16 fragmentos como ruído e deixar os outros brancos, envolvendo a computação de ruído na seguinte condicional:
if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
// same noise computation
}
Você esperaria que isso fosse muito mais rápido, mas ainda são apenas 7 qps.
Para mais um teste, vamos filtrar os pixels com a seguinte condicional:
if (x > 0.5 && y > 0.5) {
// same noise computation
}
Isso fornece exatamente o mesmo número de pixels de ruído de antes, mas agora estamos com quase 30 fps.
O que está acontecendo aqui? As duas maneiras de filtrar 16 dos pixels não deveriam fornecer exatamente o mesmo número de ciclos? E por que o mais lento é tão lento quanto renderizar todos os pixels como ruído?
Pergunta bônus: O que posso fazer sobre isso? Existe alguma maneira de contornar o desempenho horrível se eu realmente não quer salpico minha tela com apenas alguns fragmentos caros?
(Só para ter certeza, confirmei que o cálculo real do módulo não afeta a taxa de quadros, tornando todo décimo sexto pixel preto em vez de branco.)
fonte