使用 Python 在 Maya 中旋转父控制器后计算父控制器的新位置
Calculating the new position of a parented controller after rotating the parent in Maya using Python
我正在创建代码以根据控制器在 Maya 中的关键帧位置创建控制器的运动路径。在尝试使用此代码创建父级控制器的运动路径时,我遇到了 运行 问题。如果我旋转和平移父对象,生成的运动路径不会反映实际的运动路径。相反,它会创建运动路径,就好像它不受父级影响一样。我环顾四周,找到了使用矩阵变换将旋转应用到当前位置的信息,但它似乎旋转得太多了。我已经包含了创建运动路径的功能,它有点长,但在处理上躯干控制器时,不起作用的部分在 else 语句中。
旧代码
#
# This function creates an animation curve within the scene that follows the path of motion
# of the selected controller. It requires keyframe information in order to genereate the curve
# and uses the range of frames given by the user.
#
def createAnimCurve( bodyField, startField, endField, firstColor ):
# Takes the value of the text field to select the controller
obj = cmds.textField(bodyField, query=True, text=True)
print obj
# Takes in the string input of the paramter values and turns them into integer values
startFrame = cmds.intField(startField, query=True, value=True)
print startFrame
endFrame = cmds.intField(endField, query=True, value=True)
print endFrame
color = cmds.colorIndexSliderGrp( firstColor, query=True, value=True ) - 1
print color
if obj == "":
cmds.warning( "WARNING: Need to Select Body Part from Diagram" )
return
if cmds.objExists(obj[:-3]+'Path'):
# Creates a warning pop up that double checks if the user wants to remove the curve
delRes = cmds.confirmDialog( title='Delete Path Warning', message='Recreation will delete current path. Are you sure?', button=['Yes','No'], defaultButton='Yes', cancelButton='No', dismissString='No' )
# If yes then the curve is deleted
if delRes == 'Yes':
#cmds.delete(obj[:-3]+'ScalePath')
#cmds.delete(obj[:-3]+'ScalePath_LOC')
cmds.delete(obj[:-3]+'Path')
cmds.delete(obj[:-3]+'Path_LOC')
else:
return
# Sorts through the list of keyframes of the selected obj from the selected time line
global keyframes
keyframes = sorted(list(set(cmds.keyframe(obj, q=True, time=(startFrame,endFrame), timeChange=True))))
# Creates the arrays for the required point positions
points = []
centerPoints = []
centerRotates = []
combinedPoints = []
# Special cases for controllers that are named differently than their joints
if obj == "L_foot_CTL" or obj == "R_foot_CTL":
loc = obj[:-4] + "Ankle_LOC"
elif obj == "M_upTorso_CTL":
loc = "M_spineTip_LOC"
else:
loc = obj[:-3] + "LOC"
# Grabs the original world space position to calculate the approraite motion points
locPos = cmds.getAttr(loc+".translate")
centerLocPos = cmds.getAttr("M_centerMass_LOC.translate")
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
if obj != "M_upTorso_CTL":
# Queries the position of the controller to draw the curve
# Adds the position of the controller in world space to draw it relative to the control
pos = cmds.xform( obj,q=True,ws=True,t=True )
pos[0] = pos[0] + locPos[0][0]
pos[1] = pos[1] + locPos[0][1]
pos[2] = pos[2] + locPos[0][2]
# convert the tuple (vector) to a string
points.append(pos)
print pos
else:
spineLength = cmds.getAttr('spineCurveInfo.arcLength')
# Queries the position of the controller to draw the curve
# Adds the position of the controller in world space to draw it relative to the control
# adds in the spine length to the y position to take into consideration the offset of the centerMass controller
pos = cmds.xform( obj,q=True,ws=True,t=True )
pos[0] = pos[0] + locPos[0][0]
pos[1] = pos[1] + locPos[0][1]
pos[2] = pos[2] + locPos[0][2]
# convert the tuple (vector) to a string
print "Printing out points"
points.append(pos)
print pos
# Queries the position of the center of mass controller
centerPos = cmds.xform( "M_centerMass_CTL",q=1,os=1,t=1 )
centerPos[0] = centerPos[0] #+ centerLocPos[0][0]
centerPos[1] = centerPos[1] #+ centerLocPos[0][1]
centerPos[2] = centerPos[2] #+ centerLocPos[0][2]
# convert the tuple (vector) to a string
print "Printing out center Points"
centerPoints.append(centerPos)
print centerPos
# Combine the two point positions to find the relative position
combinedPos = []
combinedPos1 = pos[0] + centerPos[0]
combinedPos.append(combinedPos1)
combinedPos2 = pos[1] + centerPos[1]
combinedPos.append(combinedPos2)
combinedPos3 = pos[2] + centerPos[2]
combinedPos.append(combinedPos3)
print "Printing out combined Points"
print combinedPos
# Queries the rotation of the center of mass controller
#centerRot = cmds.xform( "M_centerMass_CTL",q=1,ws=1,ro=1 )
#centerRotates.append(centerRot)
#print "Printing out rotations"
#print centerRot
# applies rotation of the center of mass controller to the upper torso controller
# rotation around the Z axis
#tempX = combinedPos[0]*math.cos(math.radians(centerRot[2])) - combinedPos[1]*math.sin(math.radians(centerRot[2]))
#tempY = combinedPos[0]*math.sin(math.radians(centerRot[2])) + combinedPos[1]*math.cos(math.radians(centerRot[2]))
# rotation around the Y axis
#tempX2 = tempX*math.cos(math.radians(centerRot[1])) + combinedPos[2]*math.sin(math.radians(centerRot[1]))
#tempZ = combinedPos[2]*math.cos(math.radians(centerRot[1])) - tempX*math.sin(math.radians(centerRot[1]))
# rotation around the X axis
#tempY2 = tempY*math.cos(math.radians(centerRot[0])) - tempZ*math.sin(math.radians(centerRot[0]))
#tempZ2 = tempY*math.sin(math.radians(centerRot[0])) + tempZ*math.cos(math.radians(centerRot[0]))
#combinedPos[0] = tempX2
#combinedPos[1] = tempY2
#combinedPos[2] = tempZ2
#print "Printing out rotated Points"
combinedPoints.append(combinedPos)
print combinedPos
# if the obj is the upper torso controller we need to take into consideration the center of mass controller
# Creates the motion curve with the required cvs
if obj == "M_upTorso_CTL":
cur = cmds.curve(d=2, ws=True, p=combinedPoints, n=obj[:-3]+'Path')
cmds.setAttr(cur + '.overrideEnabled', 1)
cmds.setAttr(cur + '.overrideColor', color)
print cur
cmds.move(points[0][0], points[0][1], points[0][2], cur+".scalePivot", cur+".rotatePivot", absolute=True)
else:
cur = cmds.curve(d=2, ws=True, p=points, n=obj[:-3]+'Path')
cmds.setAttr(cur + '.overrideEnabled', 1)
cmds.setAttr(cur + '.overrideColor', color)
print cur
cmds.move(points[0][0], points[0][1], points[0][2], cur+".scalePivot", cur+".rotatePivot", absolute=True)
# command that runs through each cv of the curve and returns their position within a list.
cvs = cmds.getAttr( obj[:-3]+'Path.cv[*]' )
print cvs
global initCVS
initCVS = cvs
# Create a locator for the motion path that the controller will now follow
locate = cmds.spaceLocator( n=obj[:-3]+"Path_LOC" )
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
# Moves the locator to match the position of the controller
cmds.move( cvs[step][0], cvs[step][1], cvs[step][2], locate)
# Keyframes the locator
cmds.setKeyframe( locate )
# Position obj at the location of locate.
cmds.pointConstraint( locate, obj, n=obj[:-3]+"LOC1_PNT" )
cmds.setAttr( loc+'.visibility', 0)
# keys the weight of the point constraint to 0 before and after time frame (set to 1 during time frame)
#Before startFrame
cmds.currentTime( startFrame - 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After startframe
cmds.currentTime( startFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#Before endframe
cmds.currentTime( endFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After endframe
cmds.currentTime( endFrame + 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
cmds.select(obj)
代码的问题是我冻结了我的控制器上的转换,将枢轴设置为世界 space 中的 (0,0,0)。解决此问题的最佳方法是创建一个临时定位器并让它跟随控制器。使用临时定位器的位置来创建控制器的运动路径。创建后删除临时定位器。
新代码
#
# This function creates an animation curve within the scene that follows the path of motion
# of the selected controller. It requires keyframe information in order to genereate the curve
# and uses the range of frames given by the user.
#
def createAnimCurve( bodyField, startField, endField, firstColor ):
# Takes the value of the text field to select the controller
obj = cmds.textField(bodyField, query=True, text=True)
print obj
# Takes in the string input of the paramter values and turns them into integer values
startFrame = cmds.intField(startField, query=True, value=True)
print startFrame
endFrame = cmds.intField(endField, query=True, value=True)
print endFrame
color = cmds.colorIndexSliderGrp( firstColor, query=True, value=True ) - 1
print color
if obj == "":
cmds.warning( "WARNING: Need to Select Body Part from Diagram" )
return
if cmds.objExists(obj[:-3]+'Path'):
# Creates a warning pop up that double checks if the user wants to remove the curve
delRes = cmds.confirmDialog( title='Delete Path Warning', message='Recreation will delete current path. Are you sure?', button=['Yes','No'], defaultButton='Yes', cancelButton='No', dismissString='No' )
# If yes then the curve is deleted
if delRes == 'Yes':
cmds.delete(obj[:-3]+'Path')
cmds.delete(obj[:-3]+'Path_LOC')
else:
return
# Sorts through the list of keyframes of the selected obj from the selected time line
global keyframes
keyframes = sorted(list(set(cmds.keyframe(obj, q=True, time=(startFrame,endFrame), timeChange=True))))
# Creates the arrays for the required point positions
points = []
# Creates a temporary locator to find the world space values of the controller
cmds.spaceLocator( n="tempLoc" )
cmds.parentConstraint( obj, 'tempLoc', n='temp_PRT_CST' )
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
# Queries the position of the controller to draw the curve
# Adds the position of the controller in world space to draw it relative to the control
pos = cmds.xform( "tempLoc",q=True,ws=True,t=True )
pos[0] = pos[0]
pos[1] = pos[1]
pos[2] = pos[2]
# convert the tuple (vector) to a string
points.append(pos)
print pos
print "Creating the basic motion curve"
cur = cmds.curve(d=2, ws=True, p=points, n=obj[:-3]+'Path')
cmds.setAttr(cur + '.overrideEnabled', 1)
cmds.setAttr(cur + '.overrideColor', color)
print cur
cmds.move(points[0][0], points[0][1], points[0][2], cur+".scalePivot", cur+".rotatePivot", absolute=True)
# command that runs through each cv of the curve and returns their position within a list.
cvs = cmds.getAttr( obj[:-3]+'Path.cv[*]' )
print cvs
# Deletes the temp locator
cmds.select("temp_PRT_CST")
cmds.delete()
cmds.select("tempLoc")
cmds.delete()
global initCVS
initCVS = cvs
# Create a locator for the motion path that the controller will now follow
locate = cmds.spaceLocator( n=obj[:-3]+"Path_LOC" )
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
# Moves the locator to match the position of the controller
cmds.move( cvs[step][0], cvs[step][1], cvs[step][2], locate)
# Keyframes the locator
cmds.setKeyframe( locate )
# Position obj at the location of locate.
cmds.pointConstraint( locate, obj, n=obj[:-3]+"LOC1_PNT" )
# keys the weight of the point constraint to 0 before and after time frame (set to 1 during time frame)
#Before startFrame
cmds.currentTime( startFrame - 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After startframe
cmds.currentTime( startFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#Before endframe
cmds.currentTime( endFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After endframe
cmds.currentTime( endFrame + 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
cmds.select(obj)
这是生成的运动路径的样子
正确的弧线应该是这样的
这是基于新代码的新曲线。它似乎沿着运动路径跟随,但它被压缩了。
如果您只是想获得某物的世界 space 位置,您可以使用:
position = cmds.xform(item, q=True, ws=True, t=True)
然后根据需要使用该位置数据 - 无论任何 parent 如何旋转它都应该工作... xform 命令可用于设置世界中事物的位置 space 还有:
cmds.xform(item, ws=True, t=position)
我不确定这是否真的回答了您的问题 - 有点不清楚您要在代码中实现什么;我不能完全理解正在转变的定位器和点约束的原因 on/off。您要创建可编辑的运动轨迹吗?
如果是,您是否尝试过使用 Maya 的内置 editable motion trail 工具?
如果你出于某种原因想自己制作,我想你可以遵循“两步”方法,首先创建一条曲线,其中每个 cv 位于世界 space 位置通过你指定的start/end时间来控制。然后编辑曲线 cv 位置以清理圆弧和 运行 查询每个 cv 的世界 space 位置的单独函数,然后将它们应用于控件并在适当的时间设置关键帧。由于您在世界 space 个位置上进行所有这些操作,因此您无需担心任何 parent positions/rotations(幸运的是,这应该使代码相对简单)。
我刚刚想到的另一个想法是将临时定位器作为控件的父级(位于控件的枢轴处)。然后,您可以使用定位器中的 worldPosition
xyz 属性值来绘制曲线点。拥有曲线后可以删除定位器。
通过将定位器定位在控件的枢轴上以绘制曲线,它应该可以让您轻松完成约束任务(至少在理论上是这样)。由于定位器已经具有 "easy to query" 世界 space 位置值,因此数学密集度也较低。
当然,它不如进行所有数学计算那么酷,但如果它有效...
我正在创建代码以根据控制器在 Maya 中的关键帧位置创建控制器的运动路径。在尝试使用此代码创建父级控制器的运动路径时,我遇到了 运行 问题。如果我旋转和平移父对象,生成的运动路径不会反映实际的运动路径。相反,它会创建运动路径,就好像它不受父级影响一样。我环顾四周,找到了使用矩阵变换将旋转应用到当前位置的信息,但它似乎旋转得太多了。我已经包含了创建运动路径的功能,它有点长,但在处理上躯干控制器时,不起作用的部分在 else 语句中。
旧代码
#
# This function creates an animation curve within the scene that follows the path of motion
# of the selected controller. It requires keyframe information in order to genereate the curve
# and uses the range of frames given by the user.
#
def createAnimCurve( bodyField, startField, endField, firstColor ):
# Takes the value of the text field to select the controller
obj = cmds.textField(bodyField, query=True, text=True)
print obj
# Takes in the string input of the paramter values and turns them into integer values
startFrame = cmds.intField(startField, query=True, value=True)
print startFrame
endFrame = cmds.intField(endField, query=True, value=True)
print endFrame
color = cmds.colorIndexSliderGrp( firstColor, query=True, value=True ) - 1
print color
if obj == "":
cmds.warning( "WARNING: Need to Select Body Part from Diagram" )
return
if cmds.objExists(obj[:-3]+'Path'):
# Creates a warning pop up that double checks if the user wants to remove the curve
delRes = cmds.confirmDialog( title='Delete Path Warning', message='Recreation will delete current path. Are you sure?', button=['Yes','No'], defaultButton='Yes', cancelButton='No', dismissString='No' )
# If yes then the curve is deleted
if delRes == 'Yes':
#cmds.delete(obj[:-3]+'ScalePath')
#cmds.delete(obj[:-3]+'ScalePath_LOC')
cmds.delete(obj[:-3]+'Path')
cmds.delete(obj[:-3]+'Path_LOC')
else:
return
# Sorts through the list of keyframes of the selected obj from the selected time line
global keyframes
keyframes = sorted(list(set(cmds.keyframe(obj, q=True, time=(startFrame,endFrame), timeChange=True))))
# Creates the arrays for the required point positions
points = []
centerPoints = []
centerRotates = []
combinedPoints = []
# Special cases for controllers that are named differently than their joints
if obj == "L_foot_CTL" or obj == "R_foot_CTL":
loc = obj[:-4] + "Ankle_LOC"
elif obj == "M_upTorso_CTL":
loc = "M_spineTip_LOC"
else:
loc = obj[:-3] + "LOC"
# Grabs the original world space position to calculate the approraite motion points
locPos = cmds.getAttr(loc+".translate")
centerLocPos = cmds.getAttr("M_centerMass_LOC.translate")
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
if obj != "M_upTorso_CTL":
# Queries the position of the controller to draw the curve
# Adds the position of the controller in world space to draw it relative to the control
pos = cmds.xform( obj,q=True,ws=True,t=True )
pos[0] = pos[0] + locPos[0][0]
pos[1] = pos[1] + locPos[0][1]
pos[2] = pos[2] + locPos[0][2]
# convert the tuple (vector) to a string
points.append(pos)
print pos
else:
spineLength = cmds.getAttr('spineCurveInfo.arcLength')
# Queries the position of the controller to draw the curve
# Adds the position of the controller in world space to draw it relative to the control
# adds in the spine length to the y position to take into consideration the offset of the centerMass controller
pos = cmds.xform( obj,q=True,ws=True,t=True )
pos[0] = pos[0] + locPos[0][0]
pos[1] = pos[1] + locPos[0][1]
pos[2] = pos[2] + locPos[0][2]
# convert the tuple (vector) to a string
print "Printing out points"
points.append(pos)
print pos
# Queries the position of the center of mass controller
centerPos = cmds.xform( "M_centerMass_CTL",q=1,os=1,t=1 )
centerPos[0] = centerPos[0] #+ centerLocPos[0][0]
centerPos[1] = centerPos[1] #+ centerLocPos[0][1]
centerPos[2] = centerPos[2] #+ centerLocPos[0][2]
# convert the tuple (vector) to a string
print "Printing out center Points"
centerPoints.append(centerPos)
print centerPos
# Combine the two point positions to find the relative position
combinedPos = []
combinedPos1 = pos[0] + centerPos[0]
combinedPos.append(combinedPos1)
combinedPos2 = pos[1] + centerPos[1]
combinedPos.append(combinedPos2)
combinedPos3 = pos[2] + centerPos[2]
combinedPos.append(combinedPos3)
print "Printing out combined Points"
print combinedPos
# Queries the rotation of the center of mass controller
#centerRot = cmds.xform( "M_centerMass_CTL",q=1,ws=1,ro=1 )
#centerRotates.append(centerRot)
#print "Printing out rotations"
#print centerRot
# applies rotation of the center of mass controller to the upper torso controller
# rotation around the Z axis
#tempX = combinedPos[0]*math.cos(math.radians(centerRot[2])) - combinedPos[1]*math.sin(math.radians(centerRot[2]))
#tempY = combinedPos[0]*math.sin(math.radians(centerRot[2])) + combinedPos[1]*math.cos(math.radians(centerRot[2]))
# rotation around the Y axis
#tempX2 = tempX*math.cos(math.radians(centerRot[1])) + combinedPos[2]*math.sin(math.radians(centerRot[1]))
#tempZ = combinedPos[2]*math.cos(math.radians(centerRot[1])) - tempX*math.sin(math.radians(centerRot[1]))
# rotation around the X axis
#tempY2 = tempY*math.cos(math.radians(centerRot[0])) - tempZ*math.sin(math.radians(centerRot[0]))
#tempZ2 = tempY*math.sin(math.radians(centerRot[0])) + tempZ*math.cos(math.radians(centerRot[0]))
#combinedPos[0] = tempX2
#combinedPos[1] = tempY2
#combinedPos[2] = tempZ2
#print "Printing out rotated Points"
combinedPoints.append(combinedPos)
print combinedPos
# if the obj is the upper torso controller we need to take into consideration the center of mass controller
# Creates the motion curve with the required cvs
if obj == "M_upTorso_CTL":
cur = cmds.curve(d=2, ws=True, p=combinedPoints, n=obj[:-3]+'Path')
cmds.setAttr(cur + '.overrideEnabled', 1)
cmds.setAttr(cur + '.overrideColor', color)
print cur
cmds.move(points[0][0], points[0][1], points[0][2], cur+".scalePivot", cur+".rotatePivot", absolute=True)
else:
cur = cmds.curve(d=2, ws=True, p=points, n=obj[:-3]+'Path')
cmds.setAttr(cur + '.overrideEnabled', 1)
cmds.setAttr(cur + '.overrideColor', color)
print cur
cmds.move(points[0][0], points[0][1], points[0][2], cur+".scalePivot", cur+".rotatePivot", absolute=True)
# command that runs through each cv of the curve and returns their position within a list.
cvs = cmds.getAttr( obj[:-3]+'Path.cv[*]' )
print cvs
global initCVS
initCVS = cvs
# Create a locator for the motion path that the controller will now follow
locate = cmds.spaceLocator( n=obj[:-3]+"Path_LOC" )
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
# Moves the locator to match the position of the controller
cmds.move( cvs[step][0], cvs[step][1], cvs[step][2], locate)
# Keyframes the locator
cmds.setKeyframe( locate )
# Position obj at the location of locate.
cmds.pointConstraint( locate, obj, n=obj[:-3]+"LOC1_PNT" )
cmds.setAttr( loc+'.visibility', 0)
# keys the weight of the point constraint to 0 before and after time frame (set to 1 during time frame)
#Before startFrame
cmds.currentTime( startFrame - 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After startframe
cmds.currentTime( startFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#Before endframe
cmds.currentTime( endFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After endframe
cmds.currentTime( endFrame + 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
cmds.select(obj)
代码的问题是我冻结了我的控制器上的转换,将枢轴设置为世界 space 中的 (0,0,0)。解决此问题的最佳方法是创建一个临时定位器并让它跟随控制器。使用临时定位器的位置来创建控制器的运动路径。创建后删除临时定位器。
新代码
#
# This function creates an animation curve within the scene that follows the path of motion
# of the selected controller. It requires keyframe information in order to genereate the curve
# and uses the range of frames given by the user.
#
def createAnimCurve( bodyField, startField, endField, firstColor ):
# Takes the value of the text field to select the controller
obj = cmds.textField(bodyField, query=True, text=True)
print obj
# Takes in the string input of the paramter values and turns them into integer values
startFrame = cmds.intField(startField, query=True, value=True)
print startFrame
endFrame = cmds.intField(endField, query=True, value=True)
print endFrame
color = cmds.colorIndexSliderGrp( firstColor, query=True, value=True ) - 1
print color
if obj == "":
cmds.warning( "WARNING: Need to Select Body Part from Diagram" )
return
if cmds.objExists(obj[:-3]+'Path'):
# Creates a warning pop up that double checks if the user wants to remove the curve
delRes = cmds.confirmDialog( title='Delete Path Warning', message='Recreation will delete current path. Are you sure?', button=['Yes','No'], defaultButton='Yes', cancelButton='No', dismissString='No' )
# If yes then the curve is deleted
if delRes == 'Yes':
cmds.delete(obj[:-3]+'Path')
cmds.delete(obj[:-3]+'Path_LOC')
else:
return
# Sorts through the list of keyframes of the selected obj from the selected time line
global keyframes
keyframes = sorted(list(set(cmds.keyframe(obj, q=True, time=(startFrame,endFrame), timeChange=True))))
# Creates the arrays for the required point positions
points = []
# Creates a temporary locator to find the world space values of the controller
cmds.spaceLocator( n="tempLoc" )
cmds.parentConstraint( obj, 'tempLoc', n='temp_PRT_CST' )
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
# Queries the position of the controller to draw the curve
# Adds the position of the controller in world space to draw it relative to the control
pos = cmds.xform( "tempLoc",q=True,ws=True,t=True )
pos[0] = pos[0]
pos[1] = pos[1]
pos[2] = pos[2]
# convert the tuple (vector) to a string
points.append(pos)
print pos
print "Creating the basic motion curve"
cur = cmds.curve(d=2, ws=True, p=points, n=obj[:-3]+'Path')
cmds.setAttr(cur + '.overrideEnabled', 1)
cmds.setAttr(cur + '.overrideColor', color)
print cur
cmds.move(points[0][0], points[0][1], points[0][2], cur+".scalePivot", cur+".rotatePivot", absolute=True)
# command that runs through each cv of the curve and returns their position within a list.
cvs = cmds.getAttr( obj[:-3]+'Path.cv[*]' )
print cvs
# Deletes the temp locator
cmds.select("temp_PRT_CST")
cmds.delete()
cmds.select("tempLoc")
cmds.delete()
global initCVS
initCVS = cvs
# Create a locator for the motion path that the controller will now follow
locate = cmds.spaceLocator( n=obj[:-3]+"Path_LOC" )
#for step in range( startFrame, endFrame+2, int(curveCVstep)):
for step in range(len(keyframes)):
# Moves throughout the specified timeline to find point results
cmds.currentTime( keyframes[step] )
# Moves the locator to match the position of the controller
cmds.move( cvs[step][0], cvs[step][1], cvs[step][2], locate)
# Keyframes the locator
cmds.setKeyframe( locate )
# Position obj at the location of locate.
cmds.pointConstraint( locate, obj, n=obj[:-3]+"LOC1_PNT" )
# keys the weight of the point constraint to 0 before and after time frame (set to 1 during time frame)
#Before startFrame
cmds.currentTime( startFrame - 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After startframe
cmds.currentTime( startFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#Before endframe
cmds.currentTime( endFrame )
cmds.setAttr(obj+'.blendPoint1', 1 )
cmds.setKeyframe(obj+'.blendPoint1' )
#After endframe
cmds.currentTime( endFrame + 1 )
cmds.setAttr(obj+'.blendPoint1', 0 )
cmds.setKeyframe(obj+'.blendPoint1' )
cmds.select(obj)
这是生成的运动路径的样子
正确的弧线应该是这样的
这是基于新代码的新曲线。它似乎沿着运动路径跟随,但它被压缩了。
如果您只是想获得某物的世界 space 位置,您可以使用:
position = cmds.xform(item, q=True, ws=True, t=True)
然后根据需要使用该位置数据 - 无论任何 parent 如何旋转它都应该工作... xform 命令可用于设置世界中事物的位置 space 还有:
cmds.xform(item, ws=True, t=position)
我不确定这是否真的回答了您的问题 - 有点不清楚您要在代码中实现什么;我不能完全理解正在转变的定位器和点约束的原因 on/off。您要创建可编辑的运动轨迹吗?
如果是,您是否尝试过使用 Maya 的内置 editable motion trail 工具?
如果你出于某种原因想自己制作,我想你可以遵循“两步”方法,首先创建一条曲线,其中每个 cv 位于世界 space 位置通过你指定的start/end时间来控制。然后编辑曲线 cv 位置以清理圆弧和 运行 查询每个 cv 的世界 space 位置的单独函数,然后将它们应用于控件并在适当的时间设置关键帧。由于您在世界 space 个位置上进行所有这些操作,因此您无需担心任何 parent positions/rotations(幸运的是,这应该使代码相对简单)。
我刚刚想到的另一个想法是将临时定位器作为控件的父级(位于控件的枢轴处)。然后,您可以使用定位器中的 worldPosition
xyz 属性值来绘制曲线点。拥有曲线后可以删除定位器。
通过将定位器定位在控件的枢轴上以绘制曲线,它应该可以让您轻松完成约束任务(至少在理论上是这样)。由于定位器已经具有 "easy to query" 世界 space 位置值,因此数学密集度也较低。
当然,它不如进行所有数学计算那么酷,但如果它有效...