2

在 WebGL 中一次渲染多个纹理是否会更快,例如:

varying float materialIndex;
varying vec2 textureCoord; 

uniform sampler2D textureSampler1;
uniform sampler2D textureSampler2;
uniform sampler2D textureSampler3;
uniform sampler2D textureSampler4;

vec4 getMaterial(float materialId, textureCoord) {
    vec4 color;

    if (materialId == 1.0)
    {
        color = texture2D( textureSampler1, textureCoord );
    }
    else if (materialId == 2.0)
    {
        color = texture2D( textureSampler2, textureCoord );
    }
    else if (materialId == 3.0)
    {
        color = texture2D( textureSampler3, textureCoord );
    }
    else
    {
        color = texture2D( textureSampler4, textureCoord );
    }

    return color;
}

void main()               
{                  
    vec4 color = getMaterial(materialIndex, textureCoord);
    gl_FragColor = color;        
}

因为这将节省 CPU 必须发送到 GPU 的指令的四分之一,除了顶点着色器必须传递的额外信息之外,在大多数情况下,它不会比 4 倍的程序调用更快吗?我已经读到,即使在 opengl 中,迄今为止最大的性能损失也是 cpu,我敢打赌 Webgl 更是如此。或者这可能会更快?

uniform float materialIndex;
varying vec2 textureCoord; 

uniform sampler2D textureSampler1;
uniform sampler2D textureSampler2;
uniform sampler2D textureSampler3;
uniform sampler2D textureSampler4;


void main()               
{                  
    vec4 color = getMaterial(materialIndex, textureCoord);
    gl_FragColor = color;        
}

或者就 CPU 必须执行的调用次数而言,更改功能统一与加载新着色器一样糟糕?

4

1 回答 1

2

批处理很重要,是的。但这并不重要。尤其是当遇到某种硬件可以从所有四种纹理中采样的可能性时,无论如何。

在不同的情况下,编译器不知道值如何变化。因此,它将假设任何片段都可以获得任何值。所以它必须为所有东西做一个运行时分支。并且由于条件分支的成本,编译器通常会尝试通过简单地执行所有可用路径并使用非分支逻辑来计算最终结果来避免执行 4 个连续的条件分支。

您的统一案例也不能避免这种“优化”,因为某些较旧的硬件在功能上根本无法对重要指令进行条件分支。因此,他们别无选择,只能在每次更改制服时重新编译着色器(这不是夸张;旧硬件上的 NVIDIA 编译器实际上就是这样做的)或执行所有 4 次纹理访问。

哦,还有一件事:texture2D在非统一控制流中(如在条件执行的块中),函数变得未定义。现在,由于您使用它的方式,它可能不会在这里伤害您。但一般来说,您需要使用显式渐变或从条件块中删除纹理访问函数。我记得,WebGL 没有渐变纹理功能。

简而言之,只需更改纹理并重新渲染即可。即使在 JavaScript 中,这也不会像可能进行 4 次纹理访问那样影响您的性能。只要您只在渲染之间绑定纹理(即:您没有更改程序或其他状态),并且您正在观察良好做法(在状态更改之间尽可能多地渲染),您应该相对没问题.

于 2013-03-02T05:28:36.867 回答