我已经在WebGL中建立了一些FPS测量代码(基于此SO答案),并且发现我的片段着色器的性能有些奇怪。该代码仅在1024x1024画布上呈现一个四边形(或者说是两个三角形),因此所有魔术都发生在片段着色器中。
考虑一下这个简单的着色器(GLSL;顶点着色器只是一个传递):
// 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);
}
因此,这只是渲染白色画布。在我的机器上,平均速度约为30 fps。
现在,让我们增加数字运算的难度,并根据与位置相关的噪声的几个八度音程来计算每个片段:
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);
}
如果您想运行上面的代码,我一直在使用的实现snoise
。
这样会将fps降低到7。
现在,很奇怪的部分...通过将噪声计算包装在以下条件中,让我们仅将每16个片段中的一个作为噪声进行计算,而将其余部分留为白色:
if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
// same noise computation
}
您可能希望它速度更快,但是仍然只有7 fps。
再进行一次测试,让我们使用以下条件过滤像素:
if (x > 0.5 && y > 0.5) {
// same noise computation
}
这样可以提供与以前完全相同的噪点像素数量,但是现在我们可以恢复到近30 fps。
这里发生了什么?两种滤除第16个像素的方式不应该给出完全相同的周期数吗?为什么慢的像素像渲染所有像素一样慢呢?
额外的问题:我该怎么办?如果我确实确实想只用一些昂贵的片段来散布我的画布,是否有任何方法可以解决这种可怕的性能?
(可以肯定的是,通过将第16个像素渲染为黑色而不是白色,我已经确认了实际的模运算根本不影响帧速率。)