我该如何在iOS中使用3D纹理?

8

我在 OpenGL ES 2.0 中找不到 glTexImage3D() 函数。那么我该如何使用 3D 纹理,例如:一个 .tga 文件?

有人知道如何在 OpenGL ES 2.0 中使用 3D 纹理吗?

2个回答

12

OpenGL ES 1.x和2.x不强制支持3D纹理-例如,可以查看glBindTexture的规范手册,该手册仅列出GL_TEXTURE_2DGL_TEXTURE_CUBE_MAP作为目标-而且iOS硬件没有提供任何合适的扩展。

我能想到的最好解决方案是将3D纹理打包成2D纹理,例如,您有一个128x128x128的3D纹理,并将其布置为单个2D纹理上的16x8网格中的128个单独的128x128图像。因此,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)关于MIP贴图的问题也是正确的;我最终只禁用了它。
2013年末添加:在撰写本文时,iOS 7、iPhone 5s、第二代iPad Mini和iPad Air均支持ES 3.0。3.0引入了GL_TEXTURE_3D目标。因此,您可以在这些设备上直接使用3D纹理,并且兴许所有未来的iOS设备都支持它。记录显示,它在Android上也有类似的可用性,在所有最新的Nexus设备、HTC One、一些最近的三星设备和其他设备上都得到了支持。

谢谢您的回答!实际上我不确定我需要的是3D纹理。这是我第一次使用OpenGL ES进行工作。我接受了一个项目,需要在屏幕上渲染一座房子。当我打开.obj文件时,我发现每个vt都有三个组件,而不仅仅是vt。如果我忽略vt的第三个组件,纹理会非常奇怪。也许我不必使用3D纹理?我将纹理图像放在下面。也许您专家知道我需要什么。ww2.sinaimg.cn/large/991557bagw1dpytx071d5j.jpg 最终效果如下:http://ww4.sinaimg.cn/large/991557bagw1dpyu275vz4j.jpg - Ning
1
看起来像是普通的2D纹理;你记得OBJ将y纹理坐标与OpenGL相反,所以你需要在管道中快速进行1-y处理吗? - Tommy
嗯...我没做那个!谢谢! 我会尝试的! - Ning
@Tommy 这取决于您使用的创作工具。至少 Maya 以及很可能还有 3ds max 和 Blender 使用 OpenGL 约定,将 (0,0) 放在左下角(D3D 的约定是将 (0,0) 放在左上角)。 - bobobobo

2
因为OpenGL ES 2不支持3D纹理,所以我找不到glTexImage3D函数。想想看:3D纹理需要比2D纹理更多的内存。而内存是嵌入式/移动设备上非常稀缺的资源,这正是ES的目标所在。
我认为可能有人知道使用3D纹理的算法?实际上这不是一个算法问题,而是一个有限资源的问题。理论上,您可以使用多个纹理单元/采样器将图层上传到那里,并在着色器中进行插值。但这将缺乏深度mipmaping。
3D纹理,例如:.tag文件?抱歉,我不知道这种格式。您能给我一个链接阅读吗?谷歌没有找到有用的信息。您可能是指TGA吗?

谢谢您的回答!实际上我不确定我需要的是3D纹理。这是我第一次使用OpenGL ES进行工作。我接受了一个项目,需要在屏幕上渲染一座房子。当我打开.obj文件时,我发现每个vt都有三个组件,而不仅仅是vt。如果我忽略vt的第三个组件,纹理会非常奇怪。也许我不必使用3D纹理?我将纹理图像放在下面。也许您专家知道我需要什么。ww2.sinaimg.cn/large/991557bagw1dpytx071d5j.jpg 最终效果如下:http://ww4.sinaimg.cn/large/991557bagw1dpyu275vz4j.jpg - Ning
@Ning:第三个组件 w 就像一个缩放参数。你不需要它。 - datenwolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接