如果你曾经尝试将从 CAD 程序导出的 3D 模型上传到 WebGL 或 AR 服务,那么可能会遇到最大文件大小、永无休止的进度条和糟糕的帧速率等问题。
为了创作良好的在线交互体验,优化 3D 数据的大小和性能至关重要。 这也有利于你的盈利,因为较小的文件需要较少的云存储并通过 CDN 推送较少的数据。
本文介绍如何设计自动化管道来生成良好的可视化 3D 模型。 这使你可以创作包含完整细节的模型,并随时使用适合 Web 和 AR 的模型,并且只需最少的手动操作。
当为离线渲染器中的制造或可视化而编写 3D 模型时,它们通常不适合在手持设备、Web 浏览器、AR 应用程序和其他规格较低的设备中显示。 这意味着内容制作团队通常最终会花费大量时间来优化源资产或将源资产转换为低端设备,以确保流畅的渲染和快速下载。
在本文中,我们将总体介绍 3D 资源的优化,特别是此过程如何与 Substance 材质和库交互。
推荐:用 NSDT编辑器 快速搭建可编程3D场景
手动优化 3D 模型不仅枯燥且耗时,而且很容易成为生产流程中的瓶颈。 问题在于,优化本质上是源资产的下游,这意味着对源资产(3D 模型、材质等)的任何更改都需要反映在优化资产中。 因此,能够尽早预览优化内容与优化所花费的时间之间存在冲突。
如果预计源模型将在生产过程中更改几次,那么仅在最终确定后对其进行优化会更有效。
这使得优化成为自动化的首要目标。 这不是一个需要艺术表达的地方。 自动化管道将检测资产库的任何方面何时发生变化,并重新优化受影响的资产。
1、3D 优化管线概述
让我们看一下类似电子商务的设置。
源 3D 模型可以来自许多不同的地方,例如 CAD 包、DCC 包等。 除了顶点和多边形之外,我们假设它们还有纹理 UV 和法线信息。
材质库是用于 3D 模型的一组源材质。 下图来自 Substance Source,这是材质的一个很好的起点 - 但任何此类材料也可以在内部构建,也许是根据真实世界的材料样本创建的。
Substance的材质是程序性的,允许用户设置参数并定义预设。 材质与特定应用程序的设置一起称为材质实例。 作为示例,相同的皮革材料可以被实例化为红色和蓝色皮革材料。
选择材质后,我们将其分配给对象的特定部分。 对于沙发,你可以在垫子上指定织物材料,在沙发腿上指定金属:
无材质的模型(左)和已分配材质的模型(右)
同一模型还可以有多种分配配置:在本例中,同一张沙发可以有不同的织物和皮革垫子。
同一模型的两种材质排列
1.1 产出目标
不同的设备具有不同的功能,在上一代手机的浏览器中运行良好的功能可能与高端 PC 的运行方式有很大不同,因此我们希望能够针对不同的目标生产不同的模型。
最简单的形式是,管线看起来像这样:
请注意,此过程显示正在处理一个模型,但其想法是具有多个材质配置的多个输出的多个对象都会经历此过程。
概念管线中有两个阶段:优化模型,然后应用材质。 请注意,优化模型是这些步骤中的第一步,应用材质发生在下游。 这意味着对 3D 模型的任何更改都将触发材质的优化和重新应用,但无需重新优化即可对材质进行更改。
该管线经过简化,并且在现实生活中的管线中可能存在更多阶段和依赖性。
1.2 高效自动化的注意事项
通过像上面这样的结构化管线,我们可以自动化生成优化模型的过程 - 这意味着我们可以在产品的整个生命周期中拥有最新的可视化模型。
为了有效地运行资产管线,我们需要了解操作之间的关系,以及哪些数据影响哪些输出。 这意味着当源数据发生变化时,我们可以快速找出需要构建的内容。
一些例子:
- 当材质库中的材质发生更改时,使用该材质的任何输出都需要重新构建;
- 当添加新的输出目标时,需要针对该目标处理所有模型;
- 当 3D 模型发生更改时,该模型的所有目标的所有配置都需要重新构建。
- 何时以及如何触发自动化流程需要在需要多快的结果和使用多少计算能力之间取得平衡。 每次发生更改时触发运行将快速获得结果,但这也可能意味着你花费大量时间处理很快会再次更改的模型。
另一种方法是在处理能力更可用或更便宜时每晚运行该流程,这意味着每天早上都应该准备好最新的模型。
还可以让用户决定何时运行模型的流程,以便他们可以在需要时获得最新的模型。
3D 工作流程自动化部分的一个常见问题是失去艺术控制。 情况不应该是这样,因为所有艺术决策都是在自动化发生之前做出的。 优化阶段应该以与存储为 .tiff 文件的图像在放置到网站上之前可能被压缩为 .jpeg 格式相同的方式来看待。 自动化优化阶段应该可以腾出更多时间进行创造性工作,因为你不需要花时间优化部署模型。
使用自动化解决方案时需要考虑的主要问题是如何以及何时进行手动修复。 如果过程的输出对于某个模型来说不够好,本能通常是修复生成的输出资产。 这种方法的问题在于,每次更改资产时都需要重新应用修复(因为更改是自动化管道的下游)。 一般来说,所有输出调整都应作为自动化管道中的设置来完成,以便下次运行管道时可以应用它们。 除非您确定模型是其最终状态,否则不鼓励手动修复。
调整的一个好方法是分层设置覆盖。 可以在每个资产级别覆盖管道的默认值,因此你可以为效果不佳的资产设置更高的质量值,而不会影响任何其他资产。
2、为什么要优化3D模型?
输入数据的优化是为网络和手持设备制作良好 3D 模型的关键。 CAD 模型或为高端渲染制作的模型过于详细、太大,因此通常不适合该用途。
你希望通过优化改进的主要内容是:
- 渲染性能
- 电池寿命
- 下载大小
- 内存使用情况
这些不同的目标通常是一致的:较小的模型通常渲染速度更快,并且在设备上使用更少的电池电量。
2.1 评估优化过的模型
在深入研究我们优化的内容之前,重要的是要确保我们知道如何评估结果的视觉质量。 关键始终是根据模型的用途进行评估。 如果你制作的模型旨在在 400×400 像素大小的 Web 查看器或手持设备上看起来不错,那么花时间调整设置以保留细节或删除在不放大的情况下无法看到的伪影将意味着“我们将提供一个过于详细且过于繁重而无法下载的模型。
当谈到渲染性能时,如果没有基准测试,并不总是容易预测什么会产生最佳效果,但有许多启发式方法结合起来往往会产生如下所述的良好结果。 另请记住,即使你达到了目标帧速率和下载大小,在手持设备上,更小和更快仍然很重要,因为不太繁忙的 GPU 消耗的电池更少。 游戏艺术家的 GPU 性能一文更详细地介绍了该主题,是了解快速渲染 3D 模型的构成要素的良好资源。
2.2 多边形数
多边形数量和多边形密度是使模型快速渲染和快速下载的重要组成部分。 更多的多边形和顶点意味着 GPU 必须进行更多的计算才能生成图像。
GPU 通常更适合渲染更大且尺寸更均匀的多边形。 GPU 高度并行,并针对较大的多边形进行了优化。 多边形越小越薄,在被遮蔽的区域上浪费的并行性就越多。 这个问题被称为过度着色,并在上面的链接文章中进行了介绍。
一般来说,最好查看生成的模型的线框,并确保在以预期查看的尺寸可视化模型时线框不是很密集。
在不牺牲细节的情况下减少多边形数量的有效方法是使用法线贴图。 这个想法是,我们对光线与物体的相互作用比对物体轮廓的相互作用更敏感。 这意味着我们可以将细节从三角形数据移动到法线贴图(即从模型到纹理)并使用更大的多边形,并且仍然从照明中的原始数据获取细节。
这是在没有(左)和(右)包含原始模型细节的法线贴图的情况下优化的同一模型:
将模型优化到大多数小细节都位于法线贴图中的水平也允许网格具有更好的 UV 贴图。 创建 UV 贴图时,小细节和锐利边缘通常是一个问题。 更简单的模型往往具有更少的较大图表、更少的填充空间浪费以及更少的可见接缝——这对于自动 UV 贴图模型来说可能是一个问题。
2.3 GPU 绘制调用
绘制调用表示渲染器需要与 GPU 通信多少次才能渲染对象。 一般来说,每当你从一个对象切换到另一个对象或想要使用不同的纹理时,GPU 都需要得到通知。 这意味着,如果同一模型仅由一个网格和一组纹理组成,则分割为多个部分或使用许多不同材质的对象的渲染成本将更高。
2.4 纹理分辨率
GPU 擅长选择具有适合模型查看尺寸的分辨率的纹理,并避免与使用过高纹理分辨率相关的性能和质量问题。 考虑到所传输模型的查看限制,很容易包含不必要的高分辨率纹理。 它们实际上不会以全分辨率显示,这会导致用户不必要的下载时间。
2.5 过度绘制
过度绘制是在渲染最终位于其他多边形后面的多边形时发生的情况。 对于大多数对象来说,一些过度绘制是不可避免的。 然而,对于简单的查看场景,也可能存在无论用户如何与模型交互都永远看不到的多边形。 例如,想象一下一张沙发,其座垫是作为单独的物体放置在沙发框架顶部的。 在用户无法移除坐垫的情况下,坐垫的底部和放置坐垫的框架部分将永远不会被看到。
一个好的优化解决方案可以识别这些不必要的区域并消除它们,这样就不必下载或渲染不可见区域中的多边形。 更重要的是,在许多纹理场景中,纹理图像空间被分配给这些不可见的多边形,这意味着你将浪费纹理数据,对下载大小产生负面影响,并降低实际可见区域的纹理分辨率。
2.6 模型优化在保护知识产权方面的作用
最后,在处理源自 CAD 程序的数据时,3D 模型通常包含与产品制造方式相关的详细信息。 优化解决方案可以删除内部对象并将小细节转换为法线贴图和纹理信息。 这使得很难从仅用于可视化的模型中对产品进行逆向工程。
3、良好管道的基础
实现包含上述所有方面的自动管道可能是一项具有挑战性的任务。 但掌握正确的基础知识可以避免以后出现很多麻烦。
3.1 数据布局
任何成功的自动化工作的先决条件是对数据采用结构化方法。 对所使用的材质库以及将哪些材质分配给哪个对象有清晰的概念至关重要。 你还希望使该材质对管道可见,这允许管道跟踪更改,这样就不会浪费时间重新处理未更改的内容。
所有数据都应存储在某个中央存储库中,并且不允许引用该存储库之外的任何数据,以确保可以找到整个源资产,而无需安装额外的共享网络驱动器(或数据可以存在的其他潜在位置)。 选择数据格式时,它们应该是独立的,或者对其他文件的任何引用都应该易于访问,以帮助跟踪。
3.2 依赖性跟踪
跟踪资产之间的关系使你可以仅重建已更改的内容。 你的依赖项跟踪和作业执行越细粒度,你的增量资产构建就越小。
例如,假设你的依赖项跟踪将材质库视为单个不透明实体。 如果你对一种材料进行更改,它将强制重建每个模型,以保证所有材料数据都是最新的。 如果你跟踪单个材质的更改,则将只允许重建那些使用修改后的材质的对象。
3.3 执行
解决依赖关系后,你最终将需要执行多个构建任务来生成所需的输出。 这些任务通常在很大程度上是独立的,并且可以并行运行。 这意味着构建过程可以扩展到多个 CPU 或机器。 执行部分涉及调度这些任务,并确保调用适当的工具来产生所需的输出。
在优化管道中执行的任务示例包括:
- 网格优化
- 纹理渲染
- 纹理压缩
- 场景组装
3.4 缓存
构建过程中的中间结果可以被缓存以加速增量构建。 一个例子是优化的低多边形输出。 这可能无法直接用作资产,因为它需要在准备部署之前应用纹理。 然而,这个低多边形资源可以作为中间步骤进行缓存。 这样,当更新资产中使用的材质时,不必重建它,并且可以简化处理以避免重新进行优化。
缓存是解决此问题的一种便捷方法,因为可以清理缓存而不会丢失任何无法重新创建的数据。 这确保了可以不断地修剪大小,以在增量构建性能和临时数据存储之间获得良好的平衡。
4、3D资产优化管线示例
为了为这篇有些抽象的文章提供一些具体的内容,我决定构建一个资产优化管线的简单实现。
我在这里的目的是展示管线的不同方面,特别强调展示substance的材质如何参与资产优化工作流程。
该管线的目标是采用高分辨率 3D 家具模型,并自动生成体积小且渲染速度快的模型。 该管道主要用 Python 实现,旨在在单个 Windows 计算机上本地运行。
描述的原始管线如下所示:
向处理框添加详细信息,我们得到如下结果:
这是通过示例管线的单个优化模型的概述。 该管线可以应用于多个模型和同一模型的多个质量。 派生资产代表可以由构建系统缓存以加速增量构建的中间输出。
4.1 数据
该管线中的数据是磁盘上的一组文件,以使事情尽可能简单。 它们分为:
- 网格:.obj 文件
- 源材质:Substance .sbsar 文件
- 材质库:引用 .sbsar 文件的 .json 文档,以及用于选择预设、参数和材质缩放的附加设置。
- 材质分配:.json 文档将模型的各个部分与材质实例和每个模型的缩放相关联。
- 管线:描述优化目标配置文件(例如移动设备、VR 等)的 .json 文档。
- 作业:.json 文档描述要优化哪些模型、要使用哪些材料排列以及通过哪些管道生成输出。
4.2 OBJ 作为网格文件格式
我使用 .obj 文件来处理几何图形的原因是简单。 它们很容易创建和共享。 由于它们是基于文本的,因此如果组名称由于某种原因丢失或错误,也可以轻松编辑它们。
管线中网格的主要限制是 UV 图表必须适合 UV 页面。 它们不能用于将材质平铺在形状上,但如果愿意,它们可以重叠或位于不同的页面上。 理想情况下,所有 UV 图表的大小都应与其在模型上的世界空间中的大小相关,以便在所有部件上应用相同比例的纹理。
下面可以看到同一模型的两种不同的 UV 布局。 左侧的布局会产生问题,因为它的图表跨越了 UV 平铺边界; 相反,右侧的布局将正常运行。
4.3 材质库
使用的材质库格式是自定义 .json 文件,而不是 .obj 的MTL 格式。 MTL 格式不支持绑定 Substance 材质或设置程序参数,因此我决定引入具有这些功能的简单自定义格式。
这是材质库中材质实例的示例:
{ // ... // Leather is the name of the instance "Leather": { // sbsar file referenced "sbsar": "${assets}/material_library/sbsar/Sofa_Leather.sbsar", "parameters": { // These are parameters on the sbsar "normal_format": 1, "Albedo_Color": [ 0.160, 0.160, 0.160, 1 ], "Roughness_Base": 0.353 }, "scale": [ // A material relative scale for the UV 20.0, 20.0 ] } // Additional material instances // ...
}
在示例管线中,所有材质实例都存储在单个材质库文件中。
这些材质基于 PBR 金属粗糙度,使用以下贴图:
- Base color:基本色贴图
- Normal:法线贴图
- Roughness:粗糙度贴图
- Metallic:金属度贴图
4.4 材质分配
材质分配是一个单独的文件,将模型中的零件与特定材料实例相关联。 材质分配还包括特定模型的比例因子,以补偿不同模型之间纹理图表比例之间的差异。
将材质分配与几何体分离允许用户为同一模型指定不同的材质配置,或者在共享相同组名称的模型之间共享材质配置。
这是材质分配配置的示例:
{ // Legs is the name of the part in OBJ file // If similar scenes share part names the same // material assignment file can be used for all of them "Legs": { // Material refers to a material instance // in the library "material": "Metal", // Scale is the scale of the material associated with this // part. It will be multiplied by the scale from the // material instance "scale": [ 1.0, 1.0 ] }, // Additional assignments to other parts "Cushions": { "material": "Leather", "scale": [ 1.0, 1.0 ] }, "Frame": { "material": "Wood", "scale": [ 1.0, 1.0 ] }
}
4.5 GLB 作为输出格式
.glb 文件是 .gltf 的一个版本,其中网格数据、场景数据和纹理打包到单个文件中。 我使用 .glb 作为该过程的输出格式,因为它是网格、材质和所有生成的纹理的紧凑文件表示形式,并且为 Web 和移动 3D 查看器提供了广泛的行业支持。
4.6 管线定义
该管线描述了针对特定目标硬件要执行的优化的不同方面。
示例管线如下所示:
{ "import": { // Resolution for reference source textures // Insufficient resolution in the source textures // will come out as blurry areas in the model // Must be an integer power of 2 "material_resolution": 2048 }, "reference": { // Enable or disable reference model // creation "enable": true }, "optimize": { // Target size in pixels for which the model // quality should be optimized. Anything above // 2000 will be very time consuming to produce "screen_size": 600, // Resolution for the utility maps for the model "texture_resolution": 1024, // Bake tangent space using Substance Automation // Toolkit if true, use Simplygon if false "bake_tangent_space_SAT": true, "remeshing_settings": { // Angle in degrees between surfaces in // a vertex to split it with discrete // normals "hard_edge_angle": 75 }, "parameterizer_settings": { // How much stretching is allowed inside // a chart in the generated UV layout for // the model "max_stretch": 0.33, // How prioritized large charts are for the // UV layout "large_charts_importance": 0.2 } }, "render": { // Texture resolution for the atlas // for the optimized model. Should typically // be the same as the texture_resolution in // optimize "texture_resolution": 1024, // Offset for mip map selection. 0 is default, // Negative values gives sharper and noisier results // Positive values give blurrier results "mip_bias": 0, // Enable FXAA post processing on the map to give // smoother edges between different materials // (doesn't apply to normal maps) "enable_fxaa": true, // Blurring of the material id mask before compositing // to give smoother borders between materials // (doesn't apply to the normal map) "mask_blur": 0.25, // Enable FXAA post processing on the normal map to // give smoother edges between different materials "enable_fxaa_normal": true, // Blurring of the material id mask before compositing // the normal map to give smoother borders between // materials "mask_blur_normal": 0.25, // Clean up edges around charts on normal maps "edge_clean_normal_maps": false, // Normal map output format and filtering // For most cases 8 bpp is enough but // for low roughness and 16bpp is needed to avoid // artifacts "output_normal_map_bpp": 8, // Enable dithering for the normal map. Typically only // relevant for 8 bpp maps "enable_normal_map_dithering": true, // Dithering intensity. Represents 1/x. Use 256 to // get one bit of noise for an 8bpp map "normal_map_dithering_range": 256, // Paths to tools for compositing materials and // transforming normal maps "tools": { "transfer_texture": "${tools}/MultiMapBlend.sbsar", "transform_normals": "${tools}/transform_tangents.sbsar" } }
}
4.7 作业
作业是指定所有模型、材质分配和管线流程的入口点。 这是一个作业的示例:
{ // Scenes to optimize "scenes": { "sofa-a1": { // OBJ file with geometry in "mesh": "${assets}/meshes/sofa-a1.obj", // Different material variations to produce for this model "material_variations": { // These are references to material assignment files "sofa-a1-leather": "${assets}/material_bindings/leather.json", "sofa-a1-fabric": "${assets}/material_bindings/fabric.json" } }, // Additional scenes goes here // ... }, // The material library with material instances in to use "material_library": "${assets}/material_library/material_library.json", "pipelines": { // A pipeline to run for the scenes "lq": { // Reference to the definition file "definition": "${assets}/pipelines/lq.json", // Paths for reference models and optimized models for // this pipeline "output_reference": "${outputs}/lq/reference", "output_optimized": "${outputs}/lq/optimized" }, // Additional pipelines to run // ... }
}
4.8 Python 作为管线的核心语言
Python 用于实现管线。 它是一种得到广泛支持的语言,并且具有可解决我们开箱即用的许多问题的功能。 我想在此过程中使用多个工具的绑定,使我可以轻松地专注于构建管线,而不是创建与其他应用程序的桥梁。
4.9 SCons 依赖跟踪和执行
用于管线的依赖性跟踪和执行系统是 SCons 构建系统。 它是一个基于 Python 的构建系统,可以跟踪依赖关系,并尝试通过仅重建自上次构建以来已更改的数据来最小化增量构建的成本。 这意味着它作为执行器工作,并且还为我们执行中间结果的缓存。
使用基于 Python 的构建系统很方便,因为这使得与构建操作的交互变得微不足道。 它也可以在 pip 模块系统中使用,任何拥有 Python 环境的人都可以轻松安装它。
该管线还支持直接作为Python脚本运行,从而更容易调试。 直接从脚本运行管线时,每次运行都会从头开始重建,并且不会进行独立任务的并行处理。
4.10 多边形优化
为了进行优化,我使用 Simplygon 的 Remesher 2.0。 Simplygon 被认为是游戏行业多边形优化的黄金标准,并且可以生成具有大量控制的非常紧凑的网格。 它有几种不同的优化策略,可以应用于不同的场景,但为了简单起见,我为管线选择了一种。
重新网格化器具有许多优化网格所需的属性:
- 它积极优化模型,如果使用正确,通常可以使用数量级更少的多边形产生良好的结果。
- 它清除了模型的所有内部几何形状,减少了透支,以及对未见表面的纹理分配,以及从模型中删除了不相关或专有信息。
- 它为整个模型创建一个新的纹理图集,这意味着它可以使用相同数量的纹理数据作为单个绘制调用进行渲染,无论模型最初是如何设置的。
- 它生成从源网格到目标网格的映射,以便源网格上的纹理、法线等可以正确、高质量地传输到优化模型。
- 它可以优化到特定的观看尺寸。 如果你想在具有特定尺寸或分辨率的查看器中以可预测的质量显示模型,可以将此信息作为目标分辨率提供; 你的结果将是适合该尺寸的模型。 重新网格化器还可以建议此特定质量的纹理大小,尽管此功能并未在此管线中使用。
- 过去我曾在 Simplygon 工作; 因此,我在这种情况下使用 Remesher 2.0 的原因之一就是因为我非常熟悉它 - 它产生的结果类型,以及如何配置该工具以更好地使用它。
Simplygon 还具有以下特性,使其适合该管线:
- 它有一个Python API,可以驱动所有优化和场景创建,从而可以轻松将该工具与管线的其余部分集成,该管道也是用Python创建的。
- 可以读写.obj和.glb文件。 这提供了很多关于如何管理材质和纹理的控制; 因此,该工具可用于读取带有自定义材质的源数据,并写出带有使用 Substance 生成的纹理的 .glb 文件。
重新网格化器是一种积极的优化技术,对于远距离观察的模型非常有效。 然而,它不适合需要过于仔细检查的模型,因为它会极大地影响对象轮廓和网格拓扑。 因此,它可能不是适合每个可视化场景的正确解决方案。 具体来说,此处使用的实现不能很好地处理透明度,在此管线中应避免这种情况。 通过破坏对象的网格拓扑,出于动画目的或类似目的而分开的部分可能会合并在一起,因此在这种情况下需要特别注意此过程。
还有许多其他的 3D 优化解决方案,但 Simplygon 是我的自然选择,因为它具有大量的功能以及我之前的使用经验。
4.11 对优化模型进行纹理化
我正在使用 Substance Automation Toolkit 将源网格中的纹理应用到优化的网格中。
Substance Automation Toolkit 允许我使用 Substance Designer 构建纹理传输过程中使用的所有操作,并从管道中的 Python 脚本调用它们。 它还允许我将优化与纹理生成分离为两个单独的阶段,这意味着 SCons 可以独立跟踪中间文件; 这样,只要模型保持不变,材料数据的更改就不会触发几何优化,因为优化本身与材料无关。
4.12 3D资产的格式转换
有时候你可能会需要将.obj或.gltf转换为其他格式的3D资产,例如DAE、GLB、PLY等,你可以考虑将 NSDT 3DConvert 这个强大的3D格式在线转换工具加入你的优化管线。
5、管线
该管线由以下阶段组成:
5.1 纹理渲染
在此阶段,我们查看所有已处理模型的材质绑定,并渲染所有使用的材质的 Substance PBR 图像。
5.2 参考模型创建
参考阶段将原始模型与渲染纹理结合起来,生成参考 .glb 文件。
此参考 .glb 文件不会在下游使用,但它是获得“之前”和“之后”镜头的良好资源。 它还有助于调试输出中的问题是在优化过程中引入的还是在源数据中。
由于上面 .obj 部分中描述的输入 UV 坐标的限制,UV 图表根据材质比例和分配比例进行缩放。 这可确保纹理与优化模型具有相同的比例。
5.3 优化
优化阶段加载源模型并使用 Simplygon 运行重新划分网格过程。 在此过程中,模型将获得与原始 UV 集无关的新 UV 集。
除了进行重新网格化之外,它还使用 Simplygon Geometry Casters 生成一组纹理,将纹理数据从源模型传输到优化模型。 这些贴图均在优化模型的新 UV 空间中表示:
-
材料 ID。 该贴图对每个纹素的材质索引进行编码。 通过此贴图,我们可以确定将哪种材质分配给源模型上的哪个点。
-
UVs。 该贴图对优化模型的纹理空间中源模型的 UV 坐标进行编码。 使用此贴图,我们可以确定在源模型上的纹理中查找何处以将数据传输到优化模型。
请注意,此贴图是 0-1 之间的 16bpp 贴图,这就是为什么我们不能使用 UV 来平铺材质。 分配的材质平铺应用于纹理渲染阶段。
UV 重映射纹理允许我们找到高多边形模型上的 UV 坐标,以便我们可以使用原始 UV 对优化模型进行纹理化:
- 源模型的环境遮挡,以优化模型的 UV 空间表示。 由于环境光遮挡是使用源模型中的细节创建的,因此它将为优化中可能丢失的区域提供遮挡,从而为丢失的几何图形提供视觉提示。
- 源模型的世界空间法线和切线,位于优化模型的 UV 空间中。 使用这两个贴图,我们可以捕获原始模型丢失的法线,并将应用于源模型的切线空间法线贴图转移到世界空间以进行进一步处理。
- 优化模型的世界空间法线和切线。 使用这些贴图,我们可以将法线从源模型转移到优化模型的切线空间法线贴图,捕获源网格法线和应用于其的切线空间法线贴图。
5.4 优化模型的纹理渲染
此阶段是一个多阶段过程,用于使用 Substance Automation Toolkit 从源模型传输所有源材质贴图。 由于物质图在处理中不能涉及几何体,因此它使用优化阶段的图来进行物质转移。 基本过程使用UV传输贴图选择采样位置,并根据材质ID贴图拾取纹理。
除了实用贴图和材质贴图之外,此阶段还采用与 mipmap 相关的每种材质的比例和参数作为输入,以控制平铺和过滤。
对于法线贴图,该过程更加复杂,因为它不仅需要对源纹理空间法线贴图进行采样,还需要涉及源网格和目标网格的法线和切线,以便为优化模型生成切线空间法线贴图。
请注意,整个过程可能会延迟到部署之后。 如果模型打算用于材质配置场景,则可以使用服务器上的 Substance 引擎或 Substance Automation Toolkit 运行此过程,以根据用户输入按需生成图像; 这比运行完整的优化管线要快得多。
5.5 最终场景组装
场景组件使用 Simplygon 加载优化的几何体并为其分配新的渲染贴图,以便保存带有材质的 .glb 文件。
5.6 作业处理的实施
作业处理作为 Python 脚本实现,该脚本理解并跟踪作业、管道、材料库等的所有依赖项。
不同的构建阶段是单独的Python文件,管道将相关参数和输入文件应用到每个阶段。 文件和参数的内容充当缓存键,这意味着如果自上次运行以来它们均未更改,则可以重用旧结果而不是重建它。
这意味着我们尝试对每个操作应用最少的参数集,以避免不必要的重新处理。 作为如何修剪数据的示例,仅将对象的已用材质分配文件中引用的材质实例应用为参数,以确保仅对正在处理的模型引用的材质实例进行更改才会触发新构建。
处理脚本可以通过两种方式运行:
- 构建模式。 在此模式下,它将识别所有构建操作并直接从 Python 执行。 请注意,这没有考虑任何缓存,并且每次运行时都会重新评估整个管道。
- 空运行(Dry run)模式。 在此模式下,将执行所有依赖项解析,但不会运行管道,而是生成具有相应参数的构建操作列表以及指定的所有输入和输出文件。
空运行模式的输出可以由任何构建系统使用,然后可以按依赖顺序并行构建结果。
5.7 SCons 脚本
SCons 脚本将以空运行模式执行管线,并使用输出来指定所有构建任务。
它使用与 python 脚本在构建模式下使用的相同构建操作来执行任务。 然后 SCons 将识别哪些任务是独立的,并尝试并行运行尽可能多的任务,以确保构建快速运行。 它还将识别哪些目标已经是最新的并保持它们不变,以便仅构建已更改的目标。
5.8 代码包
管线的代码可以在 Substance Share 上找到。 该软件包包含安装和运行说明,你可以自己探索管线。
6、结果
6.1 输出模型
这里的比较是将创建的参考模型与优化模型进行比较。
这不一定是同类比较,因为参考模型上的纹理密度明显更高,但它应该给出模型之间差异的估计。 另请注意,你自己的运行和我们的运行之间的数字可能不相同,因为优化和纹理过程都不是确定性的。
6.2 样本管线
该流程中有两条管线,LQ 和 HQ,分别用于低质量和高质量。 LQ 经过积极优化,旨在用于类似于缩略图大小的模型。 HQ 适用于 600×600 像素查看器。
检查模型:
6.3 多边形数量
模型 | 多边形计数 | HQ 多边形计数 | LQ 多边形计数 |
---|---|---|---|
沙发 A1 | 96948 | 2226 | 256 |
沙发 A2 | 133998 | 1496 | 168 |
沙发 B1 | 740748 | 2628 | 238 |
沙发 B2 | 1009690 | 1556 | 118 |
正如你所看到的,优化模型中的多边形数量要低几个数量级。 另请注意,较密集的源模型生成的多边形数量并不明显高于较低的源模型。 这是针对目标屏幕尺寸而不是原始多边形计数的百分比进行优化的功能。 这是可取的,因为不同的 CAD 软件包、工作流程和设计人员可能会产生非常不同的源数据,但在可视化数据时,我们希望针对特定的查看场景有一致的包大小。
6.4 文件大小
文件大小由生成图像的多边形和纹理的组合决定。
模型 | 参考尺寸 HQ | 优化尺寸 HQ | 优化尺寸 LQ |
---|---|---|---|
沙发 A1 皮革 | 80 MB | 3.4 MB | 0.24 MB |
沙发 A1 面料 | 78 MB | 4.4 MB | 0.29 MB |
沙发 A2 皮革 | 80 MB | 3.3 MB | 0.22 MB |
沙发 A2 面料 | 82 MB | 4.1 MB | 0.26 MB |
沙发 B1 皮革 | 102 MB | 3.3 MB | 0.26 MB |
沙发 B1 面料 | 104 MB | 3.8 MB | 0.29 MB |
沙发 B2 皮革 | 112 MB | 3.4 MB | 0.23 MB |
沙发 B2 面料 | 113 MB | 4.0 MB | 0.27 MB |
正如你所看到的,原始模型和优化模型之间的下载大小存在巨大差异。 这是有代价的,这些模型确实不适合仔细检查,但它们代表了有意义的观看场景,其中较高质量模型的额外成本过高。 平心而论,参考模型并未针对尺寸进行优化,如果需要更高的质量水平,可以采取很多措施来使其更小。
6.5 GPU 绘制调用
优化后的模型将所有材质的纹理合并到单个图集中,这意味着它们可以作为单个绘制调用进行渲染。
源模型使用 3 种不同的材料组; 因此,大多数渲染器会为每个模型提交 3 个绘制调用。
6.6 过度绘制
优化后的模型的内部几何结构被清理干净,这意味着几乎没有不必要的过度绘制。
作为优化内容会产生影响的现实生活情况的示例,我创建了包含所有 8 个模型的 Adobe Aero 项目。 一个项目使用参考模型,一个项目使用优化模型。
这些项目是使用 Adobe Aero beta 桌面创建的,然后在具有快速 LTE 连接的 iPhone 上打开,以比较模型同步到设备的时间差异,以便它们可供使用。
第一个问题是,两个 Sofa B1 和 Sofa B2 被认为太重,无法在使用参考模型的项目中加载,因此它们根本没有出现在 Aero iPhone 应用程序中。 它们的源数据具有明显更高的多边形数量,并且它们达到了模型重量的上限,以确保应用程序运行良好。
6.7 打开时间
打开并同步项目的时间:
模型类型 | 打开时间 |
---|---|
参考 | 4 分 50 秒 |
优化 | 32秒 |
6.8 执行时间处理时间
优化管线在 6 核 2.6GHz Intel Core-7 CPU 上运行。 这将为 4 种不同模型的 2 种材质配置生成参考模型和优化模型。
执行模式 | 执行时间 |
---|---|
Python 原生 | 14 分 25 秒 |
SCons 并行 6 核 | 5 分 50 秒 |
正如你所看到的,通过 SCons 运行时,该过程的速度大约是原来的两倍。 鉴于它可以使用 6 个核心,这可能有点令人惊讶,但现实是许多运行的进程本身就是多线程的 - 这意味着你无法通过添加核心来获得线性扩展。
SCons 的真正好处体现在对资产进行最小程度的更改并进行增量构建时,只要执行的操作不耗时,并且不会触发错误,其周转时间以秒为单位。 下游发生很多变化。
6.9 上下文中的执行时间
查看这些数字时要考虑的第一点是将它们与人工执行这项工作进行比较。 生成低分辨率模型本身就是一项耗时的任务,可能需要花费数小时的时间。 每次源模型发生变化时,这也是一项需要在某种程度上重做的任务。 从时间消耗的角度来看,自动化这个过程是一个重大胜利。
另一件要记住的事情是,该进程可以对用户隐藏并在单独的计算机上运行。 这意味着它可以在构建计算机的后台运行,确保此过程不会减慢用户速度或不必要地占用工作站。
7、未来的工作
示例管线非常有限,但它应该概述了管线如何使你更有效地进行内容优化和部署。 以下是一些可以添加的改进,以使其能够扩展并更好地工作。
7.1 纹理压缩
模型中的纹理是 .png 文件。 有多种方法可以获得较小的文件:
- 在管道中实施 pngquant。 pngquant 工具是一种有损 .png 压缩器,可以显着缩小 .png 的大小,而质量损失很小,并且不需要在查看器中进行任何特殊扩展
- 目前正在进行 GPU 硬件纹理压缩工作,作为 .gltf/.glb 的扩展。 实现这一点应该允许更小的文件和更快的加载时间。
7.2 更好的Substance参数支持
当前的材质实例格式受到限制,适用于标量、向量、布尔值等。 但如果尝试使用枚举字符串或更高级的参数类型,它可能会出现错误。
7.3 更多优化选项/策略
该优化仅公开具有最少参数集的单个算法。 可能有充分的理由引入更多选项和算法来针对更广泛的目标类型。
7.4 网格压缩
.gltf 支持 draco 网格压缩。 此处对其过程进行了评估,但由于大多数数据由纹理组成,因此对文件大小没有重大影响。
7.5 网格共享
在此管道中,不同材质变化的网格是相同的。将结果写入 .gltf 文件(而不是 .glb)的设置可以在不同文件之间共享网格数据,以使用更少的磁盘空间。
7.6 分解操作
优化和纹理渲染都是通过调用多个进程来实现的操作。 如果它们被分解为更小的操作,SCons 将能够在其中找到更多的并行性,并允许更细粒度的依赖性跟踪。
7.7 法线贴图缩小
法线贴图使用 mipmap 进行过滤。 这不是法线贴图的正确过滤器,为了提高质量,可以移动太精细而无法显示到对象粗糙度的法线细节。 关于 LEAN 映射的论文对此进行了描述。
7.8 资产参考
当前资源引用(.sbsar 文件、网格体等)是本地文件路径。 此设置在单台计算机上运行良好,但如果想将管线扩展到多台计算机,你可能需要使用某种 URI 方案引用文件,以确保可以跨计算机以结构化方式引用它们。
7.9 设置覆盖
在现实世界的优化流程中,会有一些资产出现问题或需要特殊设置。 对每个资源进行可重复修复(例如纹理分辨率、优化质量等)的一种便捷方法是使用设置覆盖。 这将允许用户对每个管线、每个资产的属性进行覆盖; 这些将覆盖管线中的默认值。
7.10 规模更大
对于大规模部署,这样的构建过程可以分布在多台机器上。 然而,这对于 SCons 来说是不可能的,并且需要使用不同的构建系统。
原文链接:3D资产优化管线自动化 — BimAnt