用纹理图集优化3D场景

在 Unity 中开发移动应用程序时,确保一切都得到优化始终至关重要。 最大化帧速率使我们能够专注于优化脚本、烘焙灯光、修改对象等。

当我们将移动应用程序带入虚拟现实时,这一点变得更加重要。 虽然我们可以关注许多领域来采取措施进行优化,但我们将只关注其中一个,即纹理图集(Texture Atlas)。

1、为什么要使用纹理图集?

纹理图集是我们将所有游戏图像或纹理逻辑分组到一个文件(也称为精灵表)中的一种方法。

当在 Blender 等建模程序中创建对象时,每个图像的坐标可以映射到我们想要使用的对象上。 这使得 Unity 中的渲染效率更高,我们可以让许多对象共享相同的材质。 当我们后续将对象设为静态时,Unity 就可以使用静态批处理,将(不移动的)游戏对象组合成大网格,并以更快的方式渲染它们。

2、制作我们的贴图

为了创建和使用纹理图集,我们需要能够为 Unity 创建自己的对象并将图像放入一个文件中。 为了将图像放入一个图形中,我们可以使用 Gimp,一个免费的图像编辑程序。 为了将我们的图集映射到一个对象上,我们可以使用 Blender,一个 3D 建模程序。

2.1 添加图像

为了这个演示,我们只看下面的几个对象。 想到一些我们想要使用的材料,我们可以在网上抓取它们并将它们保存到我们的计算机上。

保存图像后,我们可以在 Gimp 中创建 1028x1028 图像,并将每个图像拖放到我们的纹理图集中。 图像的大小可以是任何大小,只要不是很大即可。

当收集纹理图集的图像时,对图像进行逻辑分组是有意义的。 如果我们有一栋建筑物,我们可以将所有这些纹理(砖块、墙壁、地板等)放入一个纹理集中。 对于我们的角色,我们也可以这样做。 这使事情变得井井有条,但在这种情况下我们并不挑剔。 让我们把它们全部扔到这里吧。

使用 Gimp 将所有图像拖入我们的 1028x1028

下面是最后得到的完整图像:

完整的纹理图集

需要注意的一件事是这些都是简单的图像。 有一些程序可以为 3D 模型生成精致的纹理。 然而,在我们的例子中,即使没有它,我们仍然可以在形状上获得漂亮的纹理。

2.2 创建和映射我们的贴图

纹理图集完成后,下一步是打开 Blender。 我们可以通过按住 Shift + A 并选择“网格”>“立方体”来添加要使用的图元。

Shift + A 快捷键
看……立方体

下一步是分割窗口,以便可以看到我们的对象,很快就能看到我们的 UV 图像编辑器。 我们可以单击窗口的右上角并向左拖动以创建两个视图。

然后在底部选择编辑器类型图标以切换到 UV/图像编辑器视图。

现在设置了视图,我们就可以做事情了。 当 Unity 将材质分配给游戏对象时,它使用 UV 坐标作为参考,以便正确映射每个纹理。 UV 很像 X/Y 坐标系。 如果未定义,我们的整个纹理图集将映射到该对象。 我们很快就会发现,通过将模型的 UV 坐标定义到图集纹理,Unity 将知道对象的哪一部分与纹理图集匹配。

左边是 3D 查看器……右边是 UV/图像编辑器

选择左侧窗口,我们可以点击选项卡并切换到编辑模式。 这使我们可以选择对象的所有或单个部分。 通过 快捷键a 我们可以选择所有内容。

在编辑模式下,我们可以仅选择面来定位立方体的一侧。

2.3 展开我们的对象

选择所有对象后,我们必须打开它。 这将获取我们的 3D 形状并将其展开到 2D 平面上,以便我们可以定义将其映射到纹理的哪个部分。

回到立方体的 3D 视图,我们可以点击 u 进行展开,然后选择展开。 这将在我们的 UV/图像编辑器中展开所有面。 如果我们选择智能 UV 投影,我们可以将所有面映射到彼此相邻的位置。 这在展开复杂对象时非常有用。

左图:展开示例 — 右图:智能 UV 投影

接下来,打开我们的纹理图集并加载它。

这将加载图像并让我们看到展开的图像落在纹理上的位置。 显然,我们不需要整个图像,因此我们需要点击 a 来选择所有内容。 然后我们可以按 s 将选区缩放到我们选择的纹理。

展开的图像(当前未选择)覆盖整个纹理图集

一旦展开的比例缩小到我们喜欢的程度,我们就可以按 g 抓住它并将其移动到我们目标的任何纹理。 在这种情况下,浅木纹。

