INTRODUCTION:
对于天天使用C++的人来说,学习和使用Maya脚本我觉得完全就像砍瓜切菜一般容易,唯一的难点在于记各种API以及熟练度上。下面我将记录一些maya里的脚本代码,也方便我日后Ctrl+C/V,我觉得三个小时学会Maya python脚本编程完全足够了。
C++派系出身的人写python的时候需要注意以下几点:
(1)请忘记类型这个概念,python中一切皆对象
(2)‘=’不是赋值,而是绑定一个名字
FORWARD DECLARATION:
下面是文章内容目录:
- Maya scripting basic concepts
- Create a poly
- Move, Scale, Rotate
- Create instance
- Loop Create Instance
- Random position
- Hide Object
- Group Objects
- Reset pivot
- Select Objects
- Object Type
- Create Constraint
- Animation key operations
- Create a window UI
- Add UI Elements Into Window
- Add/Get/Set Attribute
- Reconstruct Name String
- Add Expression
- Create a file or read write it
- Get vertex array in mesh object mode
- Write Vertex Data into file
- Save the file to the specified location and call out the selection path window
- Save maya file
- Snap shot
- Loop search Children or parent
MAIN CONTENT:
【1】Maya scripting basic concepts
在开始Maya编程之前一定要知道的是Maya的设计思想就是节点式。
这个和Unity很类似,一个Transform下面装一个Shape,Transform节点里包含了物体的位置,缩放,旋转等信息。ShapeNode里包含了顶点,UV等模型形状信息。
Transform:
Shape:
而一个Cube就是一个表,拿场景中的盒子为例
【2】Create a poly
import maya.cmds as cmd
cubeList = cmd.ls('myCube')
if len(cubeList) > 0:
cmd.delete(cubeList)
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
首先导入Maya的cmd然后从场景里找到是否存在一个叫myCube的Node列表。如果这个列表有长度,说明这个Cube已经创建了,需要先删除它然后重新创建。polyCube这个返回的是一个列表
创建求或者其它图形同理:
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
pSphere = cmd.polySphere(sx = 10, sy = 10, r = 5, name = 'mySphere')
pCylinder = cmd.polyCylinder(sx = 10, sy = 15, sz = 5, r = 5, h = 10, name = 'myCylinder')
pPolyTorus = cmd.polyTorus(r = 10, sr = 1, sx = 20, sy = 4, name = 'myTorus')
ls方法可以拿到Maya场景里的Node,并且把它存到一个列表里返回。因为Maya中物体的名字是唯一的所以上述代码是通过名字来拿物Node的。还可以通过物体类型来拿场景中的某一类物体,还可以通过选择列表拿物体,这些后面有论述。
【3】Move, Scale, Rotate
import maya.cmds as cmd
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
cmds.move(0, 10, 0, pCube)
cmds.scale(2, 2, 2, pCube)
cmds.rotate(45, 45, 0, pCube)
也可以使用xform来设置一个transform node的属性。
【4】Create instance
import maya.cmds as cmd
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
pCubeTransform = pCube[0]
pCUbeIns = cmd.instance(pCubeTransform, name = pCubeTransform + '_Instance')
【5】Loop Create Instance
import maya.cmds as cmd
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
pCubeTransform = pCube[0]
for i in range(0, 50):
pCubeIns = cmd.instance(pCubeTransform, name = pCubeTransform + '_Instance' + str(i))
cmd.move(0, 10 * i, 0, pCubeIns)
【6】Random position
import maya.cmds as cmd
import random
random.seed(1234)
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
pCubeTransform = pCube[0]
for i in range(0, 50):
x = random.uniform(-100, 100)
y = random.uniform(0, 100)
z = random.uniform(-100, 100)
pCubeIns = cmd.instance(pCubeTransform, name = pCubeTransform + '_Instance' + str(i))
cmd.move(x, y, z, pCubeIns)
【7】Hide Object
import maya.cmds as cmd
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
cmds.hide(pCube)
【8】Group Objects
import maya.cmds as cmd
import random
random.seed(1234)
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
pCubeTransform = pCube[0]
instGroup = cmd.group(empty = True, name = 'myInstGroup')
for i in range(0, 50):
x = random.uniform(-100, 100)
y = random.uniform(0, 100)
z = random.uniform(-100, 100)
pCubeIns = cmd.instance(pCubeTransform, name = pCubeTransform + '_Instance' + str(i))
cmd.parent(pCubeIns, instGroup)
cmd.move(x, y, z, pCubeIns)
【9】Reset pivot
import maya.cmds as cmd
import random
random.seed(1234)
pCube = cmd.polyCube(w = 10, h = 10, d = 10, name = 'myCube')
pCubeTransform = pCube[0]
instGroup = cmd.group(empty = True, name = 'myInstGroup')
for i in range(0, 50):
x = random.uniform(-100, 100)
y = random.uniform(0, 100)
z = random.uniform(-100, 100)
pCubeIns = cmd.instance(pCubeTransform, name = pCubeTransform + '_Instance' + str(i))
cmd.parent(pCubeIns, instGroup)
cmd.move(x, y, z, pCubeIns)
cmd.xform(instGroup, centerPivots = True)
【10】Select Objects
选择在Maya里要分为两部分作用,一个是从选择里获取,一个是把数据设置给当前选择的东西。
要想从外界传数据进脚本,方法之一就是从maya的选择列表里拿物体数据
import maya.cmds as cmd
selectObjectList = cmd.ls(orderedSelection = True)
print selectObjectList
或者也可以使用,有一个fl标志用于展平列表。
selectObjectList = cmd.ls(selection = True)
把属性设置给选择的物体,这时我们需要手动调用select命令,因为有写操作是只能对选择物体生效的,所以在执行这些操作之前需要在代码里先选中这个物体。如果场景里面有个pSphere1物体
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)
【11】Object Type
import maya.cmds as cmd
selectObjectList = cmd.ls(selection = True)
for obj in selectObjectList:
objType = cmd.objectType(obj)
print objType
在选择物体的时候可以加上Type作为过滤器
import maya.cmds as cmd
selectObjectList = cmd.ls(selection = True, type = 'transform')
for obj in selectObjectList:
objType = cmd.objectType(obj)
print objType
还可以通过Type拿到场景中全部的模型
allMeshInScene = cmds.ls(type='mesh')
【12】Create Constraint
import maya.cmds as cmd
selectObjectList = cmd.ls(orderedSelection = True)
if len(selectObjectList) >=2:
target = selectObjectList[0]
object = selectObjectList[1]
cmd.aimConstraint(target, object, aimVector = [0, 1, 0])
如果为一群物体创建aimConstraint可以得到如下效果:
import maya.cmds as cmd
selectObjectList = cmd.ls(orderedSelection = True)
if len(selectObjectList) >=2:
target = selectObjectList[0]
selectObjectList.remove(target)
for object in selectObjectList:
cmd.aimConstraint(target, object, aimVector = [0, 1, 0])
确保Target是第一个被选中的即可。
【13】Animation key operations
import maya.cmds as cmd
selectObjectList = cmd.ls(selection = True, type = 'transform')
if len(selectObjectList) >= 1:
startTime = cmd.playbackOptions(query = True, minTime = True)
endTime = cmd.playbackOptions(query = True, maxTime = True)
for obj in selectObjectList:
cmd.cutKey(obj, time = (startTime, endTime), attribute = 'rotateY')
cmd.setKeyframe(obj, time = startTime, attribute = 'rotateY', value = 0)
cmd.setKeyframe(obj, time = endTime, attribute = 'rotateY', value = 360)
cmd.selectKey(obj, time = (startTime, endTime), attribute = 'rotateY', keyframe = True)
cmd.keyTangent(inTangentType = 'linear', outTangentType = 'linear')
cmd.selectKey会先选中一段时间内的关键帧的的某些属性,然后调用cmd.keyTangent。这个函数会对我们选中的属性进行修改。
【14】Create a window UI
import maya.cmds as cmd
def createWindow(pWindowTitle):
windowID = 'myWindowID'
if cmd.window(windowID, exists = True):
cmd.deleteUI(windowID)
cmd.window(windowID, title = pWindowTitle, sizeable = False, resizeToFitChildren = True)
cmd.showWindow()
createWindow('MyWindow')
【15】Add UI Elements Into Window
创建一个窗口以后需要往里面加一些控件,但是在加空间之前需要先对Window进行布局
import maya.cmds as cmd
def createWindow(pWindowTitle):
windowID = 'myWindowID'
if cmd.window(windowID, exists = True):
cmd.deleteUI(windowID)
cmd.window(windowID, title = pWindowTitle, sizeable = False, resizeToFitChildren = True)
cmd.rowColumnLayout(numberOfColumns = 3, columnWidth = {(1, 75), (2, 60), (3, 60)})
cmd.text(label = 'my text one')
cmd.text(label = 'my two')
cmd.text(label = 'my three')
cmd.text(label = 'my text Four')
cmd.intField('pIntInput')
cmd.separator(h = 10, style = 'none')
cmd.intField('pIntInput2')
cmd.showWindow()
createWindow('MyWindow')
rowColumnLayout命令会对窗口进行布局切割numberOfColumns = 3表示横向切三刀,控件会从左往右依次填充,如果横排填满了就自动换行继续填充。
创建按钮回调函数
import maya.cmds as cmds
def create_window():
if cmds.window('mywindow', exists = True):
cmds.deleteUI('mywindow')
windowvar = cmds.window('mywindow')
cmds.columnLayout()
cmds.text(label = 'this is my window')
cmds.textField('pStatementInput')
cmds.floatField('pFloatInput')
cmds.intField('pIntInput')
cmds.button(label = 'print statement', command = 'printFunction()')
cmds.showWindow('mywindow')
def printFunction():
pStatement = cmds.textField('pStatementInput', q = True, text = True)
pInt = cmds.intField('pIntInput', q = True, value = True)
pFloat = cmds.floatField('pFloatInput', q = True, value = True)
print(pStatement + str(pInt) + str(pFloat))
create_window()
【16】Add/Get/Set Attribute
import maya.cmds as cmd
selectObjectList = cmd.ls(selection = True)
if len(selectObjectList) >= 1:
cmd.addAttr(longName = 'NewAttri', shortName = 'NewA', attributeType = 'double', min = 0, max = 100, defaultValue = 100, keyable = True)
获取Attribute的方式如下
import maya.cmds as cmds
MeshList = cmds.ls(sl = True, o = True)
Mesh = MeshList[0]
Loc = cmds.getAttr('%s.translate ' % (Mesh))
print Loc
设置方法如下
import maya.cmds as cmds
MeshList = cmds.ls(sl = True, o = True)
Mesh = MeshList[0]
cmds.setAttr('%s.translateX' % (Mesh), 10)
【17】Reconstruct Name String
import maya.cmds as cmd
selectObjectList = cmd.ls(selection = True)
objName = '%s.name' % selectObjectList[0]
print objName
【18】Add Expression
import maya.cmds as mc
mc.expression( s = 'pSphere1.translateX = cos(time/2)*10' )
在Maya中甚至可以给一个物体的一个属性在脚本里给它加上表达式,s是表达式的值,是字符串。time变量直接能获取滑杆的时间。
【19】Create a file or read write it
import maya.cmds as mc
pathToSave = 'D:\File'
createTextFile = open(pathToSave + 'aaa.txt', 'w')
可以多次调用write函数书写
最后close这个文件解除占用即可
import maya.cmds as mc
pathToSave = 'D:/'
createdTextFile = open(pathToSave + 'bbb.txt', 'w')
createdTextFile.write('this is my file\n')
createdTextFile.write('this is maya python\n')
createdTextFile.close()
读取文件也很简单
import maya.cmds as mc
pathToSave = 'D:/'
createdTextFile = open(pathToSave + 'bbb.txt', 'w')
createdTextFile.write('this is my file\n')
createdTextFile.write('this is maya python\n')
createdTextFile.close()
readFile = open(pathToSave + 'bbb.txt', 'r')
textVal = readFile.read()
print textVal
readFile.close()
【20】Get vertex array in mesh object mode
上面的几个例子中都是在物体的顶点模式下先选中所有顶点完成的,下面通过脚本直接在顶层Node情况下访问顶点数组
import maya.cmds as cmds
MeshList = cmds.ls(sl = True, o = True)
Mesh = MeshList[0]
VertexArray = cmds.ls('{}.vtx[:]'.format(Mesh), fl = True)
cmds.move(0, 20, sel_vtx[0])
【21】Write Vertex Data into file
在Maya中获取资源的数据实在太简单了,在引擎里想获得一点模型数据简直麻烦到爆炸。在maya中我们能轻松获取到我们想要的数据并且写入文件,这些数据我们可以到引擎去读取它们,这为我们写工具和自定义文件格式提供了方法。
import maya.cmds as cmd
vertexes = cmd.ls(selection = True, fl = True)
File = open('D:/MyFile.txt', 'w')
for vet in vertexes:
pos = cmd.xform(vet, query = True, translation = True, worldSpace = True)
File.write(str(pos) + '\n')
File.close()
这里要开启flatten标志,这是为了让列表中的元素全部都有数值被初始化。
对代码稍作美化:
import maya.cmds as cmd
MeshList = cmd.ls(selection = True, o = True)
Mesh = MeshList[0]
File = open("C:\Users\Yivanlee\Desktop/test.txt", 'w')
VertexArray = cmds.ls('{}.vtx[:]'.format(Mesh), fl = True)
for Vert in VertexArray:
pos = cmd.xform(Vert, query = True, translation = True, worldSpace = True)
X = str(pos[0])
Y = str(pos[1])
Z = str(pos[2])
File.write(X + "," + Y + "," + Z + "\n")
File.close()
ls的oflag是objectsOnly,当 objectsOnly打开时,只有物体的名字会被返回。物体的Components和Attribute都会被忽略
【22】Save the file to the specified location and call out the selection path window
import maya.cmds as cmd
MeshList = cmd.ls(selection = True, o = True)
Mesh = MeshList[0]
FilePath = ""
FileFilter = "*.txt"
FilePath = cmd.fileDialog2(fileFilter = FileFilter, dialogStyle = 2)
File = open(FilePath[0], 'w')
VertexArray = cmds.ls('{}.vtx[:]'.format(Mesh), fl = True)
for Vert in VertexArray:
pos = cmd.xform(Vert, query = True, translation = True, worldSpace = True)
X = str(pos[0])
Y = str(pos[1])
Z = str(pos[2])
File.write(X + "," + Y + "," + Z + "\n")
File.close()
【23】Save maya file
import maya.cmds as cmds
cmds.file(rename="C:/Users/Temp/Desktop/test.ma")
cmds.file(save=True, type="mayaAscii")
【24】Snap shot
import maya.cmds as cmd
cmds.sphere(n='sphere1')
cmds.currentTime('0')
cmds.setKeyframe('.t')
cmds.currentTime('30')
cmds.move(10,0,1)
cmds.setKeyframe('.t')
cmds.snapshot( 'sphere1', constructionHistory=True, startTime=0, endTime=30, increment=10 )
俗称快照,可以用于追踪顶点动画的每帧数据。顶点动画烘焙到纹理插件需要用到这个功能。
【25】Loop search Children or parent
import maya.cmds as cmds
Root = cmds.ls("joint1")[0]
BoneList = []
BoneList.append(Root)
while True:
Root = cmds.listRelatives(Root)
if Root is None:
break
BoneList.append(Root)
print BoneList