如何在 OpenGL 中将多个 textures/buffers 混合为一个 texture/buffer?
How to blend many textures/buffers into one texture/buffer in OpenGL?
我有一个包含 MNIST 数据集的大缓冲区(对象):许多(数万)小(28x28)灰度图像,按行顺序逐一存储为 float
s 表示像素强度。我想有效地(即有点交互地)将这些许多图像混合成一个“平均”图像,其中混合图像中的每个像素都是同一位置所有像素的平均值。这可能吗?
我考虑的选项是:
直接在缓冲区对象上使用计算着色器。我会生成 imgWidth * imgHeight
计算着色器 invocations/threads,每次调用都会遍历所有图像。这似乎不是很有效,因为每次调用都必须遍历所有图像,但以另一种方式进行(即产生 numImages
调用并遍历像素)仍然有调用相互等待。
使用图形管道将纹理逐一绘制到帧缓冲区,将它们相互混合。这仍然会导致线性时间,因为每个图像都必须依次渲染到帧缓冲区。不过,我对帧缓冲区不是很熟悉。
在 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 个维度。您可以让 X
和 Y
索引图像的像素。并且 Z
可用于在纹理数组中插入一对图像。因此对于索引 Z
,您将混合纹理 2*Z
和 2*Z+1
.
您需要考虑的一些实施细节:
- 图像的数量很可能不会是二的幂。所以在某些时候图像的数量会是奇数。
- 由于您要处理大量图像,因此您可能 运行 遇到浮点精度问题。您可能需要使用浮动纹理,或添加策略,所以这不是问题。
- 通常,当线程处理 2x2 像素的图块而不是单个像素时,计算着色器的效果最好。
我有一个包含 MNIST 数据集的大缓冲区(对象):许多(数万)小(28x28)灰度图像,按行顺序逐一存储为 float
s 表示像素强度。我想有效地(即有点交互地)将这些许多图像混合成一个“平均”图像,其中混合图像中的每个像素都是同一位置所有像素的平均值。这可能吗?
我考虑的选项是:
直接在缓冲区对象上使用计算着色器。我会生成
imgWidth * imgHeight
计算着色器 invocations/threads,每次调用都会遍历所有图像。这似乎不是很有效,因为每次调用都必须遍历所有图像,但以另一种方式进行(即产生numImages
调用并遍历像素)仍然有调用相互等待。使用图形管道将纹理逐一绘制到帧缓冲区,将它们相互混合。这仍然会导致线性时间,因为每个图像都必须依次渲染到帧缓冲区。不过,我对帧缓冲区不是很熟悉。
在 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 个维度。您可以让 X
和 Y
索引图像的像素。并且 Z
可用于在纹理数组中插入一对图像。因此对于索引 Z
,您将混合纹理 2*Z
和 2*Z+1
.
您需要考虑的一些实施细节:
- 图像的数量很可能不会是二的幂。所以在某些时候图像的数量会是奇数。
- 由于您要处理大量图像,因此您可能 运行 遇到浮点精度问题。您可能需要使用浮动纹理,或添加策略,所以这不是问题。
- 通常,当线程处理 2x2 像素的图块而不是单个像素时,计算着色器的效果最好。