3

我正在开发一个 WebGL 批处理渲染器(问题在 OpenGL 领域仍然有效)。也就是在尽可能少的 drawArrays/drawElements 调用(理想情况下为 1)中绘制的场景中的所有图形。其中一部分涉及允许基于属性确定纹理。

因此,在我的片段着色器中,我正在考虑两种情况:

1.在屏幕上绘制纹理 0 并使用属性来确定纹理位于内存中的精灵表上的“帧”。片段着色器看起来像:

precision mediump float;

uniform sampler2D u_spriteSheet;

// Represents position that's framed.
varying vec4 v_texturePosition;

void main() {
    gl_FragColor = texture2D(u_spriteSheet, v_texturePosition);
}

2.在着色器中执行“if”语句以确定使用哪个统一的 sampler2d。片段着色器看起来像:

precision mediump float;

uniform sampler2D u_image1;
uniform sampler2D u_image2;
uniform sampler2D u_image3;
uniform sampler2D u_image4;
....
uniform sampler2D u_image32;

varying uint v_imageId;
// Represents texture position that's framed
varying vec4 v_texturePosition;

void main() {
    if(v_imageId == 1) {
        gl_FragColor = texture2D(u_image1, v_texturePosition);
    }
    else if (v_imageId == 2) {
        gl_FragColor = texture2D(u_image2, v_texturePosition);
    }
    ...
    else if (v_imageId == 32) {
        gl_FragColor = texture2D(u_image32, v_texturePosition);
    }
}

我知道,对于选项 1,我受到最大纹理大小的限制,而通过方法 2,我受到可用纹理寄存器数量的限制。为了讨论,我们假设这些限制永远不会被通过。

在将大量时间投入其中之一之前,我正在尝试确定更高效的方法......所以有什么想法吗?

4

1 回答 1

4

着色器中的 if 语句通常很慢,因为在普通 GPU 上,硬件着色器作为 SIMD 执行,即许多片段是并行处理的,每条指令一条指令。简而言之,如果所有线程都处理 then 部分,则只有具有肯定 if 条件的线程真正执行并存储结果,而其他线程正在等待(或者甚至进行计算但不存储结果)。之后,所有线程都执行 else 部分,并且所有具有肯定条件的线程都在等待。

因此,在您的解决方案 #2 中,许多卡上的片段着色器将执行所有 32 个部分,而不仅仅是解决方案 #1 中的一个(在某些卡上,据说如果该部分后面没有线程,它们将停止执行 if 分支, 所以它可能小于 32)。

所以我希望解决方案#1 比片段着色器更快。但是,您的解决方案可能存在其他瓶颈,因此片段着色器的性能可能与整体性能无关。

其他想法是许多 GPU 允许的纹理少于 32,因此如果您想与许多设备保持兼容,您可能无法使用 32。根据 webglstats.com,99% 有 16 个纹理单元,并且由于大多数场景有超过 16 个纹理,因此可能无法实现类似于您的解决方案 #1 的方法。另一方面,当您达到最大纹理尺寸时,您可能还需要像 #2 这样的东西。

于 2013-11-15T19:39:30.623 回答