前言
最近特效那边给我提了需求,需要在 Maya 输出 unreal 的顶点动画。
顶点动画输出工具其实 unreal 官方也提供了一个 链接
但是这个顶点动画输出工具是针对 3dsMax 的,需要做一个 Maya 版本。
特效那边需要给角色做一个跟随的路径动画面片,然后将面片的动画以上述的纹理图片的形式 在 unreal 中用 shader 驱动动画。
过去整个流程也一直是在 Max 里面完成的,最近需要配合 Maya 的动画进行处理,所以如果有 Maya 相应的工具会方便很多。
我研究了一下 Max 的导出流程,还原 Max 的面片生成处理其实不难。
最大的问题反而是 Max 导出流程中微不足道的点,那就是 exr 数据导出的问题。
在 Max 里面提供了 exr 导出的 API ,而且 Max 的坐标轴和 unreal 一样,不需要额外的处理。
但是 Maya 的 exr 导出 API 藏得非常深,而且数据处理不好弄。
OpenMaya 输出 exr
OpenMaya 的图像 API 有两个,分别是 MImage 和 MTexture
MImage 有 setPixels 命令但是支持 0 - 255 区间的数值,输出格式不支持 exr 等纹理。
这方面的研究我之前在做 MayaViewportCapture 工具的时候有研究过。
Maya MImage 可以通过 setPixels 赋值像素数据,也可以对像素数据进行 0 - 255 的修改。
1 | # coding:utf-8 |
MTexture 格式可以输出 exr 格式,这个和 MImage 不一样,用来定义 Maya 的纹理贴图。
这个对象无法像 MImage 一样进行实例化,需要借助 MTextureManager 来生成 MTexture 实例。
而且 OpenMaya1.0 的 API 已经不支持,只可以使用 2.0 的 API 进行获取。
通过查C++文档的案例可以知道 MTextureManager 也需要通过 MRenderer 获取,无法直接实例化(属于单例模式?!)
1 | # coding:utf-8 |
MTexture 没有研究出如何通过 Python 修改像素数据,我用上面的代码可以修改 MImage 的像素却修改不了 MTexture 的像素(输出的图片为黑色)
OpenEXR 库输出
鉴于上面的 MTexture 无法操作的原因,我只好退而求其次,用外部的 Python 库来进行修改。
反正可以通过 PyInstaller 打包然后用 Maya 的 Python 外调 exe 来实现 exr 数据输出。
网上查了一下 Python 有 OpenEXR 的库。
第一步安装就出现了问题,安装提示缺少了头文件,windows 平台安装失败。
网上搜了一下,提到 Linux 系统安装 libopenexr-dev 的系统库之后才可以正常安装。
救救 windows 平台吧 o(╥﹏╥)o
后来再 stack overflow 上找到了相关问题的回答 链接
评论下面推荐使用 https://www.lfd.uci.edu/~gohlke/pythonlibs/ 这个文章下载 build 的二进制 wheel 进行安装
然而坑爹的情况出现了。
我使用 QQ浏览器 点击链接下载居然跳转到 404 目录,我以为是网站出问题了。
继续找其他网站的 build 版本,无果,之后网上搜了一下这个网站 404 的问题,没想到居然是 浏览器 的锅。
使用 Chrome 浏览器就可以正常下载了(:з」∠)
好不容易才终于可以正常安装 OpenEXR 这个库了,尝试过在 Maya 安装,果然转完之后无法执行 dll 。
所以转而去到外部的 Python 进行安装。
后续流程就是 Maya 记录特效物体每一帧的每一个顶点的位置,然后输出 json 文件。
后续利用 OpenEXR 这个库读取 json 数据 生成 EXR 图片。
当时没有考虑到 Maya 的轴向和 Unreal 不一样,结果输出的 图片 信息看起来不对,放进引擎更加不对ε=(´ο`*)))
Python 输出 exr
因为上述的原因,这个 Max 插件导出转成 Maya 导出一直卡主。
后来我搜了一下有没有现成的 Maya 插件,没想到还真让我搜到了 Maya 版本的插件。
就在 Unreal 的官方论坛里面 链接
这个插件还在不断更新中,就在今天写文章之际还更新了一版。
既然上面输出 Exr 碰到那么多问题,这个插件到底是怎么做到 Exr 的输出呢?
当我翻阅它的代码时候,我惊呆了,居然使用了 纯 Python 二进制输出方案。
1 | # coding:utf-8 |
这个文件如何输出 exr 我进行了进一步的研究,代码的注释都在上面。
主要通过 struct 模块进行 二进制 的操作,根据 OpenExr 提供的操作文档给文件添加相应二进制信息。
其中比较厉害的操作是通过 python 创建 half 类型的二进制数据,需要通过 bitwise 位运算实现,目前还没有完全弄懂原理。
在 Stack Overflow 上找到了不同打包 half 类型的方案 链接
其中 binary16 的代码虽然写法不一样,但是可以得到上面 pack_half 函数的效果,原理同样还没有完全搞清楚。
根据 https://akaedu.github.io/book/ch14s04.html 上面对浮点数的描述。
half 类型的浮点数应该是通过科学计数法记录数据的,因此计算和转换的时候会有误差
有时间再进一步研究 浮点数 转换, Exr 的输出原理基本就是这样。
顶点动画输出
搞了这么久我们貌似将主题给搞偏了,虽然 输出 EXR 格式花了大部分的研究时间,其实我们的根本目标是输出 Maya 的顶点动画。
还有很重要的一步没有做,如何将 Maya 的模型动画输出来。
其实 Unreal 论坛的脚本也有很详细的操作。
主要利用了 Maya 的 snapShot 命令生成时间内的模型 快照。
不过我拿几个月前的老版本处理会有 Bug ,直接输出在运动路径的模型的快照是固定不动的。
后面我将 snapShot 的操作改为逐帧处理即可,就是输出效率大大降低。
有了快照信息就有了模型再运动时间内的顶点位置数据,然后将这些数据打包整理到 EXR 的 RGB 通道上就完成了顶点动画信息的转移。
最后只需要输出动画模型的 FBX 即可。
这种处理方式也是有问题的,只支持一些小模型的动画,如果模型点数太多超过 8K 贴图,就无法正常输出了。(我没有测试过,是 Unreal 论坛的老哥自己说的)
总结
本来想搞 顶点动画 的,没想到却花了大量时间研究 EXR 的 binary 数据输出了。
最后有没有搞清楚 half 类型是如何输出的,倒是发现纯 Python 也可以输出类似 EXR 这样复杂的数据。
Python 的功能果然很强大,这次又开阔了我的眼界。