Maya Python 绑定工具开发深度指南
目录
- Maya Python 核心 API 解析
- 高级骨骼系统构建
- 控制器动态约束系统
- 面部绑定完整解决方案
- 蒙皮权重智能改造
- 工具界面深度集成
- Maya 性能优化策略
- 开发环境调试
1. Maya Python 核心 API 解析
1.1 节点操作最佳实践
import maya.cmds as cmds
import maya.mel as mel
import maya.api.OpenMaya as om2
def create_secure_node(node_type, name):
"""避免名称冲突的节点创建"""
if cmds.objExists(name):
cmds.delete(name)
return cmds.createNode(node_type, name=name)
ik_handle = create_secure_node("ikHandle", "arm_IK_handle")
1.2 API 2.0 高效操作
def get_mesh_points(mesh_name):
"""使用API 2.0快速获取网格顶点数据"""
sel = om2.MSelectionList()
sel.add(mesh_name)
dag = sel.getDagPath(0)
mfn_mesh = om2.MFnMesh(dag)
return mfn_mesh.getPoints()
2. 高级骨骼系统构建
2.1 自动关节方向校准
def auto_orient_joints(joint_chain):
"""自动计算关节局部坐标系"""
for i in range(len(joint_chain)-1):
current = joint_chain[i]
child = joint_chain[i+1]
current_pos = cmds.xform(current, q=True, ws=True, t=True)
child_pos = cmds.xform(child, q=True, ws=True, t=True)
direction = [child_pos[0]-current_pos[0],
child_pos[1]-current_pos[1],
child_pos[2]-current_pos[2]]
cmds.joint(current, e=True, orientJoint="xyz",
primaryAxis="x",
secondaryAxisOrient="yup")
2.2 智能镜像系统
def mirror_joint_chain(source_joint):
"""自动镜像骨骼链"""
mirror_map = {
"_L_": "_R_",
"Left": "Right",
"left": "right"
}
duplicated = cmds.duplicate(source_joint, po=True)[0]
for k, v in mirror_map.items():
duplicated = duplicated.replace(k, v)
cmds.setAttr(f"{duplicated}.scaleX", -1)
cmds.makeIdentity(duplicated, apply=True, t=1, r=1, s=1)
return duplicated
3. 控制器动态约束系统
3.1 多重约束切换
def create_space_switch(ctrl, targets):
"""创建空间切换系统"""
if not cmds.attributeQuery("space", node=ctrl, exists=True):
cmds.addAttr(ctrl, ln="space", at="enum",
enumName=":".join([t.split("_")[0] for t in targets]))
for i, target in enumerate(targets):
pc = cmds.pointConstraint(target, ctrl, mo=False)[0]
cond = cmds.createNode("condition",
name=f"{ctrl}_spaceCond_{i}")
cmds.setAttr(f"{cond}.secondTerm", i)
cmds.connectAttr(f"{ctrl}.space", f"{cond}.firstTerm")
cmds.setAttr(f"{cond}.colorIfTrueR", 1)
cmds.setAttr(f"{cond}.colorIfFalseR", 0)
cmds.connectAttr(f"{cond}.outColorR",
f"{pc}.{target}W0")
3.2 自定义约束节点
def create_matrix_constraint(driver, driven):
"""创建矩阵约束系统"""
mult_matrix = cmds.createNode("multMatrix",
name=f"{driver}_to_{driven}_multMatrix")
cmds.connectAttr(f"{driver}.worldMatrix[0]",
f"{mult_matrix}.matrixIn[0]")
cmds.connectAttr(f"{driven}.parentInverseMatrix",
f"{mult_matrix}.matrixIn[1]")
decomp = cmds.createNode("decomposeMatrix")
cmds.connectAttr(f"{mult_matrix}.matrixSum",
f"{decomp}.inputMatrix")
cmds.connectAttr(f"{decomp}.outputTranslate", f"{driven}.translate")
cmds.connectAttr(f"{decomp}.outputRotate", f"{driven}.rotate")
cmds.connectAttr(f"{decomp}.outputScale", f"{driven}.scale")
4. 面部绑定完整解决方案
4.1 混合形状组合系统
def create_combination_blendshapes(base_mesh, shapes):
"""创建组合混合形状系统"""
ctrl = cmds.circle(name="face_main_CTRL")[0]
cmds.addAttr(ctrl, ln="mouth", at="double", min=0, max=1, dv=0)
cmds.addAttr(ctrl, ln="eyes", at="double", min=0, max=1, dv=0)
blend_node = cmds.blendShape(shapes, base_mesh, name="face_blendshape")[0]
for i, shape in enumerate(shapes):
md = cmds.createNode("multiplyDivide",
name=f"{shape}_multiply")
if "mouth" in shape:
cmds.connectAttr(f"{ctrl}.mouth", f"{md}.input1X")
elif "eyes" in shape:
cmds.connectAttr(f"{ctrl}.eyes", f"{md}.input1X")
cmds.connectAttr(f"{md}.outputX",
f"{blend_node}.{shape}")
4.2 动态皱纹系统
def create_dynamic_wrinkles(mesh, joint_chain):
"""创建基于关节旋转的皱纹系统"""
cluster = cmds.cluster(mesh)[1]
for jnt in joint_chain:
md = cmds.createNode("multiplyDivide")
cmds.connectAttr(f"{jnt}.rotateX", f"{md}.input1X")
clamp = cmds.createNode("clamp")
cmds.setAttr(f"{clamp}.minR", -0.5)
cmds.setAttr(f"{clamp}.maxR", 0.5)
cmds.connectAttr(f"{md}.outputX", f"{clamp}.inputR")
cmds.connectAttr(f"{clamp}.outputR",
f"{cluster}.weightList[0].weights[0]")
5. 蒙皮权重智能处理
5.1 基于热力的权重扩散
def heat_diffusion_weighting(mesh, joints, iterations=10):
"""热力扩散权重平滑算法"""
sel = om2.MSelectionList()
sel.add(mesh)
dag = sel.getDagPath(0)
mfn_skin = om2.MFnSkinCluster(dag)
weights = om2.MDoubleArray()
mfn_skin.getWeights(dag, 0, weights)
adj = [[] for _ in range(len(weights))]
edge_iter = om2.MItMeshEdge(dag)
while not edge_iter.isDone():
v1 = edge_iter.vertexId(0)
v2 = edge_iter.vertexId(1)
adj[v1].append(v2)
adj[v2].append(v1)
edge_iter.next()
for _ in range(iterations):
new_weights = om2.MDoubleArray(len(weights), 0.0)
for v in range(len(weights)):
neighbors = adj[v]
total = sum(weights[n] for n in neighbors)
new_weights[v] = total / len(neighbors)
weights = new_weights
mfn_skin.setWeights(dag, 0, weights, False)
6. 工具界面深度集成
6.1 Maya 标记菜单集成
def create_rigging_marking_menu():
"""创建右键标记菜单"""
menu = '''
global proc RiggingMarkingMenu() {
popupMenu -mm 1 -button 3 "RiggingToolsMenu";
menuItem -label "Create Joint" -c "create_joint()";
menuItem -label "Add Controller" -c "add_controller()";
menuItem -divider;
menuItem -label "Mirror System" -c "mirror_system()";
setParent -menu ..;
}
'''
mel.eval(menu)
6.2 工具架
def create_docking_shelf():
"""创建停靠式工具界面"""
if cmds.dockControl("RiggingShelf", exists=True):
cmds.deleteUI("RiggingShelf")
window = cmds.window()
layout = cmds.columnLayout()
cmds.button(label="Auto Rig", c="create_auto_rig()")
cmds.button(label="Mirror System", c="mirror_system()")
cmds.button(label="Skin Tools", c="show_skin_tools()")
cmds.dockControl("RiggingShelf",
area="left",
content=window,
allowedArea=["left", "right"])
7. Maya 性能优化策略
7.1 节点计算冻结
def freeze_transform_hierarchy(top_node):
"""冻结变换层级"""
nodes = cmds.listRelatives(top_node, ad=True, type="transform") or []
nodes.append(top_node)
for node in nodes:
cmds.makeIdentity(node, apply=True, t=1, r=1, s=1)
cmds.delete(node, ch=True)
7.2 动画缓存优化
def create_animation_cache(start, end):
"""创建动画缓存"""
cache_node = cmds.createNode("cacheFile", name="animCache")
cmds.setAttr(f"{cache_node}.cachePath", "//project/cache/", type="string")
cmds.setAttr(f"{cache_node}.startFrame", start)
cmds.setAttr(f"{cache_node}.endFrame", end)
character = cmds.ls(type="character")[0]
cmds.connectAttr(f"{character}.message", f"{cache_node}.characters")
8. 开发环境调试技巧
8.1 错误处理增强
def safe_delete(nodes):
"""带错误处理的删除操作"""
for node in nodes:
try:
if cmds.objExists(node):
cmds.delete(node)
except Exception as e:
print(f"删除失败 {node}: {str(e)}")
continue
8.2 调试信息覆盖
def debug_scene():
"""场景调试"""
print("\n=== 场景调试报告 ===")
print(f"总节点数: {len(cmds.ls())}")
print(f"空组数量: {len(cmds.ls(empty=True))}")
print(f"无连接属性: {len(cmds.ls(unused=True))}")
print("骨骼层级检查:")
for jnt in cmds.ls(type="joint"):
children = cmds.listRelatives(jnt, c=True)
print(f"{jnt}: {len(children) if children else 0} 个子物体")