312 lines
9.2 KiB
Markdown
312 lines
9.2 KiB
Markdown
|
---
|
|||
|
title: Maya Python笔记
|
|||
|
date: 2022-08-09 13:55:15
|
|||
|
tags: Maya
|
|||
|
rating: ⭐️⭐️
|
|||
|
---
|
|||
|
# 前言
|
|||
|
# 前期准备
|
|||
|
开发环境搭建:https://www.jianshu.com/p/813b2cc71ca2
|
|||
|
|
|||
|
《Maya Python游戏与影视编程指南》这个书还是挺不错的。
|
|||
|
|
|||
|
# VSCode插件
|
|||
|
除了必须的Python(打开一个Py文件就会提示安装),我使用的是MayaPy与MayaCode。
|
|||
|
|
|||
|
# Maya开启端口
|
|||
|
在Maya中开启端口,这样就可以在VSCode中将代码直接发送到Maya中执行。
|
|||
|
## Mel
|
|||
|
commandPort -name "localhost:7001" -sourceType "mel" -echoOutput;
|
|||
|
|
|||
|
## Python
|
|||
|
```python
|
|||
|
import maya.cmds as cmds
|
|||
|
|
|||
|
cmds.commandPort(name=":7001", sourceType="mel",echoOutput=True)
|
|||
|
```
|
|||
|
|
|||
|
建议建一个脚本文件,这样就不用每次启动都手动开启端口了。以Python为例,把上面Python代码复制到新建的.py文件中,放到下面目录:
|
|||
|
```s
|
|||
|
Windows: <drive>:\Documents and Settings\<你的windows用户名>\My Documents\maya\<你maya的版本号>\scripts
|
|||
|
(其实就是我的文档下面maya文件夹)
|
|||
|
MacOSX: ~/Library/Preferences/Autodesk/maya/<你maya的版本号>/scripts.
|
|||
|
Linux: ~/maya/<你maya的版本号>/scripts.
|
|||
|
```
|
|||
|
|
|||
|
# Maya Python路径设置及代码自动补全
|
|||
|
VS Code中按Ctrl+Shift+P,输入Settings打开settings.json配置文件,在大括号里加入下面代码:
|
|||
|
```
|
|||
|
//python.pythonPath是指定Python命令路径,请根据你maya的安装路径来做修改
|
|||
|
"python.pythonPath": "C:/Program Files/Autodesk/Maya2019/bin/mayapy.exe",
|
|||
|
//python.autoComplete.extraPaths是代码自动补全路径,同样根据你自己的maya安装路径来写
|
|||
|
"python.autoComplete.extraPaths": "C:/Program Files/Autodesk/Maya2019/devkit/other/pymel/extras/completion/py"
|
|||
|
```
|
|||
|
|
|||
|
注意:settings.json文件中,每一项设置用","隔开,最后一项设置后面没有",",如果报错,检查一下是不是这里出现了问题。
|
|||
|
|
|||
|
# Flag参数
|
|||
|
```
|
|||
|
-e -edit
|
|||
|
-q -query
|
|||
|
-ax. -axis Length Length Length
|
|||
|
-cch -caching onloff
|
|||
|
-ch -constructionHistory onloff
|
|||
|
-cuv -createUVs Int
|
|||
|
-d -depth Length
|
|||
|
-h -height Length
|
|||
|
-n - name String
|
|||
|
- nds - nodeState Int
|
|||
|
-0 -object onlof f
|
|||
|
-sd -subdivisionsDepth Int
|
|||
|
-sh - subdivisionsHeight Int
|
|||
|
-sw -subdivis ionsWidth Int
|
|||
|
-SX -subdivisionsX Int
|
|||
|
-sy -subdivisionsY Int
|
|||
|
-sz - subdivisionsZ Int
|
|||
|
-tx -texture Int
|
|||
|
-W -width Length
|
|||
|
```
|
|||
|
## 查询参数
|
|||
|
使用以下命令可以查询具体函数的flag,例如polyCube:
|
|||
|
```
|
|||
|
print(cmds.help('polyCube'));
|
|||
|
```
|
|||
|
结果为:
|
|||
|
```
|
|||
|
Synopsis: polyCube [flags] [String...]
|
|||
|
Flags:
|
|||
|
-e -edit
|
|||
|
-q -query
|
|||
|
-ax -axis Length Length Length
|
|||
|
-cch -caching on|off
|
|||
|
-ch -constructionHistory on|off
|
|||
|
-cuv -createUVs Int
|
|||
|
-d -depth Length
|
|||
|
-fzn -frozen on|off
|
|||
|
-h -height Length
|
|||
|
-n -name String
|
|||
|
-nds -nodeState Int
|
|||
|
-o -object on|off
|
|||
|
-sd -subdivisionsDepth Int
|
|||
|
-sh -subdivisionsHeight Int
|
|||
|
-sw -subdivisionsWidth Int
|
|||
|
-sx -subdivisionsX Int
|
|||
|
-sy -subdivisionsY Int
|
|||
|
-sz -subdivisionsZ Int
|
|||
|
-tx -texture Int
|
|||
|
-w -width Length
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
# 【10】Select Objects
|
|||
|
选择在Maya里要分为两部分作用,一个是从选择里获取,一个是把数据设置给当前选择的东西。
|
|||
|
要想从外界传数据进脚本,方法之一就是从maya的选择列表里拿物体数据
|
|||
|
```python
|
|||
|
import maya.cmds as cmd
|
|||
|
|
|||
|
selectObjectList = cmd.ls(orderedSelection = True)
|
|||
|
print selectObjectList
|
|||
|
```
|
|||
|
|
|||
|
把属性设置给选择的物体,这时我们需要手动调用select命令,因为有写操作是只能对选择物体生效的,所以在执行这些操作之前需要在代码里先选中这个物体。如果场景里面有个pSphere1物体
|
|||
|
```python
|
|||
|
import maya.cmds as cmd
|
|||
|
cmd.select('pSphere1')
|
|||
|
清除空选择列表:
|
|||
|
|
|||
|
import maya.cmds as cmd
|
|||
|
cmd.select(clear = True)
|
|||
|
加选
|
|||
|
|
|||
|
import maya.cmds as cmd
|
|||
|
cmd.select('pSphere1')
|
|||
|
cmd.select('pSphere2', add = True)
|
|||
|
```
|
|||
|
|
|||
|
从列表中获取所有节点
|
|||
|
```python
|
|||
|
nodes=cmds.ls();
|
|||
|
print(nodes)
|
|||
|
```
|
|||
|
|
|||
|
添加类型限制
|
|||
|
```python
|
|||
|
nodes=cmds.ls(type='transform');
|
|||
|
print(nodes)
|
|||
|
```
|
|||
|
|
|||
|
字符串配合通配符*
|
|||
|
```python
|
|||
|
nodes = cmds.ls('joint*');
|
|||
|
print(nodes);
|
|||
|
```
|
|||
|
|
|||
|
选中指定的物体
|
|||
|
```python
|
|||
|
cmds.select('side*','top*');
|
|||
|
```
|
|||
|
|
|||
|
select指令与ls指令可以结合使用,例如:
|
|||
|
```python
|
|||
|
cmds.ls(sl=True);
|
|||
|
cmds.select(cmds.ls('joint*'));
|
|||
|
```
|
|||
|
|
|||
|
# getAttr与setAttr
|
|||
|
通过字符串获取属性,不容易报错。
|
|||
|
```python
|
|||
|
loc=cmds.spaceLocator()[0]
|
|||
|
sx=cmds.getAttr(loc+'.scaleX')
|
|||
|
print(sx)
|
|||
|
```
|
|||
|
但注意,因为不确定类型,所以请注意数据格式
|
|||
|
|
|||
|
# 对应的容器
|
|||
|
有数组、map与set
|
|||
|
## 序列操作符
|
|||
|
```
|
|||
|
x in s 如在在序列中则返回true
|
|||
|
x not in s 如果不在序列中则返回true
|
|||
|
s+t 串联
|
|||
|
s[i] s序列中的第i项
|
|||
|
s[i:j] 取得指定范围的成员
|
|||
|
s[i:j:k] 取得指定范围的成员,k为步长
|
|||
|
len(s) 长度
|
|||
|
min(s) 最小项
|
|||
|
max(s) 最大项
|
|||
|
s.index(x) 第一次出现的index
|
|||
|
s.count(x) 出现次数
|
|||
|
```
|
|||
|
|
|||
|
# 可变参数的函数
|
|||
|
```python
|
|||
|
def function1(*args):
|
|||
|
print(args[0],args[1:]);
|
|||
|
```
|
|||
|
两个**则代表Map
|
|||
|
|
|||
|
# cmds.file
|
|||
|
可以用于保存、新建、打开新场景。
|
|||
|
|
|||
|
# 模块
|
|||
|
查看全局与本地队友对象:globals()与locals()
|
|||
|
|
|||
|
```
|
|||
|
__main__ #为当前MayaPython编辑器模块。
|
|||
|
__file__ #文件绝对路径
|
|||
|
__package__ #所在包名
|
|||
|
```
|
|||
|
|
|||
|
在一个文件夹中放入一个__init__.py与其他*.py文件,之后就可以
|
|||
|
```python
|
|||
|
import 文件夹名;
|
|||
|
文件夹名.py名.function()
|
|||
|
```
|
|||
|
调用函数
|
|||
|
# 路径
|
|||
|
```python
|
|||
|
import sys;
|
|||
|
for p in sys.path:
|
|||
|
print(p)
|
|||
|
```
|
|||
|
# 类
|
|||
|
```python
|
|||
|
class NewClass(object):
|
|||
|
pass;
|
|||
|
```
|
|||
|
实例化
|
|||
|
```python
|
|||
|
instance1=NewClass();
|
|||
|
instance2=NewClass();
|
|||
|
```
|
|||
|
构造函数
|
|||
|
```python
|
|||
|
class Human(object):
|
|||
|
def __init__(self):
|
|||
|
self.first_name='aaaa';
|
|||
|
self.last_name='bbbb';
|
|||
|
```
|
|||
|
# PyMel
|
|||
|
PyMel与maya.cmds不同在于,它返回的不是字符串,而是一个PyNode对象。它可以直接修改节点属性值,无需调用getAttr与setAttr。更加适合于习惯了OOP语言人士使用。同时PyMel可以简化GUI的构建。
|
|||
|
|
|||
|
# GUI
|
|||
|
开发包里有一些案例文件可以参考:
|
|||
|
- devkit\pythonScripts\widgetHierarchy.py
|
|||
|
|
|||
|
推荐使用Maya安装目录下的designer.exe
|
|||
|
|
|||
|
安装 PySide2:安装 python 后,在安装目录下有 /script 文件夹,里面有 pip.exe ,cmd执行:pip install PySide,pip install PySide2(注意: python2.x 对应 PySide,python3.x 对应PySide2)pyside-uic.exe 位于Python的安装目录下
|
|||
|
|
|||
|
## python HumanIK
|
|||
|
无效 https://forums.autodesk.com/t5/maya-programming/python-hik/td-p/4262564
|
|||
|
https://forums.autodesk.com/t5/maya-animation-and-rigging/pythonic-mel-way-to-retarget-hik/td-p/7609798
|
|||
|
|
|||
|
## 文档
|
|||
|
- http://help.autodesk.com/view/MAYAUL/2018/ENU/?guid=GUID-CEC1D76B-7568-4DCA-B80B-1DE49362492C&pl=CHS
|
|||
|
- http://help.autodesk.com/cloudhelp/2018/JPN/Maya-Tech-Docs/PyMel/generated/pymel.core.animation.html
|
|||
|
|
|||
|
## Pyside2文档
|
|||
|
百度的时候请搜索PyQt5
|
|||
|
https://doc.qt.io/qtforpython/modules.html
|
|||
|
|
|||
|
## 信号槽与解决生命周期问题
|
|||
|
其中SIGNAL需要先导入
|
|||
|
```python
|
|||
|
from PySide2.QtCore import SIGNAL, QObject
|
|||
|
|
|||
|
class MainWindow(QWidget, Ui_Form):
|
|||
|
def slotBtnClicked(self):
|
|||
|
msgBox = QMessageBox(self)
|
|||
|
msgBox.setText(u"The document has been modified.")
|
|||
|
msgBox.setInformativeText(u"Do you want to save your changes?")
|
|||
|
msgBox.setStandardButtons(QMessageBox.Save)
|
|||
|
msgBox.setDefaultButton(QMessageBox.Save)
|
|||
|
msgBox.show()
|
|||
|
def __init__(self, parent=None):
|
|||
|
self.pushButton_stop.clicked.connect(self.slotBtnClicked)
|
|||
|
QObject.connect(self.pushButton_targetSkin,SIGNAL('clicked()'), self.slotBtnClicked)
|
|||
|
```
|
|||
|
|
|||
|
# FBX Mel文档
|
|||
|
https://knowledge.autodesk.com/zh-hans/support/maya/learn-explore/caas/CloudHelp/cloudhelp/2019/CHS/Maya-DataExchange/files/GUID-335F2172-DD4D-4D79-B969-55238C08F2EF-htm.html
|
|||
|
|
|||
|
# FBX导出
|
|||
|
```
|
|||
|
# FBX Exporter options. Set as required.
|
|||
|
# You can find a reference guide here: http://download.autodesk.com/us/fbx/20112/Maya/_index.html
|
|||
|
# Just add/change what you need.
|
|||
|
|
|||
|
# Geometry
|
|||
|
mm.eval("FBXExportSmoothingGroups -v true")
|
|||
|
mm.eval("FBXExportHardEdges -v false")
|
|||
|
mm.eval("FBXExportTangents -v false")
|
|||
|
mm.eval("FBXExportSmoothMesh -v true")
|
|||
|
mm.eval("FBXExportInstances -v false")
|
|||
|
mm.eval("FBXExportReferencedContainersContent -v false")
|
|||
|
# Animation
|
|||
|
mm.eval("FBXExportBakeComplexAnimation -v true")
|
|||
|
mm.eval("FBXExportBakeComplexStart -v "+str(exportStartFrame[x]))
|
|||
|
mm.eval("FBXExportBakeComplexEnd -v "+str(exportEndFrame[x]))
|
|||
|
mm.eval("FBXExportBakeComplexStep -v 1")
|
|||
|
# mm.eval("FBXExportBakeResampleAll -v true")
|
|||
|
mm.eval("FBXExportUseSceneName -v false")
|
|||
|
mm.eval("FBXExportQuaternion -v euler")
|
|||
|
mm.eval("FBXExportShapes -v true")
|
|||
|
mm.eval("FBXExportSkins -v true")
|
|||
|
# Constraints
|
|||
|
mm.eval("FBXExportConstraints -v false")
|
|||
|
# Cameras
|
|||
|
mm.eval("FBXExportCameras -v false")
|
|||
|
# Lights
|
|||
|
mm.eval("FBXExportLights -v false")
|
|||
|
# Embed Media
|
|||
|
mm.eval("FBXExportEmbeddedTextures -v false")
|
|||
|
# Connections
|
|||
|
mm.eval("FBXExportInputConnections -v false")
|
|||
|
# Axis Conversion
|
|||
|
mm.eval("FBXExportUpAxis y")
|
|||
|
|
|||
|
# Export!
|
|||
|
mm.eval("FBXExport -f "+exportNames[x]+".fbx -s")
|
|||
|
```
|