37DATA

我是如何做到在线预览 Maya 资产的

背景

之前设计团队的大大们提了一个很有挑战的需求,想要在客户端(Web页面)上直接预览 Maya 资产文件,而 Maya 是一款 Autodesk 公司出品的商业化三维动画软件,脱离了 Maya 这款工具本身,目前还没有能够直接预览 Maya 资产文件(.ma .mb)的方法,想要实现这个需求的话估计得另辟蹊径了。在这里简单记录一下解决的全过程。

前期调研

经过简单的调研,在 Maya 身上我们找到了几个有意思的点:

1. Maya 本身集成了 Python 解释器,可以直接运行 Python 脚本,并通过调用对应的库快速完成某些操作;这也是 pipeline TD 开发美术流程工具的基础
2. 有一门编程语言叫做 MEL(Maya埋入式语言),Maya界面的几乎每一个要点都是在 MEL 指令和脚本程序上建立的。由于Maya给出了对于MEL自身的完全的访问,你可以扩展和定制Maya
3. 无论是 MEL 还是 Python 都可以开启一个叫做 Maya CommandPort 的功能,可以监听本机的特定端口(TCP),并支持直接执行来自该通道的命令

而在前端方面,某新大佬悄悄告诉我,咱们年会的洋葱头3D模型是 glTF 格式的,前端的 three.js 虽然不支持 ma、mb 之类的闭源特殊格式,但是支持 obj、dae、glTF 等格式,在 glTF 格式下的表现会比较好。

因此一个“大胆的想法”应运而生:调用 Maya 将特有的格式转码成通用的 3D 格式。

通用3D格式的选择

既然需要转换为通用的 3D 格式,那我们需要如何在众多 3D 格式中做出选择呢?

经过各路资料的收集,得到各个关于 3D 格式的说明如下:


. fbx 格式,Autodesk 家族格式 - 支持动画!这是一个商业的格式,兼容最好的当属 Autodesk 家族的软件了。fbx 也开放给了第三方软件,但总是感觉除了他自己的软件之外或多或少的都有解决不完的问题。 毋庸置疑,FBX 现在是最受欢迎的格式。


.glTF 格式, - 支持动画等!.gITF 2.0 格式逐步的完成了 WebGL 的布局,也成为了这个领域的专用格式,随着发展游戏领域的应用也会越来越广泛。这种格式可以减少3D格式中与渲染无关的冗余数据并且在更加适合OpenGL簇加载的一种3D文件格式。glTF的提出是源自于3D工业和媒体发展的过程中,对3D格式统一化的急迫需求。如果用一句话来描述:glTF 就是三维文件的 JPEG ,三维格式的 MP3。


. obj 格式, 静态多边形模型 - 附带 UV 信息及材质路径!不包含动画、材质特性、贴图路径、动力学、粒子等信息。主要支持多边形(Polygons)模型。是最受欢迎的格式。


. 3ds 格式 - 三角面静态模型!文件格式简单,现在几乎都已淘汰!应该在一些老的项目应用上才有可能会用到。


. x3d 格式 - Web3D 使用较多的格式 - 少量动画 WebGL 支持!支持多纹理和多遍绘制、支持 Shader 着色、支持多渲染目标(MRT)、支持几何实例(Geometry Instance)。


. dae 格式, FBX 的代替品 - Collada DAE需要自行下载安装!Google 地图便是使用的 DAE 格式。


. stl 格式,三维打印的通用格式 - 三角面静态模型!文件格式简单,只能描述三维物体的几何信息,不支持颜色材质等信息,是计算机图形学处理CG、数字几何处理如CAD、 数字几何工业应用, 如三维打印机支持的最常见文件格式。


. bvh 格式, 动作捕捉通用格式 - 骨骼动画数据!捕捉后的文件可以重复利用,应用在不同的角色骨骼驱动上制作动画。制作游戏、影视等方面的应用广泛。


.abc 格式,中文名称:蒸馏机 - 支持动画、粒子等!bake三维场景的模型、流体、动画、特效等数据,输出输入到其他三维软件。注意是 bake(烘焙),有可能在导入其他三维软件中无法再二次编辑,比如:Rig、流体烟雾模拟等。不必多说,ABC将会是三维软件交互的王者。


. ply 格式 - 静态多边形模型 - OBJ 格式的升级版!PLY格式受 Wavefront .obj 格式的启发,但改进了Obj格式所缺少的对任意属性及群组的扩充性。因此PLY格式发明了"property"及"element"这两个关键词,来概括“顶点、面、相关资讯、群组”的概念。


