首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多纹理化的最有效方法- iOS,OpenGL ES2,优化

多纹理化的最有效方法- iOS,OpenGL ES2,优化
EN

Stack Overflow用户
提问于 2014-03-01 05:24:56
回答 2查看 779关注 0票数 6

我正在寻找在OpenGL ES2 on iOS中处理多纹理的最有效的方法。我所说的“高效”指的是即使在较旧的iOS设备(iPhone 4和更高版本)上也是最快的渲染--但同时也平衡了便利性。

我考虑过(并尝试过)几种不同的方法。但是遇到了一些问题和问题。

方法1 -我的基本值和正常值都是rgb,没有。对于这些物体,我不需要透明度。我的发射信息和镜面信息都只有一个通道。为了减少texture2D()调用,我想我可以将发射存储为基本的alpha通道,而镜面存储为普通的alpha。如果每个文件都在自己的文件中,则如下所示:

到目前为止,我的问题是找到一种文件格式,它将支持一个完整的非乘α通道。PNG只是没有为我工作过。我试图将其保存为PNG的每一种方式都会使.alpha与文件上的.rgb相乘(通过photoshop),基本上销毁.rgb。当我重新加载文件时,任何带有0.0 alpha的像素都有一个黑色的rgb。我在没有活动的情况下发布了这个问题here

我知道如果我能想出一种方法来保存和加载这个独立的第4通道,这个方法会产生更快的呈现效果。但到目前为止我还没能继续前进。

方法2 -当这不起作用时,我转到一个单一的4路纹理,其中每个象限有一个不同的地图。这并不减少texture2D()调用,但它减少了在着色器中访问纹理的数量。

4路纹理确实要求我修改纹理坐标内的着色器.为了模型的灵活性,我将纹理和弦保留在模型的结构中,并在着色器中修改它们,如下所示:

代码语言:javascript
复制
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

为了避免dynamic texture lookups (谢谢Brad Larson),我将这些偏移移到顶点着色器,并将它们排除在片段着色器之外。

但我在这里的问题是:是否减少了用于着色的纹理采样器的数量?还是在这里使用4种不同的小纹理更好呢?

我确实有一个问题,就是在不同的地图之间流血。由于线性纹理映射,一些蓝色法线像素的纹理平均为1.0。这在靠近接缝的物体上增加了一个蓝色的边缘。为了避免它,我不得不改变我的紫外线映射,以避免太接近边缘。对很多物体来说这是一种痛苦。

方法3是将方法1和2组合在一起,其中一边是base.rgb +排放.a,另一边是normal.rgb +投机性.a。但是,我仍然有这个问题,让一个独立的alpha保存在一个文件中。

也许我可以将它们保存为两个文件,但是在将它们发送到openGL之前,可以在加载期间将它们组合起来。我得试试这么做。

方法4最后,在一个三维世界中,如果我有20个不同的墙面纹理,这些是单独的文件还是全部打包在一个单一的纹理地图集?我最近注意到,在某种程度上,“我的世界”从一本地图集变成了一个单独的纹理--尽管它们每个都是16x16。

使用单个模型,通过修改纹理坐标(我已经在上面的方法2和3中做了),您可以很容易地向着色器发送偏移量,以便在地图集中选择特定的地图:

代码语言:javascript
复制
v_fragmentTexCoord0 = u_texOffset + a_vertexTexCoord0 * u_texScale;

这提供了很大的灵活性,减少了纹理绑定的数量。这基本上就是我现在在比赛中所做的。但是,是否更快地访问更大纹理的一小部分,并在顶点着色器中使用上述数学?还是一次又一次地将较小的纹理反复绑定更快?尤其是当你不按纹理对物体排序的时候。

我知道这事太多了。但这里的主要问题是,考虑到速度+方便,最有效的方法是什么?对于多个纹理,方法4是更快,还是多个重新绑定更快?或者有什么别的方法让我忽略了。我看到所有这些3d游戏与大量的图形和地区覆盖。他们如何保持帧速率上升,特别是在像iphone4这样的老设备上?

*更新*

因为在过去的几天里我突然得到了两个答案,所以我会这么说。基本上我找到了答案。或者一个的答案。问题是哪种方法更有效?这意味着哪种方法会产生最佳的帧速率。我已经尝试过上面的各种方法,在iPhone 5上,它们几乎都一样快。iPhone5 5/5S有一个非常快的gpu。重要的是在更老的设备上,比如iPhone4/4S,或者更大的设备上,比如视网膜iPad。我的测试是不科学的,我也没有速度报告。但是,对4个RGBA纹理的4个texture2D()调用实际上与对单个带有偏移的纹理的4个texture2d()调用一样快,甚至可能更快。当然,我在顶点着色器中做那些偏移计算,而不是在碎片着色器中(从来没有在片段着色器中)。

所以也许有一天我会做测试,用一些数字来报告。但我现在没有时间去做这件事,自己写一个正确的答案。而且我也不能在没有回答问题的其他答案上加签,因为这不是这样的工作方式。

但多亏了那些回答的人。看看我的另一个问题,它也回答了其中的一些问题:Load an RGBA image from two jpegs on iOS - OpenGL ES 2.0

EN

回答 2

Stack Overflow用户

发布于 2014-06-17 06:54:31

在内容管道中有一个post处理步骤,您可以将rgb与alpha纹理合并,并在打包游戏时将其存储在. Ktx文件中,或者在编译时将其存储为post构建事件。

这是相当简单的格式,编写这样的命令行工具可以加载2个png并将它们合并到一个Ktx,rgb + alpha中。

这样做的一些好处是,在游戏启动时加载文件时,cpu开销更小,因此游戏开始得更快。-一些GPUso本机不支持rgb 24位格式,这将迫使驱动程序内部将其转换为rgba 32位。这为加载阶段和临时内存使用增加了更多时间。

现在,当您在纹理对象中获得数据时,您确实希望最小化纹理采样,因为它意味着大量的gpu操作和内存访问(取决于过滤模式)。

我建议使用两个纹理,每个纹理层有两个层,因为如果确实将所有纹理添加到相同的纹理中,那么当您使用双线性或mipmap进行采样时,可能会出现潜在的伪影,因为它可能包括靠近边缘的相邻像素,其中一个纹理层结束,第二个纹理层开始,或者如果您决定生成mipmap。

作为一个额外的改进,我建议不要在Ktx中使用原始的rgba 32位数据,而是将其压缩为dxt或pvrtc格式。这将使用更少的内存,这意味着更快的加载时间和更少的内存传输到gpu,因为内存带宽是有限的。当然,将压缩机添加到后处理工具会稍微复杂一些。请注意,根据算法和实现,压缩的纹理会松一些质量。

票数 1
EN

Stack Overflow用户

发布于 2014-06-17 10:28:02

愚蠢的问题,但你确定你是有限的采样器?在我看来,与你的“双向纹理”,你可能会吸引很多纹理数据,你可能反而是带宽有限。

如果您使用3种纹理BaseRGB、NormalRBG和组合Emission+Specular并使用PVRTC压缩,该怎么办?根据细节,您甚至可以为BaseRGB和/或Emission+Specular使用2bpp (而不是4bpp)。

对于正常人,我可能会坚持4磅。此外,如果您能够负担得起着色指令,只需存储R&G通道(将0放入蓝色通道),然后用一些数学方法重新导出蓝色通道。这应该会使质量更好。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22110519

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档