OpenGL ES 1.x 和 2.x 不强制要求支持 3d 纹理 - 请参阅例如规范手册页glBindTexture,其中仅列出GL_TEXTURE_2D
and GL_TEXTURE_CUBE_MAP
作为目标 - 并且 iOS 硬件不提供任何合适的扩展。
我能想到的最好的解决方案是将 3d 纹理包装为 2d 纹理,因此您可以说是 128x128x128 3d 纹理,然后将其布局为 16x8 网格中的 128 个独立的 128x128 图像单个 2d 纹理。因此,2d 纹理为 2048x1024 像素,接近 iPhone 4 和 iPad 2 代设备以及之前的 ES 2.0 兼容 iOS 设备的硬件限制。
然后,您将 3D 纹理坐标输入到片段着色器中,就像有一种方法可以本地索引 3D 纹理一样,但需要快速进行一些数学运算,将其折叠为 2D。
因此,在 128x128x128 示例中,您可以执行类似的操作(在此处编码,正如我所说,未经测试):
texPos.x = sourceVarying.x / 16.0; // because we've packed 16 source images across,
texPos.y = sourceVarying.y / 8.0; // and 8 images down
// we'll multiply z by 16 since then, logically, the integer part is
// how many tiles across to index, and the decimal part is now many
// tiles down to index
texPos.z *= 16.0;
// figure out how many tiles across to index, with each tile being
// 1.0 / 16.0 in size
texPos.x += floor(texPos.z) / 16.0;
// remove the integer part of z, then multiply by 8 to do much what
// we just did to y
texPos.z = fract(texPos.z) * 8.0;
texPos.y += floor(texPos.z) / 8.0;
// now load the appropriate sample from texPos.xy
这可能不是实现这一目标的最有效方法,它是为了(相对)清晰而编写的。您还会看到每个纹理读取都依赖的显着性能缺点(即,GPU 无法预测片段着色器外部的访问,从而导致严重的管道困难)。但这需要权衡使用 3D 纹理贴图以外的其他内容所需花费的成本。
另请注意,您正在执行与特定 z 切片相关的一次访问。所以你仅限于GL_NEAREST
- 至少在一维中进行采样,除非您想要进行两个采样并以更高的成本自行混合结果。我也没有对夹紧做任何事情,您很可能想解决这个问题。
Datenwolf(顺便说一下,+1)关于 mipmap 是一个问题的说法也是完全正确的;我最终只是禁用了它。
2013年底附录:截至撰写本文时,iOS 7、iPhone 5s、第二代 iPad Mini 和 iPad Air 均支持 ES 3.0。 3.0 引入了GL_TEXTURE_3D
目标。因此,您可以直接在这些设备上以及可能在所有未来的 iOS 设备上使用 3D 纹理。而且,根据记录,它在 Android 上也有类似的可用性,所有最新的 Nexus 设备、HTC One、一些最近的三星设备和其他设备都支持该功能。