明白了!你希望这段 Maya Python 脚本能够在 **Maya 2018 或更早版本**(使用 Python 2.7)中运行。
虽然你之前的代码已经是 Python 2 兼容的,但为了确保它在 **Maya 2016~2018(Python 2.7)** 中**完全兼容且稳定运行**,我们需要做一些调整。
---
## ✅ 兼容性调整说明:
| 项目 | 是否需要调整 | 原因 |
|------|----------------|------|
| `from __future__` 导入 | 是 | Python 2 默认没有这些,但可以保留 |
| `print()` 函数 | 是 | Python 2 需要去掉括号或使用 `from __future__ import print_function` |
| `int_to_rgb` 函数 | 否 | 已兼容 |
| `lambda` 表达式 | 否 | Maya Python 2 支持 |
| `try/except` | 否 | 完全支持 |
| `random.sample()` | 否 | 完全支持 |
| `MItSelectionList` | 否 | OpenMaya 1.0,兼容 Python 2 |
---
## ✅ 以下是你在 **Maya Python 2.7** 环境下运行的完整代码:
```python
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
import maya.cmds as cmds
import maya.OpenMaya as om
import random
# 加载 Arnold 插件
def load_arnold_plugin():
if not cmds.pluginInfo("mtoa", query=True, loaded=True):
try:
cmds.loadPlugin("mtoa")
print(u"成功加载 Arnold 插件 (mtoa)")
except Exception as e:
cmds.warning(u"无法加载 Arnold 插件,请确认是否已安装 MtoA!")
return False
return True
# 创建主窗口
def create_tool_window():
window_name = "arnoldSubdivToolWindow"
if cmds.window(window_name, exists=True):
cmds.deleteUI(window_name)
window = cmds.window(window_name, title=u"Arnold Subdivision & Material Tool", widthHeight=(320, 340))
main_layout = cmds.columnLayout(adj=True, rs=10)
# ========================
# 第一部分:细分设置
# ========================
if load_arnold_plugin():
cmds.frameLayout(label=u"Arnold Subdivision Settings", width=300, collapsable=True)
subdiv_layout = cmds.columnLayout(adj=True)
type_menu = cmds.optionMenu(label=u"细分类型")
cmds.menuItem(label="None")
cmds.menuItem(label="Catclark")
iteration_field = cmds.intFieldGrp(numberOfFields=1, label=u"细分层级", value1=2)
apply_subdiv_button = cmds.button(
label=u"应用细分设置",
command=lambda x: apply_subdivision_settings(type_menu, iteration_field)
)
cmds.button(apply_subdiv_button, edit=True, backgroundColor=[0, 1, 0])
cmds.setParent('..') # 返回 frameLayout
cmds.setParent('..') # 返回主 layout
else:
cmds.text(label=u"未加载 Arnold 插件,无法使用细分设置。", align='center')
# ========================
# 第二部分:材质设置
# ========================
cmds.frameLayout(label=u"材质设置", width=300, collapsable=True)
material_layout = cmds.columnLayout(adj=True)
cmds.text(label=u"随机颜色分配(RGB,不重复)")
apply_mat_button = cmds.button(
label=u"应用随机材质",
command=apply_random_material_settings
)
cmds.button(apply_mat_button, edit=True, backgroundColor=[0, 1, 0])
cmds.setParent('..') # 返回 frameLayout
cmds.setParent('..') # 返回主 layout
# ========================
# 第三部分:OpenSubdiv UV Boundary 设置(下拉菜单 + Apply 按钮)
# ========================
cmds.frameLayout(label=u"OpenSubdiv UV Boundary 设置", width=300, collapsable=True)
uv_layout = cmds.columnLayout(adj=True)
cmds.text(label=u"UV 边界细分模式选择", align='center')
uv_mode_menu = cmds.optionMenu(label=u"UV Boundary 模式")
cmds.menuItem(label="Maya Catmull-Clark")
cmds.menuItem(label="Preserve Edges and Corners")
apply_uv_button = cmds.button(
label=u"应用到选中物体",
command=lambda x: apply_uv_boundary_settings(uv_mode_menu),
backgroundColor=[0.3, 0.6, 1.0]
)
cmds.setParent('..') # 返回 frameLayout
cmds.setParent('..') # 返回主 layout
cmds.showWindow(window)
# 应用细分设置
def apply_subdivision_settings(type_menu, iteration_field):
type_index = cmds.optionMenu(type_menu, query=True, select=True)
iterations = cmds.intFieldGrp(iteration_field, query=True, value1=True)
subdiv_type = 'catclark' if type_index == 2 else 'none'
set_arnold_subdivision(subdiv_type, iterations)
# 设置 Arnold 细分
def set_arnold_subdivision(subdiv_type='catclark', iterations=2):
selected_transforms = cmds.ls(selection=True, transforms=True)
if not selected_transforms:
cmds.warning(u"请先选择至少一个物体!")
return
for transform in selected_transforms:
shapes = cmds.listRelatives(transform, shapes=True, fullPath=True)
if not shapes:
continue
for shape in shapes:
if cmds.objectType(shape) != 'mesh':
continue
if not cmds.attributeQuery('aiSubdivType', node=shape, exists=True):
try:
cmds.addAttr(shape, ln='aiSubdivType', at='enum', en='none:catclark', dv=0, k=True)
except Exception as e:
cmds.warning(u"无法为 %s 添加 aiSubdivType 属性:%s" % (shape, e))
continue
if not cmds.attributeQuery('aiSubdivIterations', node=shape, exists=True):
try:
cmds.addAttr(shape, ln='aiSubdivIterations', at='long', min=0, max=10, dv=1, k=True)
except Exception as e:
cmds.warning(u"无法为 %s 添加 aiSubdivIterations 属性:%s" % (shape, e))
continue
subdiv_value = 1 if subdiv_type == 'catclark' else 0
cmds.setAttr(shape + ".aiSubdivType", subdiv_value)
cmds.setAttr(shape + ".aiSubdivIterations", iterations)
print(u"成功设置 %s 的 Arnold Type 为 %s, Iterations 为 %s" % (shape, subdiv_type, iterations))
# 设置 OpenSubdiv UV Boundary 模式
def apply_uv_boundary_settings(mode_menu):
mode_index = cmds.optionMenu(mode_menu, query=True, select=True) # 返回 1 或 2
selected_transforms = cmds.ls(selection=True, transforms=True)
if not selected_transforms:
cmds.warning(u"请先选择至少一个物体!")
return
for transform in selected_transforms:
shapes = cmds.listRelatives(transform, shapes=True, fullPath=True)
if not shapes:
continue
for shape in shapes:
if cmds.objectType(shape) != 'mesh':
continue
# 检查 smoothMeshUVBoundary 属性是否存在
if not cmds.attributeQuery('smoothMeshUVBoundary', node=shape, exists=True):
try:
cmds.addAttr(shape, ln='smoothMeshUVBoundary',
at='enum', en='Maya Catmull-Clark:Preserve Edges and Corners', dv=0, k=True)
except Exception as e:
cmds.warning(u"无法为 %s 添加 smoothMeshUVBoundary 属性:%s" % (shape, e))
continue
# 设置属性值(注意:optionMenu 的 index 从 1 开始)
mode_value = mode_index - 1 # 1 -> 0, 2 -> 1
cmds.setAttr(shape + ".smoothMeshUVBoundary", mode_value)
mode_str = "Maya Catmull-Clark" if mode_value == 0 else "Preserve Edges and Corners"
print(u"成功设置 %s 的 UV Boundary 模式为 %s" % (shape, mode_str))
# 将整数转换为 RGB 值(0-1)
def int_to_rgb(i):
r = ((i >> 16) & 0xFF) / 255.0
g = ((i >> 8) & 0xFF) / 255.0
b = (i & 0xFF) / 255.0
return (r, g, b)
# 应用随机材质
def apply_random_material_settings(*args):
selected_transforms = cmds.ls(selection=True, transforms=True)
if not selected_transforms:
cmds.warning(u"请先选择至少一个物体!")
return
num_objs = len(selected_transforms)
total_colors = 16777216 # 256^3
if num_objs > total_colors:
cmds.warning(u"物体数量超过可用颜色总数!")
return
color_indices = random.sample(range(total_colors), num_objs)
# 获取所有选中模型的 shape 节点
sel = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sel)
dag_paths = []
sel_iter = om.MItSelectionList(sel)
while not sel_iter.isDone():
dag_path = om.MDagPath()
sel_iter.getDagPath(dag_path)
if dag_path.node().hasFn(om.MFn.kTransform):
for i in range(dag_path.childCount()):
child = dag_path.child(i)
if child.hasFn(om.MFn.kMesh):
child_path = om.MDagPath(dag_path)
child_path.push(child)
dag_paths.append(child_path)
elif dag_path.node().hasFn(om.MFn.kMesh):
dag_paths.append(dag_path)
sel_iter.next()
# 禁用刷新提升性能
cmds.refresh(suspend=True)
material_cache = {}
for idx, dag_path in enumerate(dag_paths):
r, g, b = int_to_rgb(color_indices[idx])
r_int = int(r * 255)
g_int = int(g * 255)
b_int = int(b * 255)
mat_name = u"randomMat_ID_{0}_{1}_{2}".format(r_int, g_int, b_int)
if mat_name in material_cache:
mat = material_cache[mat_name]
else:
if not cmds.objExists(mat_name):
mat = cmds.shadingNode('lambert', asShader=True, name=mat_name)
sg = cmds.sets(renderable=True, noSurfaceShader=True, empty=True, name=mat_name + "SG")
cmds.connectAttr(mat + ".outColor", sg + ".surfaceShader", f=True)
cmds.setAttr(mat + ".color", r, g, b, type='double3')
else:
mat = mat_name
material_cache[mat_name] = mat
shape_name = dag_path.fullPathName()
sg = mat + "SG"
cmds.sets(shape_name, forceElement=sg)
# 恢复刷新
cmds.refresh(suspend=False)
print(u"成功为 %s 个物体分配了随机颜色材质" % len(selected_transforms))
# 启动工具界面
create_tool_window()
```
---
## ✅ 使用方法(Maya Python 2.7):
1. 打开 Maya(2016~2018)
2. 打开 Script Editor
3. 切换到 Python 语言模式
4. 将上面的代码粘贴进去并运行
5. 工具窗口会自动弹出
---
## ✅