Maya脚本重复运行时如何避免Shader/Shading Engine被命名为MAT1、MATSG1?
问题解决:Maya肢体Shader统一与重命名重复运行增量问题
问题核心
脚本首次运行能正确为成对肢体分配同名Shader并重命名,但重复运行时Shader会出现Hand_MAT1、Hand_MATSG1这类带增量的命名;尝试删除现有Shader时误删网格信息。
问题原因
- 重命名未检查目标名称是否存在:重复运行时,目标Shader/着色组名称已存在,Maya自动添加增量后缀避免命名冲突。
- 删除Shader操作错误:直接删除Shader未先断开与网格的连接,导致连带删除了关联的形状节点(或误选了网格对象)。
- 现有逻辑未复用已存在的目标Shader:脚本每次运行都尝试重命名旧Shader,而非直接使用已存在的正确命名Shader。
修正后的脚本
import maya.cmds as cmds def get_or_create_body_shader(body_part): """获取或创建对应肢体的标准命名Shader与着色组""" shader_name = f"{body_part}_MAT" sg_name = f"{body_part}_MATSG" # 检查Shader是否已存在 if cmds.objExists(shader_name): shader = shader_name else: # 创建Lambert Shader(可根据需求替换为其他类型,比如aiStandardSurface) shader = cmds.shadingNode("lambert", asShader=True, name=shader_name) # 检查着色组是否已存在 if cmds.objExists(sg_name): sg = sg_name else: sg = cmds.sets(renderable=True, noSurfaceShader=True, empty=True, name=sg_name) # 连接Shader到着色组 cmds.connectAttr(f"{shader}.outColor", f"{sg}.surfaceShader", force=True) return sg, shader # 收集符合条件的肢体变换节点 selected_transforms = [] shading_engines = {} target_body_parts = ["Arm", "Leg", "Hand"] for transform in cmds.ls(transforms=True): if ("LT_" in transform or "RT_" in transform) and any(part in transform for part in target_body_parts): shapes = cmds.listRelatives(transform, shapes=True, noIntermediate=True) if shapes: # 获取当前形状节点的着色组 sgs = cmds.listConnections(shapes[0], type="shadingEngine") if sgs: sg_name = sgs[0] # 获取关联的Shader名称 shader_name = cmds.connectionInfo(f"{sg_name}.surfaceShader", sourceFromDestination=True).split(".")[0] shading_engines[transform] = [sg_name, shader_name] selected_transforms.append(transform) # 统一成对肢体的Shader for transform in selected_transforms: # 获取成对的肢体节点(LT/RT互换) paired_transform = transform.replace("LT_", "RT_") if "LT_" in transform else transform.replace("RT_", "LT_") if paired_transform not in shading_engines: continue # 提取肢体类型(Arm/Leg/Hand) body_part = transform.split("_")[1] # 获取或创建标准Shader与着色组 target_sg, target_shader = get_or_create_body_shader(body_part) # 将当前变换与成对变换的形状节点都指定到目标着色组 for t in [transform, paired_transform]: shapes = cmds.listRelatives(t, shapes=True, noIntermediate=True) if shapes: cmds.sets(shapes[0], edit=True, forceElement=target_sg) # 删除旧的Shader与着色组(如果不是目标对象) old_sg, old_shader = shading_engines[transform] if old_sg != target_sg and cmds.objExists(old_sg): # 先检查着色组是否还有其他连接,避免误删 members = cmds.sets(old_sg, query=True) if not members: cmds.delete(old_sg) if old_shader != target_shader and cmds.objExists(old_shader): # 检查Shader是否还有其他连接 connections = cmds.listConnections(old_shader, source=False, destination=True) if not connections: cmds.delete(old_shader) # 清理可能残留的重复Shader(可选) for part in target_body_parts: # 删除带增量的冗余Shader for shader in cmds.ls(f"{part}_MAT*"): if shader != f"{part}_MAT" and not cmds.listConnections(shader): cmds.delete(shader) # 删除带增量的冗余着色组 for sg in cmds.ls(f"{part}_MATSG*"): if sg != f"{part}_MATSG" and not cmds.sets(sg, query=True): cmds.delete(sg)
关键修改点
- 新增
get_or_create_body_shader函数:先检查目标名称的Shader/着色组是否已存在,存在则直接复用,不存在才创建,从根源避免增量命名问题 - 统一Shader分配逻辑:直接将成对肢体的形状节点指定到目标着色组,不再依赖原Shader的重命名操作
- 安全删除旧Shader:删除前检查旧Shader/着色组是否还有其他关联对象,只有无关联时才删除,彻底避免误删网格相关信息
- 清理冗余增量对象:自动删除带增量后缀的冗余Shader与着色组,保持场景命名整洁
内容的提问来源于stack exchange,提问作者Kartikey Sinha
相关产品推荐
相关产品推荐