. psk 格式 - Unral Engine 格式 - 带骨骼动画的模型!psk 是 一个比较特殊的格式,通常情况下是原来提取游戏模型使用的。最终生成的基于虚幻引擎的游戏打包成这个格式的模型。


. dxf 格式 - Drawing Exchange File - CAD 通用格式!一般都是CAD 矢量数据的交互格式。


看到“glTF 就是三维文件的 JPEG ,三维格式的 MP3”时,心向往之,是不是我们把 .ma .mb 之类的特殊格式,转换成 .glTF 格式就可以了呢?

很快现实就给我们泼了冷水,Maya 并不支持直接导出 gltf 格式的 3D 模型,需要单独安装第三方的插件,遗憾的是这个第三方的插件已经不在更新了,并不能保证以后的版本中能够做到比较好的兼容,那么我们能否退而求其次,导出号称 Autodesk 最强交换格式的 fbx,然后再从 fbx 转换为 glTF 格式呢?

我们找到了 Facebook(Meta) Incubator 开源的 fbx2gltf 工具,成功地在 Linux 测试机下把 fbx 格式文件转换成了 glTF 格式文件并在 Web 中进行了渲染;然而这时现实再次向我们展示了它骨感的身影,当我们把这款工具搬到运行 Maya 的 Windows 测试机上运行时,发现原本能在 Linux 下正常转码的部分文件会提示格式编码有误,所幸的是后面队友黄老板给力,找到了一款名为 assimp 的开源格式也能完成 fbx 到 glTF 的转码,这款工具在 Windows 和 Linux 下都能够比较好地完成转换。

到这里,glTF 格式转换方面看似已经符合 Web 渲染的预期了,但是我们又遇到了一个问题,glTF 格式确切地说并不是单个文件,更像是由多个文件(如bin、jpg等)组成的一个包,由 .gltf 这个以 json 格式存在的“配置”文件中产生对其他文件的引用;因为文件转码完成之后,中间预览文件(即 glTF 产物)是需要重新上传到其他的 Web 服务器上进行存储的,对于后端而言单个文件的管理永远比目录要好。

Image

这个时候,我们又在 glTF 家族中发现了一个网络上讨论得比较少,但是却比较实用的格式:glb。它是 glTF 模型的二进制文件格式表示,以单文件存储了glTF 的组件,如JSON、BIN文件和图片。同时 glb 避免了使用 glTF 格式文件变大的问题,通过压缩,glb 能更快地加载;更为重要的是作为 glTF 家族中的一员,前端的 three.js 组件同样能够对它做到比较好的支持。

和 Maya 的交互

既然 Maya 可以把自己特有的格式导出为 fbx,并通过工具我们可以把 fbx 文件转换为支持 WebGL 渲染的 glTF/glb 格式,那么我们怎么让我们运行在云端的 Web 后端程序和 Maya 产生交互,通知 Maya 对特定的文件进行转码导出呢?结合前期调研,我们快速制定了几个可行的方案:

① Web 后端程序往 kafka 投递消息,使用 Python 编写消费者进行监听,接收到消息后调用 Maya 相关的库进行加工并导出

Image

优点:Maya 相关的 Python 库功能相对强大,可定制性强

缺点:1. 当前项目组内没有特别熟悉 Python 开发的后端同学,都偏向 Golang 或 PHP 开发;2. 考虑到到时候这部分内容需要部署在办公网络内的 Windwos 机器下,如何保证 Python 程序的稳定性也是值得思考的问题

② Web 后端程序往 kafka 投递消息,使用 Go (技术中心TCF框架) 编写消费者进行监听,接收到消息后通过命令行的方式唤起 Maya 并执行文件转换的 MEL 脚本

Image

优点:1. 利用技术中心 TCF 框架可以做到技术栈的统一,同时主动告警、内置 Prometheus 等特性更利于我们对程序稳定性的监控 2. 和传统的利用 Golang 调用外部命令一样,只要系统资源足够,可以通过 Go 协程 or 增加消费者数量轻松提高性能 3. 同样的调用模式,不仅仅可以调起 Maya 主程序,还可以调用 Maya Render 进行批量渲染,以及调用 fbx2gltf、assimp 等工具,后续可以节约这场场景开发时间 4. Golang + TCF 框架是大势所趋,我们需顺势而为

缺点:由于接收到请求后再调用 Maya,因此会存在 Maya 冷启动的过程,相对耗时较长

