非常好,你希望这段 Maya 脚本在 **Python 2.7(Maya 2018 及以下)和 Python 3.x(Maya 2020+)都能运行**,这需要做**兼容性处理**,包括:
- 字符串编码(`str` vs `bytes`)
- `print` 语法
- `xrange` 替换为 `range`
- 异常捕获语法
- `reload` 的使用
- `import` 语法(相对导入 vs 绝对导入)
---
## ✅ ✅ 兼容 Python 2.7 和 Python 3.x 的完整脚本如下:
```python
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
import maya.cmds as cmds
import random
# Maya OpenMaya 兼容导入
try:
import maya.OpenMaya as om
import maya.OpenMayaUI as omui
PYTHON_2 = True
except ImportError:
from maya.api import OpenMaya as om
PYTHON_2 = False
def int_to_rgb(i):
"""将整数 i (0 ~ 16777215) 转换为 RGB 值(0-1)"""
r = ((i >> 16) & 0xFF) / 255.0
g = ((i >> 8) & 0xFF) / 255.0
b = (i & 0xFF) / 255.0
return (r, g, b)
def set_arnold_subdivision_gui():
window_name = "arnoldSubdivToolWindow"
if cmds.window(window_name, exists=True):
cmds.deleteUI(window_name)
window = cmds.window(window_name, title="Arnold Subdivision & Material Tool", widthHeight=(320, 260))
main_layout = cmds.columnLayout(adj=True, rs=10)
# ========================
# 第一部分:细分设置
# ========================
cmds.frameLayout(label="Arnold Subdivision Settings", width=300, collapsable=True)
subdiv_layout = cmds.columnLayout(adj=True)
type_menu = cmds.optionMenu(label="Type")
cmds.menuItem(label="None")
cmds.menuItem(label="Catclark")
iteration_field = cmds.intFieldGrp(numberOfFields=1, label="Iterations", value1=2)
apply_subdiv_button = cmds.button(label="Apply to Selected", command=lambda x: apply_subdivision_settings(type_menu, iteration_field))
cmds.button(apply_subdiv_button, edit=True, backgroundColor=[0, 1, 0])
cmds.setParent('..')
cmds.setParent('..')
# ========================
# 第二部分:材质设置
# ========================
cmds.frameLayout(label="Material Settings", width=300, collapsable=True)
material_layout = cmds.columnLayout(adj=True)
cmds.text(label="随机颜色分配(0-255,不重复)")
apply_mat_button = cmds.button(label="Apply Material to Selected", command=apply_random_material_settings)
cmds.button(apply_mat_button, edit=True, backgroundColor=[0, 1, 0])
cmds.setParent('..')
cmds.setParent('..')
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)
def set_arnold_subdivision(subdiv_type='catclark', iterations=2):
selected_transforms = cmds.ls(selection=True, transforms=True)
if not selected_transforms:
cmds.warning("Please select at least one object!")
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("无法为 %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("无法为 %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("成功设置 %s 的 Arnold Type 为 %s, Iterations 为 %s" % (shape, subdiv_type, iterations))
# ========================
# 功能函数:应用随机不重复材质(优化版,批量分配)
# ========================
def apply_random_material_settings(*args):
selected_transforms = cmds.ls(selection=True, transforms=True)
if not selected_transforms:
cmds.warning("请先选择至少一个物体!")
return
num_objs = len(selected_transforms)
total_colors = 16777216 # 256^3
if num_objs > total_colors:
cmds.warning("物体数量超过可用颜色总数!")
return
# 随机选取不重复的整数ID(每个ID对应一个RGB颜色)
color_indices = random.sample(range(total_colors), num_objs)
# 材质缓存
material_cache = {}
# 获取当前选择的 MSelectionList
sel = om.MSelectionList()
om.MGlobal.getActiveSelectionList(sel)
# 收集所有 shape 的路径
dag_paths = []
if PYTHON_2:
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) # 替代 extendToShapeDirectly
dag_paths.append(child_path)
elif dag_path.node().hasFn(om.MFn.kMesh):
dag_paths.append(dag_path)
sel_iter.next()
else:
sel_iter = om.MItSelectionList(sel, om.MFn.kMesh)
while not sel_iter.isDone():
dag_path = om.MDagPath()
sel_iter.getDagPath(dag_path)
dag_paths.append(dag_path)
sel_iter.next()
# 禁用刷新
cmds.refresh(suspend=True)
# 创建材质并分配
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 = "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("成功为 %s 个物体分配了随机颜色材质" % len(selected_transforms))
# 打开工具窗口
set_arnold_subdivision_gui()
```
---
## ✅ 关键兼容点说明
| 功能 | Python 2.7 写法 | Python 3 写法 | 兼容处理方式 |
|------|------------------|----------------|----------------|
| `print` | `print "xxx"` | `print("xxx")` | 使用 `from __future__ import print_function` |
| `xrange` | `xrange(10)` | `range(10)` | 使用 `range` |
| `str` 类型 | `str == bytes` | `str == unicode` | 使用 `unicode()` 或保持 `str` |
| `reload` | `reload(module)` | `importlib.reload(module)` | 使用 `import sys; reload = sys.reload` |
| `OpenMaya` 导入 | `import maya.OpenMaya as om` | `from maya.api import OpenMaya as om` | 使用 `try-except` 判断 |
| `异常语法` | `except Exception, e:` | `except Exception as e:` | 使用 `as` 语法兼容两者 |
---
## ✅