完成后,我们可以保存文件,现在我们有了一个带有映射 UV 坐标的对象,引用了这个纹理图集。

2.3 映射不同的面

在进入 Unity 之前,应该注意的是,我们可以单独选择每个面。 就我们的立方体而言,每个面都可以映射到纹理图集中的不同纹理,并且效果很好。 在这种情况下,立方体已经映射,我们可以在 3D 查看器中选择立方体的一个面。 我们需要确保处于编辑模式并且可以选择面。

其对应的展开如下所示。 转到 UV/图像编辑器并点击 a 选择所有点,然后我们可以点击 g 将展开的立方体面移动到我们想要分配的任何纹理。

我们可以对每个面或少数几个面执行此操作,以实现更精细的纹理。 当我们的模型变得更加复杂时,这会很有用。

绘制立方体的三个独立面
选择要在 UV/图像编辑器中绘制的凳子底座

在进入 Unity 之前,我们创建几个对象(球体、圆柱体等)并将它们映射到我们的纹理图集中。 然后我们就准备好了。

3、将3D模型导入Unity

一旦我们在 Blender 中创建了已映射到纹理图集的对象,我们就可以将这些对象拖到 Unity 中,拖到我们的项目窗口中。 如果我们有一个 prefabs 文件夹,我们可以将它们放入其中。

通常,我们的对象及其材质将导入到 Unity 的材质文件夹内。 但有时,你可能会发现只是浪费了一个小时来打开物体。 如果发生这种情况,有解决办法。 在 Unity 中,我们应该导入纹理图集。 我们可以将其与其余纹理放在一起。

然后在项目窗口中右键单击并选择“创建”>“材质”。 选择材质后,查看检查器并确保我们选择了移动/不发光(支持光照贴图)。 由于我们专注于移动设备,因此我们将把所有灯光烘焙到纹理中。 分配移动/无光照着色器是实现此目的的好方法。

一旦我们指定了“移动/不照明”,我们就可以选择与该材质关联的纹理。 这是我们单击“选择”并找到我们的纹理图集的地方。

拥有 Mobile/Unlit 可确保移动设备上的最佳性能
一旦我们的纹理被分配给材质,对象就会更新

现在我们有了使用纹理图集的材质,我们在 Blender 中映射的任何对象都可以很好地与我们指定的纹理同步。

3.1 静态化并烘焙场景

使用相同材质设置所有对象后,下一步就是利用 Unity 的静态批处理。 通过将所有对象标记为静态,可以快速完成此操作。 假设这些在我们的应用程序中没有动画,这是必须做的。

使用一些聚光灯以获得良好的效果,我们确保将它们标记为区域(仅烘焙)。 这样,我们的场景显然得到了一些光线,而且我们的对象现在也可以将光照烘焙到它们的纹理上,因为它们现在是静态的。

为了使这些更改可见,我们可以转到“窗口”>“照明”>“设置”并为场景生成照明。

烘焙场景

3.2 静态批在哪里?

我们在开始时提到,静态批处理是优化场景渲染的一种方法。 Unity 采用具有相同材质的静态对象,然后将其渲染为一个大网格,以加快速度。 Unity 中更少的绘制调用意味着每秒更多的帧,当我们有 1000 多个对象时,我们就会明白为什么这如此重要。

由于我们为对象创建了纹理图集,Unity 可以完成一次绘制所有游戏对象。 查看实际情况的一种方法是使用帧调试器。

3.3 Unity 的帧调试器

帧调试器允许我们在播放模式期间暂停游戏并分解每个帧的渲染方式。 通过逐步浏览右侧层次结构中的每个项目,我们可以看到每个渲染的顺序。 请注意,Static Batch 行在游戏视图下方突出显示,我们看到 Unity 通过一次绘制调用一次性渲染所有这些对象。 很好,对吧?

如果我们为每个对象分配不同的材质,我们就会增加绘制调用并强制 Unity 单独渲染每个对象,如下所示。 效率不太高。

没有共享材材质,就没有静态批处理

4、图集、拆包和批次……

生成简单的纹理图集可以让我们在 Unity 中跨多个游戏对象创建共享材质。 如果我们能够在 Blender 等 3D 建模工具中创建或修改模型,我们就可以更好地控制这些纹理的映射,并使我们的应用程序运行更高效。

尽管移动设备变得越来越强大,但我们仍在不断突破硬件的极限。 我们需要优化应用程序以提供最佳用户体验的多种方法中,这只是实现这一目标的重要一步。 记住纹理图集。


原文链接:Texture Atlasing: An Inside Look At Optimizing 3D Worlds!

BimAnt翻译整理,转载请标明出处