我正在尝试找到在 iOS 上处理 OpenGL ES2 中多重纹理的最有效方法。我所说的“高效”是指即使在较旧的 iOS 设备(iPhone 4 及更高版本)上也能实现最快的渲染 - 但同时还要平衡便利性。
我考虑过(并尝试过)几种不同的方法。但遇到了一些问题和疑问。
Method 1- 我的基本值和正常值是 rgb,没有 ALPHA。对于这些对象我不需要透明度。我的发射和镜面反射信息都只有一个通道。减少texture2D()
我想我可以将发射存储为基础的 Alpha 通道,将镜面反射存储为法线的 Alpha。每个文件都在自己的文件中,看起来像这样:
到目前为止,我的问题是找到一种支持完整非预乘 Alpha 通道的文件格式。 PNG 对我来说不起作用。我尝试将其另存为 PNG 的每一种方法都会将 .alpha 与文件保存时的 .rgb 预乘(通过 Photoshop),基本上会破坏 .rgb。当我重新加载文件时,任何具有 0.0 alpha 的像素都会显示黑色 rgb。我发布了这个问题here https://stackoverflow.com/questions/21752582/how-to-encode-emission-or-specular-info-in-the-alpha-of-a-open-gl-texture没有任何活动。
我知道如果我能找到一种方法来保存和加载这个独立的第四通道,这种方法会产生更快的渲染速度。但到目前为止,我还无法做到这一点,不得不继续前进。
Method 2- 当这不起作用时,我转向单个 4 向纹理,其中每个象限都有不同的贴图。这并没有减少texture2D()
调用,但它减少了着色器内访问的纹理数量。
4 路纹理确实需要我修改着色器内的纹理坐标。为了模型的灵活性,我将纹理坐标保留在模型结构中,并在着色器中修改它们,如下所示:
v_fragmentTexCoord0 = a_vertexTexCoord0 * 0.5;
v_fragmentTexCoord1 = v_fragmentTexCoord0 + vec2(0.0, 0.5); // illumination frag is up half
v_fragmentTexCoord2 = v_fragmentTexCoord0 + vec2(0.5, 0.5); // shininess frag is up and over
v_fragmentTexCoord3 = v_fragmentTexCoord0 + vec2(0.5, 0.0); // normal frag is over half
避免动态纹理查找 https://stackoverflow.com/questions/9946572/shader-optimization-for-retina-screen-on-ios(谢谢布拉德·拉尔森 https://stackoverflow.com/users/19679/brad-larson)我将这些偏移量移至顶点着色器,并将它们保留在片段着色器之外。
但我的问题是:减少着色器中使用的纹理采样器的数量是否重要?或者我在这里使用 4 个不同的较小纹理会更好吗?
我遇到的一个问题是不同地图之间的渗色。由于线性纹理映射,一些蓝色法线像素的 texcoord 被平均为 1.0。这在接缝附近的对象上添加了蓝色边缘。为了避免这种情况,我必须更改 UV 贴图,以免太靠近边缘。对于很多对象来说这是一件痛苦的事情。
Method 3将方法 1 和 2 结合起来,一侧为 base.rgb + Emission.a,另一侧为 Normal.rgb + Specular.a。但我仍然遇到了将独立的 alpha 保存在文件中的问题。
也许我可以将它们保存为两个文件,但在加载期间将它们组合起来,然后再将其发送到 openGL。我得尝试一下。
Method 4最后,在 3D 世界中,如果我有 20 种不同的墙壁面板纹理,这些应该是单独的文件还是全部打包在单个纹理图集中?我最近注意到,在某种程度上,《我的世界》从地图集转移到了单独的纹理 - 尽管它们都是 16x16。
使用单个模型并通过修改纹理坐标(我已经在上面的方法 2 和 3 中进行了操作),您可以轻松地将偏移量发送到着色器以选择图集中的特定贴图:
v_fragmentTexCoord0 = u_texOffset + a_vertexTexCoord0 * u_texScale;
这提供了很大的灵活性并减少了纹理绑定的数量。这基本上就是我现在在游戏中所做的。但IS IT更快地访问较大纹理的一小部分并在顶点着色器中进行上述数学运算?或者一遍又一遍地重复绑定较小的纹理是否更快?特别是如果您不按纹理对对象进行排序。
我知道这很多。但这里的主要问题是,考虑到速度+便利性,最有效的方法是什么?对于多个纹理,方法 4 会更快还是多次重新绑定会更快?或者还有其他我忽略的方式。我看到所有这些 3D 游戏都有大量的图形和区域覆盖。他们如何保持较高的帧速率,尤其是在 iPhone4 等较旧的设备上?
**** 更新 ****
由于这几天我突然有了两个答案,我就这么说。基本上我确实找到了答案。或者AN回答。问题是哪种方法更有效?这意味着哪种方法会产生最佳帧速率。我已经尝试了上面的各种方法,在 iPhone 5 上它们都差不多快。 iPhone5/5S 拥有速度极快的 GPU。重要的是在 iPhone4/4S 等较旧的设备上,或视网膜 iPad 等较大的设备上。我的测试不科学,而且我没有毫秒速度可供报告。但是4texture2D()
对 4 个 RGBA 纹理的调用实际上与 4 个 RGBA 纹理一样快,甚至可能更快texture2d()
调用带有偏移量的单个纹理。当然,我在顶点着色器而不是片段着色器中进行这些偏移计算(从来不在片段着色器中)。
所以也许有一天我会做测试并制作一个包含一些数据的网格来报告。但我现在没有时间这样做并自己写出正确的答案。我无法真正勾选任何其他未回答问题的答案,因为这不是这样的工作原理。
不过还是谢谢那些回答的人。看看我的另一个问题,它也回答了其中的一些问题:在 iOS 上从两个 jpeg 加载 RGBA 图像 - OpenGL ES 2.0 https://stackoverflow.com/questions/22263863/load-an-rgba-image-from-two-jpegs-on-ios-opengl-es-2-0