在 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 个连续的条件分支。
您的统一案例也不能免受此类“优化”的影响,因为某些较旧的硬件在功能上根本无法对重要指令进行条件分支。因此,他们别无选择,只能在每次更改统一时重新编译着色器(这并不夸张;旧硬件上的 NVIDIA 编译器实际上就是这样做的)或执行所有 4 个纹理访问。
哦,还有一件事:在非统一控制流中(例如在条件执行 block 中),texture2D
函数变得未定义。现在,由于您使用它的方式,它可能不会对您造成伤害。但一般来说,您需要使用显式渐变或从条件 block 中删除纹理访问函数。我记得 WebGL 没有渐变纹理功能。
简而言之,只需更改纹理并重新渲染即可。即使在 JavaScript 中,这也不会像进行 4 次纹理访问那样影响性能。只要您仅在渲染之间绑定(bind)纹理(即:您不更改程序或其他状态),并且您正在观察良好的实践(在状态更改之间尽可能合理地渲染),您应该相对没问题.
关于opengl-es - 在一个着色器 channel 中渲染多个纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15170736/