如何在 OpenGL 中将多个 textures/buffers 混合为一个 texture/buffer?

How to blend many textures/buffers into one texture/buffer in OpenGL?

我有一个包含 MNIST 数据集的大缓冲区(对象):许多(数万)小(28x28)灰度图像,按行顺序逐一存储为 floats 表示像素强度。我想有效地(即有点交互地)将这些许多图像混合成一个“平均”图像,其中混合图像中的每个像素都是同一位置所有像素的平均值。这可能吗?

我考虑的选项是:

  1. 直接在缓冲区对象上使用计算着色器。我会生成 imgWidth * imgHeight 计算着色器 invocations/threads,每次调用都会遍历所有图像。这似乎不是很有效,因为每次调用都必须遍历所有图像,但以另一种方式进行(即产生 numImages 调用并遍历像素)仍然有调用相互等待。

  2. 使用图形管道将纹理逐一绘制到帧缓冲区,将它们相互混合。这仍然会导致线性时间,因为每个图像都必须依次渲染到帧缓冲区。不过,我对帧缓冲区不是很熟悉。

  3. 在 CPU 中线性地完成这一切,这似乎比在 GPU 上完成更容易,也不会慢多少。我只会错过像素的并行处理。

还有我遗漏的其他可能性吗?有最优方法吗?如果没有,您认为最简单的是什么?

我就是这样做的。

将所有纹理渲染到帧缓冲区,也可以是默认的帧缓冲区。

渲染完成后。

从帧缓冲区读取数据。

glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, w_pbo[w_writeIndex]);
// copy from framebuffer to PBO asynchronously. it will be ready in the NEXT frame
glReadPixels(0, 0, SCR_WIDTH, SCR_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// now read other PBO which should be already in CPU memory
glBindBuffer(GL_PIXEL_PACK_BUFFER, w_pbo[w_readIndex]);
unsigned char* Data = (unsigned char*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);

大多数时候我们希望在像素级别并行化,因为有很多。

但是,在你的情况下没有那么多像素 (28x28)。

您拥有的最大数字似乎是图像的数量(数千张图像)。所以我们想利用它。

使用计算着色器,而不是遍历所有图像,您可以将图像成对混合。每次通过后,您会将图像数量减半。一旦图像数量变得非常少,您可能想要更改策略,但这是您需要进行试验以了解最佳效果的方法。

你知道计算着色器可以有 3 个维度。您可以让 XY 索引图像的像素。并且 Z 可用于在纹理数组中插入一对图像。因此对于索引 Z,您将混合纹理 2*Z2*Z+1.

您需要考虑的一些实施细节:

  • 图像的数量很可能不会是二的幂。所以在某些时候图像的数量会是奇数。
  • 由于您要处理大量图像,因此您可能 运行 遇到浮点精度问题。您可能需要使用浮动纹理,或添加策略,所以这不是问题。
  • 通常,当线程处理 2x2 像素的图块而不是单个像素时,计算着色器的效果最好。