Maya控制器层级创建脚本报错:Cannot parent components or objects in the underworld
Let's break down why you're seeing that warning and how to fix it quickly:
The Root Cause
The cmds.circle() command returns a list with two items: the transform node (the top-level object you see in the Outliner) and the underlying shape node (the actual curve geometry, which lives in Maya's "underworld"—the lower part of the DAG hierarchy).
In your original code, you're storing the entire list in firstCtrl and circleCtrl, then trying to parent groups to these lists. Maya interprets this as trying to parent to the shape node (since it's part of the list), which is not allowed—shape nodes can't be parent targets for transforms.
The Fix
Simply grab only the transform node from the cmds.circle() result by indexing [0]. Here's the corrected code:
import maya.cmds as cmds def setZero(target): cmds.setAttr("%s.translateX" % target, 0) cmds.setAttr("%s.translateY" % target, 0) cmds.setAttr("%s.translateZ" % target, 0) cmds.setAttr("%s.rotateX" % target, 0) cmds.setAttr("%s.rotateY" % target, 0) cmds.setAttr("%s.rotateZ" % target, 0) # Add a check to avoid errors if nothing is selected selJoint = cmds.ls(selection=True, shortNames=True) if not selJoint: cmds.warning("Please select at least one joint first!") else: # Grab ONLY the transform node of the circle firstCtrl = cmds.circle(normal=(1,0,0))[0] firstGrp = cmds.group(firstCtrl) cmds.parent(firstGrp, selJoint[0]) setZero(firstGrp) cmds.parent(firstGrp, world=True) # Loop through remaining joints (skip first one directly) for joint in selJoint[1:]: # Again, grab the transform node of the new circle circleCtrl = cmds.circle(normal=(1,0,0))[0] offsetGrp = cmds.group(circleCtrl) cmds.parent(offsetGrp, joint) setZero(offsetGrp) cmds.parent(offsetGrp, world=True) cmds.parent(offsetGrp, firstCtrl) # Update the parent target for the next iteration firstCtrl = circleCtrl
Extra Improvements
- Added a check for empty selection to prevent index errors if no joints are selected.
- Changed the loop to iterate over
selJoint[1:]instead of checkingif joint == selJoint[0]each time—cleaner and more efficient. - If you want to simplify the
setZerofunction, you can usecmds.xforminstead of multiplesetAttrcalls:def setZero(target): cmds.xform(target, translate=(0,0,0), rotate=(0,0,0), worldSpace=False)
This will eliminate the "underworld" warning entirely, since you're now parenting groups to valid transform nodes (the circle controllers) instead of shape components.
内容的提问来源于stack exchange,提问作者DaveTheDolphin

