做游戏的人,迟早都要面对这个经典问题:Maya里摆得好好的模型、场景、动画,一进UE要么是躺着的,要么是歪的,要么干脆朝向全乱。说这是“运气问题”就太天真了,本质原因是Maya和UE用了两套完全不同的坐标系。这篇文章我把这个事的底层原理、日常导入导出流程、以及不依赖FBX的脚本转换方法一次说清楚,适合刚入行的技术美术、DCC工具链开发,以及被资产朝向折腾到想摔鼠标的环境美术。
Maya是右手坐标系、Y轴向上;UE是左手坐标系、Z轴向上。光看这句话可能觉得没什么,但真正做项目的时候,“手性”“轴向”“旋转顺序”这三个词会在你导入蒙皮、摄像机动画、点云数据、程序化生成结果时反复出现。下面按我实际在项目里的处理顺序来写。
1. 先搞清楚两套坐标系的关系——一个右手一个左手
1.1 轴向差异:Maya的Y-Up和UE的Z-Up
Maya默认的轴向是X向右、Y向上、Z朝向屏幕外。听起来很直观,因为美术在正视图里画东西,Y轴向上符合直觉。UE则不同,它规定Z轴向上,X轴向前,Y轴向右。你可以把UE理解成一个“地图平面+高度”的组合:X和Y是地面上的前后左右,Z是高度。
这个差异意味着同一个“朝上”的概念,在Maya里是Y轴方向,在UE里是Z轴方向。所以模型从Maya导出到UE,如果不做任何转换,模型相当于在Maya里是站立着的,但在UE里会沿着X轴方向躺倒。你可以这样记:Maya的“上”是UE的“前”,Maya的“前”是UE的“右”……不对,前面的细节值得展开讲。
1.2 坐标映射关系:从六个方向推出来
先把两套轴向完整列出来,以角色模型的标准摆放位置为参考:
| Maya轴向 | 含义 | UE对应轴向 | 含义 |
|---|---|---|---|
| +X | 右 | +Y | 右 |
| -X | 左 | -Y | 左 |
| +Y | 上 | +Z | 上 |
| -Y | 下 | -Z | 下 |
| +Z | 前 | +X | 前 |
| -Z | 后 | -X | 后 |
从表格能直接写出坐标值转换关系:
P_ue = (P_maya.z, P_maya.x, P_maya.y)也就是UE的X坐标取自Maya的Z坐标,UE的Y坐标取自Maya的X坐标,UE的Z坐标取自Maya的Y坐标。
这里要特别提醒:这个映射关系存在一个前提,就是模型在Maya中按标准朝向摆放,角色面朝+Z。如果美术在Maya里把模型随便转了30度再导出,那后面所有轴转换讨论都没有意义,必须先让模型回到标准朝向再谈导出。我在项目里见过太多次“坐标转换怎么算都不对”的案例,最后发现是模型本身没有正对+Z轴。
还有一点容易被忽略:这个变换矩阵的行列式是正的,意味着它是个纯旋转,不包含镜像。这很重要,因为镜像变换会导致法线翻转、模型里外反转,而Maya转UE不会出现这个问题,通常也不需要你手动去翻转法线。
2. 常规资产导入:把轴转换交给FBX
2.1 FBX为什么能自动处理?一次说透
大多数情况你不需要自己写坐标映射,因为FBX格式本身保存了轴系统信息。FBX文件的GlobalSettings里记录了它来自哪个DCC、UpAxis是哪根轴、FrontAxis是哪根轴。UE在导入FBX时,会读取这些信息,在内部自动把Y-up的数据旋转成Z-up。这就是为什么直接拖一个FBX进UE,模型通常是站立且朝向正确的。
你把FBX理解成一个带“元数据”的快递盒,Maya那边发货时写清楚了原产地坐标规则,UE收货时就会自动拆包并把货物摆正。自己写转换脚本只是兜底方案,通常用在上游数据不是FBX,或者你需要批量操作点数据的时候。
2.2 Maya导出设置实测清单
Maya导出FBX时,以下几个地方建议固定下来,不要每回都凭感觉勾选:
- 单位:Window > Settings/Preferences > Preferences > Settings > Working Units > Linear,必须设为Centimeter。UE内部默认单位也是厘米,如果Maya里用了Meters或者Inches,导入UE后物体会整体缩放100倍或者缩成原来的1/100。
- 导出命令:直接File > Export All或者Export Selection,导出对话框里选择FBX格式。
- Axis Conversion:FBX导出设置的Advanced Options > Axis Conversion,通常不需要额外改,保持默认的Y-Up就行。这里默认值会让Maya生成的FBX记录“Up Axis = Y”,UE导入时会自动转换成Z-up。
- 勾选Smoothing Groups:对硬表面模型尤其重要,不勾选的话导入UE后圆滑组会乱掉,模型会变得“棱角分明”。
- 勾选Tangents and Binormals:如果做的是需要法线贴图的资产,建议导出切线。不导出的话UE会自己计算切线,某些接缝位置容易出现光影瑕疵。
- 动画相关:如果需要导出动画,确保Bake Animation勾选,并把Resample All Curves选上,避免导入UE后曲线抖动。
2.3 UE导入设置怎么做最省心
UE导入FBX时,弹出的FBX Import Options里,有几点保持默认通常就好:
- Import Translation / Import Rotation / Import Uniform Scale:全部留0/0/1。UE会自己处理Y-up转Z-up,你再加旋转反而会转错。
- Normal Import Method:默认的Import Normals and Tangents即可。如果模型法线有问题,再考虑改成Compute Normals。
- Import Mesh:默认勾选。
- 如果导入的是骨骼模型,记得在Animation选项卡里选好Skeleton,并确认Root Bone设置。
我自己踩过的坑是:美术好心在Maya里把模型整体旋转了90度,想“提前调整好”,结果导出后UE又转了一次,模型歪了45度。这里统一规则比“好心”重要。
2.4 导入后朝向还是不对?从这三个地方找原因
如果你严格按照上面流程做了,导入UE后模型朝向依然不对,优先排查这三项:
- Maya场景里模型是否正对+Z轴。选中模型,查看Translate和Rotate,如果Rotate不是0,先执行Modify > Freeze Transformations,冻结变换后再导出。
- FBX导出对话框的Axis Conversion是否被改成了Z-Up。有人为了让FBX“适配UE”,手动把Up Axis从Y改成了Z,结果UE导入时又转一次,模型反而躺倒。
- UE导入选项里的Import Rotation是否被填了数值。有时候美术或策划为了“临时修正”,在导入选项里加了旋转,下次重导又会叠加,建议一律清0。
检查完这三项,90%的朝向问题都能解掉。
3. 不依赖FBX的硬核转换:Python脚本批量操作
3.1 什么时候需要自己写转换
FBX虽然好用,但遇到下面这些场景你就必须自己动手了:
- 手里是CSV或TXT点云文件,里面有几千个点的坐标,要摆到UE场景里。
- 你从Maya里导出的是自定义数据格式,比如JSON或者XML,引擎端要直接读取。
- 你是程序化生成管线,在Maya里用Python生成了一批物件坐标,想直接生成UE蓝图放置数据。
- 你要把Maya里的灯光位置、摄像机位置批量导出给UE,不想走FBX。
有人可能会说“FBX也能干这些事啊”,确实能,但FBX解析起来麻烦,而且为了几个坐标点去走一整套DCC导出链路,效率太低了。自己用Python算一遍映射,十分钟搞定。
3.2 Maya端CSV坐标转换脚本
下面这段脚本可以直接在Maya的Script Editor里跑,作用是把一份Maya坐标CSV转换成UE坐标CSV。假设输入文件每一行是x,y,z三个值,没有表头。
import csv def maya_csv_to_ue_csv(input_path, output_path): rows = [] with open(input_path, 'r') as f: reader = csv.reader(f) for row in reader: if not row or len(row) < 3: continue mx = float(row[0]) my = float(row[1]) mz = float(row[2]) # 核心映射:UE_X = Maya_Z, UE_Y = Maya_X, UE_Z = Maya_Y ux = mz uy = mx uz = my rows.append([ux, uy, uz]) with open(output_path, 'w', newline='') as f: writer = csv.writer(f) writer.writerow(['UE_X', 'UE_Y', 'UE_Z']) writer.writerows(rows) # 用法示例 maya_csv_to_ue_csv('D:/maya_points.csv', 'D:/ue_points.csv')这个脚本很简单,但确实验证过可以跑。核心就是那一行坐标映射,如果你项目中角色朝向习惯和其他项目不一样,需要先确认真实的映射表,别想当然用我给的公式。建议先拿一个已知的点测试:Maya里放一个坐标(100, 200, 300)的物体,转换出来应该在UE里是(300, 100, 200),然后在UE里手动验证。
如果你希望支持带表头的CSV,或者每行数据里还有名称、旋转、缩放,自己扩展一行解析逻辑就行。批量处理大文件时,建议每处理1000行打印一条进度,方便知道脚本卡没卡。
3.3 反向转换与旋转数据的处理
反向转换就是从UE坐标转回Maya,公式是逆映射:
P_maya = (P_ue.y, P_ue.z, P_ue.x)逻辑很好理解,Maya的X取UE的Y,Maya的Y取UE的Z,Maya的Z取UE的X。
旋转数据比位置麻烦得多。坐标点很好转,因为只是三个轴的置换;旋转则涉及旋转顺序。Maya默认的欧拉旋转顺序是XYZ,而UE内部旋转是Yaw(Pitch(Roll),对应的是ZYX顺序。如果你尝试直接把Maya里的欧拉角拷贝到UE里,几乎必然结果不对。
正确做法是:把Maya欧拉角转成旋转矩阵,用坐标映射矩阵做一次相似变换,再按UE的旋转顺序分解出Yaw/Pitch/Roll。示意代码如下:
import numpy as np from scipy.spatial.transform import Rotation as R def maya_euler_to_ue_euler(mx_deg, my_deg, mz_deg, maya_order='xyz'): # Maya欧拉角 -> 旋转矩阵 r_maya = R.from_euler(maya_order, [mx_deg, my_deg, mz_deg], degrees=True) # 坐标映射矩阵 M = np.array([ [0, 0, 1], [1, 0, 0], [0, 1, 0] ]) # 相似变换:R_ue = M * R_maya * M^T r_ue = R.from_matrix(M @ r_maya.as_matrix() @ M.T) # 按UE的ZYX顺序输出 Yaw/Pitch/Roll yaw, pitch, roll = r_ue.as_euler('zyx', degrees=True) return yaw, pitch, roll这段代码依赖numpy和scipy,实际Maya环境里不一定有,但你完全可以用Maya自带的OpenMaya矩阵类来实现同样的逻辑。核心思想就是:用矩阵做中间转换层,别试图硬凑三个欧拉角。
我在项目里遇到过有人直接用“旋转轴对调”的方式转旋转值,比如Maya的rx转成UE的pitch,ry转成yaw,rz转成roll,结果模型角度全乱。这不是数学不好,是对旋转顺序没有敬畏。所有涉及旋转的人为转换,一律走矩阵,不要手动对应轴向。
3.4 批量摆放数据的实战用法
这个脚本最常见的用途是批量生成UE场景摆放数据。比如你有一个Maya场景,里面手动摆了几百棵树的位置,现在要把这些树在UE里以相同位置放置。做法是导出CSV位置信息,用脚本转成UE坐标,然后在UE里用HISM(Hierarchical Instanced Static Mesh)组件批量生成实例,或者用Python在编辑器脚本里循环SpawnActor。
我实际做过的流程是这样:
- 在Maya里选中所有树模型,用Python脚本输出每个模型的translate到CSV。
- 运行上面的转换脚本,得到UE坐标CSV。
- 在UE编辑器里写一个Editor Utility Widget,读取CSV,遍历每一行,在对应坐标点SpawnActor。
- 检查发现有几棵树位置在地面以下,原因是Maya里树的轴心点没有统一,有的轴心在根部,有的在模型中心。归根结底还是资产规范问题,不是坐标转换能解决的。
所以脚本解决的是“坐标系不一致”的问题,资产轴心和命名规范还是要靠流程来管。
4. 进阶场景:骨骼、动画与相机
4.1 角色骨骼与动画的坐标陷阱
FBX导入角色骨骼时,UE会自动处理骨骼整体的Y-up到Z-up旋转,骨骼树内部的层级关系会被保留。所以大部分情况下,角色不需要额外做骨骼坐标转换。
但有几个容易出问题的点:
- Root Bone(根骨骼)朝向。UE的Humanoid Rig要求骨骼T-Pose时角色面朝+X,但在Maya里标准姿势是面朝+Z。FBX导入通常能处理这个差异,但前提是Maya里的绑定朝向是规范的,如果骨骼节点在Maya里被旋转过,导入UE后Root Bone可能带着一个额外角度,导致动画重定向时整个角色偏移。
- 肩部、手指这些旋转敏感的骨骼。骨骼如果自身带roll角(比如肩部骨骼绕自身长轴转了30度),导入UE后可能出现手腕扭曲。因为UE在计算骨骼空间时用的是全局旋转矩阵的逆,分骨翻转顺序有细微差异。应对办法是在Maya绑定阶段就保持骨骼轴向与世界轴对齐,别为了刷权重方便随便旋转骨骼。
- 动画曲线采样。导出动画时勾选Resample All Curves,避免Maya与UE的旋转插值算法差异导致角色动作抖动。
4.2 旋转顺序:为什么拷贝欧拉角会乱
这一节值得单独拿出来说。MAYA和UE旋转顺序的差异,是“为什么我手动算的旋转导入后总是错”的核心原因之一。
Maya属性编辑器里有个Rotation Order参数,默认是XYZ,即先绕X轴转,再绕Y轴转,最后绕Z轴转。UE那边,Actor旋转的Roll绕X、Pitch绕Y、Yaw绕Z,但内部组合顺序是Yaw优先,也就是ZYX。这正好和Maya默认顺序相反。
如果你把Maya里的欧拉角原封不动导给UE,等于用一个顺序去解释另一套顺序的结果,角度自然错得离谱。典型的错误是:Maya里只要不是三个轴都有旋转,看起来好像还行;一旦同时有多个轴旋转,角色就会歪成奇怪的角度。
解决办法还是那句:用矩阵转换。搞一个工具脚本,用户输入Maya欧拉角和旋转顺序,输出UE的Yaw/Pitch/Roll,所有转换都通过矩阵,不手动映射轴向。这样既能在一次性转换任务里用,也能沉淀成团队工具。
4.3 相机与镜头动画的特殊处理
相机是另一个重灾区。Maya相机的默认视线方向是自身局部坐标的-Z方向,而UE的相机默认看向自身局部坐标的+X方向。两套方向不仅差90度,还有一个手性差异,所以直接把Maya相机动画烘焙到FBX导入UE,镜头经常扭成螺旋。
我推荐的做法是:在Maya里建一个“转换相机层次”,把目标相机放在一个父级组下,在父级组上套用一个坐标转换矩阵,导出时只烘焙转换后的子相机,这样动画曲线在源端就已经变成UE视角。另一种方案是直接不依赖通用FBX,在UE里用虚拟摄像机工具(Virtual Camera)重新拍一遍,反而更可控。
如果只是要镜头路径的Position数据,那简单,坐标映射直接用第一节的公式就行;但要带旋转,就必须用4.2的矩阵转换思路。记住:位置可以人肉算,旋转一定要走矩阵。
5. 常见问题速查与项目规范建议
5.1 高频问题排查表
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 模型导入UE后躺倒/歪斜 | Maya里模型Rotate未冻结,或FBX导出Axis Conversion被改成Z-Up | 在Maya里利用Freeze Transformations,导出保持Y-Up |
| 模型背面全黑 | 自定义格式导入时三角形顶点缠绕顺序翻转 | 检查导入设置Normal Import Method,或交换顶点索引顺序 |
| 角色骨骼动画扭曲 | Maya动画曲线未Bake,或骨骼自带非标roll角 | 导出时勾选Bake Animation和Resample All Curves,检查骨骼轴向 |
| 手动计算旋转值但结果全错 | 忽略旋转顺序,直接对调轴向 | 通过旋转矩阵+相似变换,不要直接替换欧拉角xyz |
| CSV点云摆放位置镜像颠倒 | 坐标映射公式用反或用成镜像 | 拿一个已知点(100,200,300)实测验证映射方向 |
| 导入UE后物体大小不对 | Maya工作单位不是厘米 | 检查Working Units > Linear,统一设为Centimeter |
这些坑几乎每个项目都会踩一遍。特别是“背面全黑”这个问题,用FBX通常不会遇到,因为FBX内部把缠绕方向处理掉了;一旦你绕开FBX走自定义格式,就要自己处理。
5.2 建立项目规范:从源头减少坐标系问题
坐标系的坑,靠人情提醒是堵不住的,必须靠规范和工具。这里分享几条我沉淀下来的经验:
- 明确规定Maya资产标准朝向:角色面朝+Z,场景地面在Y=0平面。这条写进项目Wiki,新人入职第一课就灌输这个意识。
- 统一单位。Maya工作单位、FBX导出单位、UE项目单位全部用厘米。用代码在Maya启动时自动检查Working Units,不对就报错。
- 把坐标转换脚本封装成工具。Maya里做成工具架按钮,UE里做成Editor Utility Widget,一键导出/导入CSV,降低手算出错概率。
- 写一个“资产体检”Maya脚本,一键检查模型是否面朝+Z、是否冻结变换、是否非等比缩放、工作单位是否厘米。任何资产导出前必跑一遍。
- 不要手动在UE导入选项里添加额外旋转或缩放,所有修正必须在Maya侧完成。临时在UE里改导入参数,资产更新后十有八九会叠错。
我在实际项目里最深的一个体会是:坐标转换本身并不难,难的是所有环节的人都能遵循同一套规范。工具脚本能把“需要思考”变成“一键执行”,这才是它最大的价值。如果你现在正被Maya和UE的坐标系折腾,先别急着硬记公式,把第一节的轴向映射表贴在工位上,再用一个已知点验证一遍自己的理解,后面所有环节都会顺很多。