查询 maya 文件中引用文件的路径 -- 通过 mayapy.exe 及 maya Python 命令获取路径

该博客介绍了如何使用Python脚本通过Maya的mayapy.exe执行查询Maya文件引用节点及其路径的过程。主要内容包括利用subprocess模块调用Python2脚本,处理不同Python版本间的问题,以及解决高版本Maya文件在低版本软件中打开的错误。此外,还探讨了通过读取Maya文件获取创建时的软件版本信息,以解决版本兼容性问题。最后,提到了编码问题以及处理错误信息的方法。
摘要由CSDN通过智能技术生成

Python 查询 maya 文件的引用节点及引用文件的路径

环境

  • Maya 2017 & 2018
  • Python 3.6
  • VS Code

实现

需求:给定一个 maya 文件,查询这个 maya 文件引用了哪些文件,返回引用的文件路径。

首先,需要使用 maya 软件自带的 mayapy.exe 解释器来执行 maya 包的 Python 命令,如:cmds 的相关命令,maya 中的 Python 为 Python 2,但是开发环境使用的是 Python 3.6,所以需要变通一下。通过 subprocess 模块的 Popen 方法,调用 mayapy.exe 执行一个用 Python 2.7 写的脚本。主文件 main.py 如下:

import os
import subprocess

