You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于mayapy.exe的Maya .ma转Nuke .nk脚本开发:相机信息导出问题

把Maya相机导出为Nuke .nk工程的实现方案

嘿,我来帮你搞定把Maya相机导出成Nuke可用的.nk工程文件的问题!你之前用FBX导出的方式虽然能传递相机数据,但直接生成Nuke原生的.nk纯文本文件,不仅更高效,还能精准控制每一个相机参数和动画关键帧。

核心思路

Nuke的.nk文件本质是结构化的纯文本,我们只需要读取Maya相机的属性(静态参数+动画关键帧),然后按照Nuke Camera节点的语法格式生成文本,最后写入文件即可。

完整实现代码(mayapy批处理可用)

import maya.cmds as cmds
import os
import sys

def export_maya_camera_to_nuke():
    # 确保在批处理模式下也能正常初始化Maya
    if not cmds.about(batch=True):
        cmds.file(new=True, force=True)
    
    # 获取当前场景路径
    current_scene = cmds.file(query=True, sceneName=True)
    if not current_scene:
        print("请先打开一个Maya场景文件!")
        sys.exit(1)
    
    # 获取选中的相机(如果没有选中则取场景主相机)
    selected_cameras = cmds.ls(selection=True, type='camera')
    if not selected_cameras:
        # fallback到场景主相机
        selected_cameras = cmds.ls(type='camera')
        # 过滤掉默认的persp/top/front/side,取自定义相机或者persp
        selected_cameras = [cam for cam in selected_cameras if not cam in ['perspShape', 'topShape', 'frontShape', 'sideShape']]
        if not selected_cameras:
            selected_cameras = ['perspShape']
    
    camera = selected_cameras[0]
    camera_transform = cmds.listRelatives(camera, parent=True)[0]
    print(f"正在处理相机:{camera_transform}")

    # ---------------------- 读取Maya相机静态属性 ----------------------
    # 基础参数
    focal_length = cmds.getAttr(f"{camera}.focalLength")
    horizontal_aperture = cmds.getAttr(f"{camera}.horizontalFilmAperture")
    vertical_aperture = cmds.getAttr(f"{camera}.verticalFilmAperture")
    near_clip = cmds.getAttr(f"{camera}.nearClipPlane")
    far_clip = cmds.getAttr(f"{camera}.farClipPlane")
    is_orthographic = cmds.getAttr(f"{camera}.orthographic")
    ortho_width = cmds.getAttr(f"{camera}.orthographicWidth") if is_orthographic else 0

    # ---------------------- 读取动画关键帧数据 ----------------------
    def get_keyframe_data(attr_path):
        """获取指定属性的关键帧(帧号+数值),返回[(frame, value), ...]"""
        keyframes = cmds.keyframe(attr_path, query=True, timeChange=True)
        values = cmds.keyframe(attr_path, query=True, valueChange=True)
        if keyframes and values:
            return list(zip(keyframes, values))
        return None

    # 位移/旋转/缩放动画
    tx_keys = get_keyframe_data(f"{camera_transform}.translateX")
    ty_keys = get_keyframe_data(f"{camera_transform}.translateY")
    tz_keys = get_keyframe_data(f"{camera_transform}.translateZ")

    rx_keys = get_keyframe_data(f"{camera_transform}.rotateX")
    ry_keys = get_keyframe_data(f"{camera_transform}.rotateY")
    rz_keys = get_keyframe_data(f"{camera_transform}.rotateZ")

    # 相机属性动画
    focal_keys = get_keyframe_data(f"{camera}.focalLength")
    ortho_width_keys = get_keyframe_data(f"{camera}.orthographicWidth") if is_orthographic else None

    # ---------------------- 构建Nuke .nk内容 ----------------------
    nk_content = f"""Camera {{
 inputs 0
 name "{camera_transform}"
 xpos 0
 ypos 0
 focal {focal_length:.6f}
 haperture {horizontal_aperture:.6f}
 vaperture {vertical_aperture:.6f}
 near {near_clip:.6f}
 far {far_clip:.6f}
"""

    # 添加投影类型
    if is_orthographic:
        nk_content += f" projection orthographic\n"
        nk_content += f" ortho_width {ortho_width:.6f}\n"
    else:
        nk_content += f" projection perspective\n"

    # 生成位移动画曲线
    def add_animation_curve(nk_str, attr_name, key_data):
        if key_data:
            nk_str += f" {attr_name} {{\n"
            for frame, val in key_data:
                # Nuke曲线格式:curve 帧号 数值; (默认线性插值,如需匹配Maya插值可扩展)
                nk_str += f"  curve {int(frame)} {val:.6f};\n"
            nk_str += f" }}\n"
        return nk_str

    nk_content = add_animation_curve(nk_content, "translate", tx_keys)
    nk_content = add_animation_curve(nk_content, "translate.y", ty_keys)
    nk_content = add_animation_curve(nk_content, "translate.z", tz_keys)

    nk_content = add_animation_curve(nk_content, "rotate", rx_keys)
    nk_content = add_animation_curve(nk_content, "rotate.y", ry_keys)
    nk_content = add_animation_curve(nk_content, "rotate.z", rz_keys)

    nk_content = add_animation_curve(nk_content, "focal", focal_keys)
    if is_orthographic and ortho_width_keys:
        nk_content = add_animation_curve(nk_content, "ortho_width", ortho_width_keys)

    # 闭合节点
    nk_content += "}"

    # ---------------------- 写入.nk文件 ----------------------
    output_filename = os.path.splitext(current_scene)[0] + '.nk'
    with open(output_filename, 'w') as f:
        f.write(nk_content)
    
    print(f"✅ 成功导出Nuke相机工程到:{output_filename}")

if __name__ == "__main__":
    export_maya_camera_to_nuke()

关键注意事项

  1. 单位匹配:Maya和Nuke的相机光圈单位默认都是英寸,所以horizontalFilmAperture可以直接复用;如果Maya用了其他单位(比如厘米),需要做单位转换(1英寸=2.54厘米)。
  2. 动画插值:上面的代码默认用线性插值,如果需要精确匹配Maya的关键帧插值类型(比如贝塞尔、缓入缓出),可以读取Maya关键帧的inTangentTypeoutTangentType,然后转换成Nuke对应的插值语法(比如curve 0 10 bezier 0.5 0.5 0.5 0.5;)。
  3. 批处理模式适配:代码里加入了批处理模式的判断,确保用mayapy.exe执行时能正常初始化Maya环境。
  4. 相机选择逻辑:如果没有选中相机,会自动 fallback 到场景中的自定义相机,最后才用默认的persp相机,避免报错。

内容的提问来源于stack exchange,提问作者William Eguienta

火山引擎 最新活动