さて pythonでツールを作っていきます。
リグを組むために。
骨打ち用ツール
欲しい機能としては
- setJointOrient
- createNode
- mirrorJoints
- mirrorOrients
- mirrorPositios
くらいかしら。
もしかしたらmayaの標準機能で既にあるのかもしれませんが、まぁ作ろう。
setJointOrient
追加で欲しい機能としては、
- primary Axis にも +/-欲しい
- secondary Axis にも +/- 欲しい
- secondary Axis World Orientation については、aimConstraintの様に object/ parent が欲しい
処理の大雑把な流れとしては
- 子ノードの現在の位置・向きを取得
- primary/secondaryの変化先をベクトルとしてそれぞれ取得
- vectorの投影によってdistSecondaryAxisVectorからdistPrimaryAxisVectorに直交するvectorを取得
- 外積によって残りの軸のvectorを取得
- 各軸のvectorから変化後のmatrixを作成
- matrixをセット
- 子ノードの現在の位置・向きを復元
追記:外積2回で各軸ベクトル求めた方がシンプルな気がします
import maya.cmds as cmds
import maya.api.OpenMaya as om
import maya.api.OpenMayaAnim as omAnm
def getPosition(target):
return cmds.xform(target , q =True , ws = True, rotatePivot =True)[0:3]
def stringToVector(axis):
if axis == "x":
return om.MVector.kXaxisVector
elif axis == "y":
return om.MVector.kYaxisVector
elif axis == "z":
return om.MVector.kZaxisVector
elif axis == "-x":
return om.MVector.kXnegAxisVector
elif axis == "-y":
return om.MVector.kYnegAxisVector
elif axis == "-z":
return om.MVector.kZnegAxisVector
def axisToVector(axis,target):
pointMatrix = om.MMatrix(cmds.getAttr(target + ".worldMatrix[0]"))
axisVector = om.MTransformationMatrix(pointMatrix).setTranslation(stringToVector(axis),om.MSpace.kObject).translation(om.MSpace.kWorld)
return axisVector.normal()
def getProjctionVector(vectorA,vectorB):
vectorA = om.MVector(vectorA)
vectorB = om.MVector(vectorB)
vectorB = vectorB.normal()
dotProduct = vectorA * vectorB
shadowVector = vectorB * dotProduct
return shadowVector
##----------------------------------------------------------------------------------
def primaryDistVector(target,primaryAimType,primaryAimTarget):
targetPosition = om.MVector(getPosition(target))
if primaryAimType == "next":
chNodes = cmds.listRelatives(target,type="transform",fullPath =True)
panretNodes = cmds.listRelatives(target,type="transform",p=True,fullPath =True)
if chNodes != None:
aimPosition = om.MVector(getPosition(chNodes[0]))
elif chNodes == None and panretNodes != None:
aimPosition = om.MVector(getPosition(panretNodes[0])) * -1.0
elif primaryAimType == "object":
aimPosition = om.MVector(getPosition(primaryAimTarget))
distAxisVector = aimPosition - targetPosition
distAxisVector = distAxisVector.normal()
return distAxisVector
def secondaryDistVector(target,secondaryAimType,secondaryAimTarget):
if secondaryAimType == "world":
distAxisVector = stringToVector(secondaryAimTarget)
elif secondaryAimType == "object":
targetPosition = om.MVector(getPosition(target))
aimPosition = om.MVector(getPosition(secondaryAimTarget))
distAxisVector = aimPosition - targetPosition
distAxisVector = distAxisVector.normal()
elif secondaryAimType == "parent":
parent = cmds.listRelatives(target,p=True,fullPath =True)
distAxisVector = axisToVector(secondaryAimTarget,parent[0])
return distAxisVector
def vectorToMatrix(axisOrder,distPrimaryAxisVector,distSecondaryAxisVector,distSideAxisVector):
axisMatrix = []
distPrimaryAxisVector = list(distPrimaryAxisVector)
distPrimaryAxisVector.append(0.0)
distSecondaryAxisVector = list(distSecondaryAxisVector)
distSecondaryAxisVector.append(0.0)
distSideAxisVector = list(distSideAxisVector)
distSideAxisVector.append(0.0)
if axisOrder == "xy":
axisMatrix.extend(distPrimaryAxisVector)
axisMatrix.extend(distSecondaryAxisVector)
axisMatrix.extend(distSideAxisVector)
elif axisOrder == "xz":
axisMatrix.extend(distPrimaryAxisVector)
axisMatrix.extend(distSideAxisVector)
axisMatrix.extend(distSecondaryAxisVector)
elif axisOrder == "yx":
axisMatrix.extend(distSecondaryAxisVector)
axisMatrix.extend(distPrimaryAxisVector)
axisMatrix.extend(distSideAxisVector)
elif axisOrder == "yz":
axisMatrix.extend(distSideAxisVector)
axisMatrix.extend(distPrimaryAxisVector)
axisMatrix.extend(distSecondaryAxisVector)
elif axisOrder == "zx":
axisMatrix.extend(distSecondaryAxisVector)
axisMatrix.extend(distSideAxisVector)
axisMatrix.extend(distPrimaryAxisVector)
elif axisOrder == "zy":
axisMatrix.extend(distSideAxisVector)
axisMatrix.extend(distSecondaryAxisVector)
axisMatrix.extend(distPrimaryAxisVector)
axisMatrix.extend([0.0,0.0,0.0,1.0])
return axisMatrix
def getChNodeTransform(target):
chNodes = cmds.listRelatives(target,type="transform",fullPath =True) or []
chNodesPosition = {}
for node in chNodes:
position = cmds.xform(node , q =True ,ws =True , t =True)
rotation = cmds.xform(node , q =True ,ws =True , ro =True)
chNodesPosition[node] = {"position":position,"rotation":rotation}
return chNodesPosition
def restoreChNodeTransform(chNodesPosition):
for node in list(chNodesPosition.keys()):
cmds.xform(node ,ws =True , t = chNodesPosition[node]["position"])
cmds.xform(node ,ws =True , ro =chNodesPosition[node]["rotation"])
##----------------------------------------------------------------------------------
def setJointOrient(joint,primaryAxis,secondaryAxis,primaryAimType,secondaryAimType,primaryAimTarget,secondaryAimTarget,primaryAxisReverse,secondaryAxisReverse):
axisOrder = primaryAxis + secondaryAxis
chNodesPosition = getChNodeTransform(joint)
distPrimaryAxisVector = primaryDistVector(joint,primaryAimType,primaryAimTarget)
if primaryAxisReverse:
distPrimaryAxisVector = distPrimaryAxisVector * -1.0
distSecondaryAxisVector = secondaryDistVector(joint,secondaryAimType,secondaryAimTarget)
if secondaryAxisReverse:
distSecondaryAxisVector = distSecondaryAxisVector * -1.0
shadowVector = getProjctionVector(distSecondaryAxisVector,distPrimaryAxisVector)
distSecondaryAxisVector = (distSecondaryAxisVector - shadowVector).normal()
if axisOrder == "zy" or axisOrder == "xz":
distSideAxisVector = distSecondaryAxisVector ^ distPrimaryAxisVector
else:
distSideAxisVector = distPrimaryAxisVector ^ distSecondaryAxisVector
axisMatrix = vectorToMatrix(axisOrder,distPrimaryAxisVector,distSecondaryAxisVector,distSideAxisVector)
setMatrix = om.MTransformationMatrix(om.MMatrix(axisMatrix)).setTranslation(om.MVector(getPosition(joint)),om.MSpace.kWorld).asMatrix()
cmds.xform(joint, matrix = list(setMatrix), ws = True)
cmds.makeIdentity(joint, a =True, r=True, s =True)
restoreChNodeTransform(chNodesPosition)
一部脳筋実装が見えるけれども、動くからまぁヨシ!
ここまでできたらもうリグできたも同然なので、続きは次回。