def main():
    mayaPath = "D:\\Maya2018\\maya2018\\bin\\mayapy.exe"  # 修改成你的 mayapy.exe 路径
    scriptPath = "C:\\test\\Coding\\test3.py"  # 要执行查询引用的文件
    file = "C:\\test\\maya\\文档\\w2.ma"  # 要查询的文件

    try:
        referenceFilePath = subprocess.Popen(mayaPath+' '+scriptPath+' '+upload_file_path,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
        out, err = referenceFilePath.communicate()
    except Exception as e:
        pass
    else:
        try:
            ref_filepaths = eval(out.decode('utf-8'))  # 正确的结果为字符串 list,此命令可以转为 list。
        except Exception as e:
            print(err.decode('utf-8'))
            print('文件版本高于 maya 软件版本')
        else:
            print('引用文件列表 -------:', ref_filepaths)
            # return ref_filepaths


if __name__ == '__main__':
    main()

以上代码中,得到的结果 out、err 可能存在编码问题,需要处理。如果要在执行的脚本中再传入参数,如上面代码中的 file 参数,在脚本中需要再获取参数。

mayapy.exe 解释器使用的是 Python 2.7 的版本。查阅 maya 技术文档,get_ref.py 具体实现入下:

# -*- coding:utf-8 -*-
import os
import sys
import maya.cmds as cmds
reload(sys)
sys.setdefaultencoding('utf-8')
os.environ["MAYA_SKIP_USERSETUP_PY"] = ""
os.environ["setupScriptPaths"] = "D:\\我的文档\\maya\\scripts\\userSetup.py"  # 注意修改路径

try:
    import maya.standalone
    maya.standalone.initialize(name='python')
except Exception as e:
    pass

def get_ref_file_path(upload_file_path):
    rfnNodes = {}
    try:
        cmds.file(upload_file_path, reference=True, namespace='ns')
        rfnNode = cmds.referenceQuery(upload_file_path, referenceNode=True, child=True) # list
    except Exception, e:
        raise e
    else:
        rfnNodes[upload_file_path] = rfnNode
    ref_file_paths = []
    if rfnNodes[upload_file_path]:
        for node in rfnNodes[upload_file_path]:
            try:
                cmds.file(upload_file_path, reference=True, namespace='ns')
                ref_filepath = cmds.referenceQuery(node, filename=True)
            except Exception, e:
                raise e
            else:
                ref_file_paths.append(ref_filepath)
    print ref_file_paths  # 结果返回到 main.py 中

upload_file_path = sys.argv[1]  # 获取传入的 file 参数,即:file = "C:\\test\\maya\\文档\\w2.ma",此参数在拿到之前无法直接使用 file 参数。
get_ref_file_path(upload_file_path)
maya.standalone.uninitialize()

以上查询存在一个问题,如果 文件是由高版本 maya 软件(如 2018)创建,此时用低版本 maya(如 2017)打开,maya app 会报意外关闭错误。

因此,需要先获取文件和软件版本信息,比较后再处理查询。修改 get_ref.py 文件如下:

import os

...

def get_ref_file_path(upload_file_path):
    # ...

def get_version(upload_file_path):
    cmds.file(upload_file_path, open=True)
    file_version = cmds.fileInfo('version', query=True)  # ['2018']
    maya_version = cmds.about(version=True)
    cmds.file(upload_file_path, open=True)
    if file_version <= maya_version:
        print get_ref_file_path(upload_file_path)

upload_file_path = sys.argv[1]  # 获取传入的 file 参数,即:file = "C:\\test\\maya\\文档\\w2.ma",此参数在拿到之前无法直接使用 file 参数。
get_version(upload_file_path)
maya.standalone.uninitialize()

经测试,以上修改并不能解决 maya 软件报意外关闭错误,无论是在外部判断版本信息,还是内部,均不能幸免。甚至引入新的错误,由于此代码 cmds.file(upload_file_path, open=True) 导致查询引用文件时报错:错误: 请指定一个引用节点、一个被引用文件或一个来自被引用文件的节点

经思考,是否可以给个标志,执行两次 subprocess.Popen(mayaPath+' '+scriptPath+' '+upload_file_path+' '+flag,stdout=subprocess.PIPE,stderr=subprocess.PIPE),第一次执行函数 get_version,获取版本信息,在 main.py 中比较后再决定是否查询引用,依然不行,最后发现无论是查文件版本信息,还是文件的引用信息,都需要先打开文件,只要用低版本软件打开高版本文件,就会出错。所以得出结论,用 Python 命令获取文件版本信息是错误的方法。

经研究,maya 文件是一个可以打开的文本文件,存储着创建文件的 maya 版本信息,格式如:fileInfo "version" 2017;, 因此可以以二进制格式打开文件,获取文件中存储的创建文件时的 maya 软件版本。修改 get_ref.py 如下:

import os

...

def get_ref_file_path(upload_file_path):
    # ...

def get_version(upload_file_path):
    maya_version = cmds.about(version=True)  # unicode
    with open(upload_file_path, 'rb') as f:
        for i in f.readlines():
            if i.startswith(b'fileInfo "version"'):
                file_version = ((i.decode()).split('"')[-2])
                break
    return maya_version, file_version

if __name__ == '__main__':
    upload_file_path = sys.argv[1]
    maya_version, file_version = get_version(upload_file_path)
    if file_version <= maya_version:
        print get_ref_file_path(upload_file_path)
    maya.standalone.uninitialize()

如果仔细一点,还存在一个明显的版本号问题,即:查到的版本信息格式可能不一致,导致两个版本号无法比较。maya 有多个版本,目前了解到的版本号有如下格式:“2018”、“6.0”、“6.0.1”、“2011 x64”,如果格式一致,如 “2018” 和 “2017”,版本很容易比较大小。现在如果 1 个 “2018”,1 个 “6.5”,可以通过 float 转换成浮点数比较大小。再其次,如果,1 个 “2018”,1 个 “6.0.1”,该如何比较呢?又,如果 1 个 “6.0”,1 个 “6.0.1” 该如何比较?6.0 版本的软件与 6.0.1 版本的软件同属一个大版本,所以 “6.0.1” 版本的软件能否打开 “6.0” 版本的文件,而不出错呢?我没有这两个版本的软件,无法测试。这不是一个问题,而是一系列问题。可能还有许多其他的版本号,没有发现,所以需要调查,以及尽可能全面的解决这个问题。而如果能够确定 maya 以及文件的版本均是年份命名,那么这个问题也就不是问题了。

至此,相关的问题大概解决完毕,最后的问题可能是编码问题,由于 get_ref 文件执行 maya.cmds 的是 Python 2,而 main 使用的是 Python 3,编码是个问题。

在 main 文件中,得到正确的结果,是一个字符串列表,使用命令 eval(out.decode('utf-8')) 可以转为列表格式,而如果查询 err 错误信息,使用 err.decode('utf-8') 命令可能就不太行了,将 utf-8 改为 gbk 似乎可以,如果还是不行,可以把 \x 开头的字符单独复制出来,使用 utf-8 解码,得到中文字符,查看报错信息。

最后,似乎问题全部解决了。

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值