"Interleaved rendering" 在片段着色器中

"Interleaved rendering" in fragment shader

P.S。是的,我在 Computer Graphics Stack Exchange 上发布了这个 question。不过发在那里也是希望更多人看到

简介

我正在尝试渲染多通道图像(超过 4 个通道,以便将其馈送到神经网络)。由于 OpenGL 本身不支持它,我有多个 4 通道渲染缓冲区,我在其中渲染通道的相应部分。

例如,我需要大小为 512 x 512 x 16 的多通道图像,在 OpenGL 中我有 4 个大小为 512 x 512 x 4 的渲染缓冲区。现在的问题是神经网络期望数据的步幅为 512 x 512 x 16,即一个像素的 16 个通道值后面跟着下一个像素的 16 个通道值。然而,目前我可以通过 4 次调用 glReadPixels 有效地读取我的 4 个渲染缓冲区,基本上使数据具有跨度 4 x 512 x 512 x 4。在客户端手动重新排序数据 无法满足我的需求,因为它太慢了。

主要问题

我想渲染到大小为 512*4 x 512 x 4 的单个 4 通道渲染缓冲区,因为在步幅方面它等同于 512 x 512 x 16,我们只处理 4 个像素的组合连续作为单个像素的 16 通道输出图像。我们称之为“交错渲染”

但这需要我神奇地调整我的片段着色器,以便每组后续的 4 片段 将具有完全相同的顶点属性插值。有什么办法吗?

这个带有 1024 x 512 4 通道图像的 1 个渲染缓冲区的糟糕插图是应该如何渲染的示例。这样我就可以在一次调用中 glReadPixels 大步提取数据 512 x 512 x 8

编辑:更好的图片 我现在拥有的(4 个渲染缓冲区)

我想在 OpenGL 中本机执行的操作(此图像是在 Python 离线中完成的)

But this requires me to magically adjust my fragment shader, so that every group of consequent 4 fragments would have exactly the same interpolation of vertex attributes.

不,它需要的不止于此。您必须从根本上改变 光栅化 的工作方式。

以 4 倍宽度渲染就是以 4 倍宽度渲染。这意味着相对于方形区域拉伸生成的基元。但这不是你想要的效果。您需要光栅化器以原始分辨率进行光栅化,然后复制光栅化产品。

这不可能。

来自评论:

It just got to me, that I can try to get a 512 x 512 x 2 image of texture coordinates from vertex+fragment shaders, then stitch it with itself to make 4 times wider (thus we'll get the same interpolation) and from that form the final image

这是个好主意。您需要渲染原始大小纹理所需的任何插值,类似于延迟渲染的工作方式。所以它可能不仅仅是 2 个值。您可以只存储 gl_FragCoord.xy 值,然后使用它们来计算您需要的任何值,但直接存储插值可能更容易。

我建议在读取纹理时执行 texelFetch,因为您可以指定精确的整数纹素坐标。您需要的整数坐标可以从 gl_FragCoord 计算如下:

ivec2 texCoords = ivec2(int(gl_FragCoord.x * 0.25f), int(gl_FragCoord.y));