如何在没有着色器的情况下将 glDrawArrays 与纹理数组一起使用

How to use glDrawArrays with a Texture Array without shaders

我试图通过将我的纹理组合成数组纹理来优化我的代码(我意识到我不能使用纹理图集,因为大多数纹理都是重复的(在地面上等))。我在 PyGame 和 PyOpenGL 工作,我以前从未使用过着色器。是否可以将单个数组纹理与 glBindTexture(GL_TEXTURE_2D_ARRAY, texname) 绑定并使用 3d 纹理坐标或其他东西来访问不同的层?没有着色器甚至可能吗?

目前我用这个函数为每个纹理调用 glDrawArrays:

def DRAW(im, array):
    glBindTexture(GL_TEXTURE_2D,im)
    glTexCoordPointer(2, GL_FLOAT, 32, array)
    glNormalPointer(GL_FLOAT, 32, array[2:])
    glVertexPointer(3, GL_FLOAT, 32, array[5:])
    glDrawArrays(GL_QUADS,0,len(array)/8)

没有着色器就不能使用纹理数组。它们从来都不是固定功能管道的一部分。 GL中没有GL_TEXTURE_2D_ARRAY使能位。

固定功能片段处理在OpenGL 4.5 compatibility profile specification.中的第16节中指定。第 16.2 节指出:

Array and multisample textures are only supported by shaders, and may not be enabled for fixed-function texturing.

在原来的 GL_EXT_texture_array 扩展中,您会发现以下语句:

(2) Should texture arrays be supported for fixed-function fragment processing?

RESOLVED: No; it's not believed to be worth the effort. Fixed-function fragment processing could be easily supported by allowing applications to enable or disable TEXTURE_1D_ARRAY_EXT or TEXTURE_2D_ARRAY_EXT.

Note that for fixed-function fragment processing, there would be issues with texture lookups of two-dimensional array textures with shadow mapping. Given that all texture lookups are projective, a total of five coordinate components would be required (s, t, layer, depth, q).

(3) If fixed-function were supported, should the layer number (T or R) be divided by Q in projective texture lookups?

RESOLVED: It doesn't need to be resolved in this extension, but it would be a problem. There are probably cases where an application would want the divide (handle R more-or-less like S/T); there are probably other cases where the divide would not be wanted. Many developers won't care, and may not even know what the Q coordinate is used for! The default of 1.0 allows applications that don't care about projective lookups to simply ignore that fact.

For programmable fragment shading, an application can code it either way and use non-projective lookups. To the extent that the divide by Q for projective lookups is "free" or "cheap" on OpenGL hardware, compilers may be able to recognize a projective pattern in the computed coordinates and generate code appropriately.

当数组纹理被提升为 OpenGL 核心功能时,这一点没有改变。

正如@derhass 的回答中的规范引用所示,没有着色器不支持数组纹理。

但是,您可以使用 3D 纹理来做几乎相同的事情。您将每个纹理存储在 3D 纹理的一层中。然后像往常一样使用前 2 个纹理坐标来确定纹理图像中的位置。第三个纹理坐标用于 select 3D 纹理中的图层。

要将图像加载到 3D 纹理中,请使用 glTexSubImage3D()。例如,假设您的纹理大小为 512x512,并且您想要加载纹理索引 20:

glTexSubImage3D(GL_TEXTURE_3D, 0,
    0, 0, 20, 512, 512, 1,
    GL_RGBA, GL_UNSIGNED_BYTE, data);

唯一有点棘手的部分是正确计算第三个纹理坐标,因为纹理坐标是规范化的浮点数。特别是如果你使用线性采样,你必须准确地击中图层的中心,否则你会得到混合图像。

如果您的 3D 纹理中有 n 层,则层 k 的纹理坐标为:

(k + 0.5f) / n

例如,使用 n = 4,4 层的最终纹理坐标将为:

0.125f
0.375f
0.625f
0.875f

请注意这些值是如何按 0.25f 间隔的,如您所料,并在区间 [0.0f, 1.0f]

内对称放置

使用 3D 纹理的一个缺点是它们的尺寸限制较小。使用这种方法,请确保您不超过 MAX_3D_TEXTURE_SIZE.

我鼓励您学习使用着色器。起初它可能看起来有点吓人,因为对于非常简单的用例来说,它肯定需要更多的工作。但是您会发现,一旦掌握了它,当您的功能变得更加复杂时,它们实际上会使事情变得更容易。编写 GLSL 代码来准确地执行您想要的操作通常要简单得多,而不是试图弄清楚如何正确设置几十个状态值以获得所需的结果。当然,着色器允许您实现在固定管道中根本不可能实现的功能。