③ 事先启动好 Maya 主程序,并通过 Python 脚本或 MEL 提前开启 commandPort 的监听;Web 后端程序往 kafka 投递消息,使用 Go (技术中心TCF框架) 编写消费者进行监听,接收到消息后通过特定端口和 Maya 建立 TCP 连接,执行对应的命令进行文件的导出

Image

优点:相比起上一个方案,这种方式减少了 Maya 冷启动的过程,性能更优

缺点:1. 需要实现开机自动启动 Maya 并监听 commandPort,存在 maya 假死后我们监控不到的情况,并且需要提前分配好各个 maya 进程的端口号 2. 扩容时需要配置多个 maya 的自动启动以及指定端口号,操作不太方便。3. Maya commandPort 上的操作并不能做到并发安全!需要在 Go 消费者中进行控制

最终基于开发成本和稳定性考虑,我们选择了使用方案②

如何落地

经过上述整理,我们可以发现整个流程大致包含以下几个节点:

1.  用户上传 maya 资产文件至服务器
2.  Web 后端触发一个事件(把要处理的文件地址等信息投递至消息队列: Kafka)
3.  Go 守护进程监听消息队列,收到消息后将对应的资产文件下载到本地
4.  调用 Maya 进行处理
5.  处理完成后,把处理后的结果文件上传到 Web 后端

最开始落地时,我们的步骤真的就像上面方案所展示的一样,写了个 Go 消费者进行处理:

Image

当简单压测后发现了一个问题,整个链路的耗时主要分布在下载、Maya处理这两部分。如果单纯扩容 Go 消费者确实是可以解决问题,但是还会受到 Kafka 分区数的限制,超出分区数的消费者并不会工作,而增加分区数意味着成本的上升。因此便衍生了第二套方案,把耗时较大的下载、处理这两部分分离:

Image

其中:

1、分发器负责监听来自 Web 后端的队列,鉴别出对应的事件并下载Maya的资产文件,下载完成后重新投递至消息队列(这里的消息队列也可以选择更轻量、成本更低的其他队列,只不过为了统一管理以及安全考虑我们目前还是选择了 Kafka)
2、处理器负责与 Maya 主程序进行交互,完成资产文件的加工处理并回调 Web 后端

如此一来,在性能遇到瓶颈时便可以针对性地进行扩容,如果是网络原因导致的下载慢,则只需要扩容分发器;如果是资产文件处理耗时比较长,在机器性能足够的情况下以调整处理器的进程数即可

除此之外还有一些前文并未提及的问题,那就是资产文件都是存储于办公网络内的,分布在各个业务团队自有的NAS和Linux文件服务器上,我们需要打通线上生产环境到办公网络的交互,经和SRE、DBA、网络、安全等同事对齐后选择了开放了外网访问的 Kafka 作为介质沟通两个网络环境,同时开启了 SASL-SSL + 用户名密码的验证,这里还有一段趣事就是咱们技术中心的 TCF 框架 kafka 组件当时并未支持 SASL 等特性,有幸动手为 TCF 提了个 MR 为其增加了相关特性,也算造福一下后来者。

最后在稳定性方面,整体还有待观察。从应用层面来讲,TCF 框架虽然提供了 Prometheus Metrics,但是目前我们还尚未对办公网络内的机器进行收集,只利用 ERROR 日志主动告警的功能让错误在发生时能够及时通知到开发人员,并在上图中“处理器”部分分阶段对 Web 后端进行了多次回调,从而能够把握到整体的处理进度,方便对办公网络内消费者运行状态进行分析。在网络、机器层面的话,也是复用以前运维侧的看板。目前该项目的监控数据源分散在企信Prometheus、海外 Prometheus、海外对内K8S集群的SLS上,暂未能收拢到同一个 Grafana 上,较为可惜,也是后续一个需要填的大坑吧。

最终完整的设计如下:

Image

总结

行文至此,相信很多朋友应该都看出来了,这个就是我们【图灵-设计中台】中资产管理模块的其中一个功能点,除了 Maya 的私有格式外,设计大大还提了 UE、3dsmax、blender 等 3d 格式的预览支持,和一些冷门的音/视频格式预览要求,我们通过对资源的统一规整(3D资产统一规整为 glTF 2.0、图片统一规整为 webp、视频统一规整为 webm),再由前端针对性对 glTF、webp、webm 这几种特定格式提供支持实现了多种格式的在线预览,至于其它设计类工具的对接大同小异,以后有空的话可以把踩过的坑一一分享出来~