Skip to content

Instantly share code, notes, and snippets.

@FryPotato893
Last active November 8, 2017 09:22
Show Gist options
  • Save FryPotato893/f30727bafd7bcf16445dab3b86c4e684 to your computer and use it in GitHub Desktop.
Save FryPotato893/f30727bafd7bcf16445dab3b86c4e684 to your computer and use it in GitHub Desktop.
【Maya Python API】選択したインスタンサーノードをメッシュにベイク。
u"""
パーティクルインスタンスをオブジェクトにベイク
インスタンサーノードを選択して実行
"""
import math
import maya.mel as mel
import maya.cmds as cmds
import maya.api.OpenMaya as om2
import maya.OpenMaya as om
import maya.OpenMayaFX as omFX
class ParticleAttribute(object):
u"""
概要:
選択したインスタンサーノードからパーティクルのアトリビュート情報を取得
"""
def __init__(self):
self.idArray = om.MIntArray()
self.sel = om.MSelectionList()
self.dag = om.MDagPath()
self.vector = om.MVectorArray()
om.MGlobal.getActiveSelectionList(self.sel)
#何も選択してなかった場合、エラー
if self.sel.isEmpty() == True:
cmds.error(u"select instancer node.")
self.sel.getDagPath(0,self.dag)
#選択したノードがインスタンサーノードじゃない場合、エラー
if self.dag.apiType() != om.MFn.kInstancer:
cmds.error(u"select instancer node.")
#MFnにインスタンサー情報を渡す。
self.instance = omFX.MFnInstancer(self.dag)
#MFnにパーティクル情報を渡す。
self.sel.add(cmds.listConnections(self.instance.fullPathName()+".inputPoints")[0])
self.sel.getDagPath(1,self.dag)
self.particle = omFX.MFnParticleSystem(self.dag)
def getCount(self):
u"""
戻り値:
int : パーティクルの数
"""
return self.instance.particleCount()
def getIDs(self):
u"""
戻り値:
int : パーティクルID
"""
self.idArray = om.MIntArray()
self.particle.particleIds(self.idArray)
return self.idArray
def getInstanceObject(self):
u"""
戻り値:
string[] : インスタンスオブジェクトをリストで取得
"""
return cmds.instancer(self.instance.fullPathName(),q=True,object=True)
def getInstancerAttrName(self,name):
u"""
引数:
インスタンスアトリビュートで使用されるアトリビュート名を指定
【一般オプション】
position : 位置
scale : スケール
shear : シア
visibility : 可視性
objectIndex : オブジェクトインデックス
【回転オプション】
rotationType : 回転タイプ
rotation : 回転
aimDirection : エイム方向
aimPosition : エイム位置
aimAxis : エイム軸
aimUpAxis : エイムアップ軸
aimWorldUp : エイムワールドアップ
戻り値:
string[] : インスタンスオブジェクトのオブジェクトインデックスで使用しているアトリビュート名をリストで取得
"""
#何故かmaya.cmdsではアトリビュート名が取得できなかったので、仕方なくmelで取得
return mel.eval("particleInstancer -name %s -q -%s %s;"
%(self.instance.fullPathName().split("|")[1], name, self.particle.fullPathName().split("|")[1]))
def getObjectIndex(self):
u"""
戻り値:
double[] : パーティクル個々のオブジェクトインデックス値の配列をリストで取得
"""
if self.getInstancerAttrName("objectIndex") == None:
return None
else:
if self.getCount() == 0:
return None
else:
self.double = om.MDoubleArray()
self.particle.getPerParticleAttribute(self.getInstancerAttrName("objectIndex"),self.double)
return self.double
def getVisibility(self):
u"""
戻り値:
double[] : パーティクル個々の可視性の配列をリストで取得
"""
if self.getInstancerAttrName("visibility") == None:
return None
else:
if self.getCount() == 0:
return None
else:
self.double = om.MDoubleArray()
self.particle.getPerParticleAttribute(self.getInstancerAttrName("visibility"),self.double)
#1以上の値はすべて1に統一
self.list = []
for vis in self.double:
if vis > 1:
self.list.append(1.0)
else:
self.list.append(vis)
return self.list
def getParticleAttr(self,attrName):
u"""
戻り値:
double[] : パーティクル個々のオブジェクトインデックス値の配列をリストで取得
"""
if self.getInstancerAttrName(attrName) == None:
return None
else:
self.double = om.MDoubleArray()
self.particle.getPerParticleAttribute(attrName,self.double)
return self.double
class Matrix(ParticleAttribute):
u"""
ParticleAttributeクラスを継承
"""
def __init__(self):
super(Matrix,self).__init__()
def getMatrix(self,particleID):
self.dagArray = om.MDagPathArray()
self.mat = om.MMatrix()
#インスタンサーからパーティクルの情報を取得。
self.instance.instancesForParticle(particleID,self.dagArray,self.mat)
#api2.0のmatrixへ変換。
self.matrix = om2.MTransformationMatrix(om2.MMatrix(self.mat))
def getPosition(self):
u"""
戻り値:
float() : パーティクルの位置情報をタプルで取得
"""
return self.matrix.translation(om2.MSpace.kWorld)
def getRotation(self):
u"""
戻り値:
float() : パーティクルの回転情報をタプルで取得
"""
return (math.degrees(self.matrix.rotation()[0]),math.degrees(self.matrix.rotation()[1]),math.degrees(self.matrix.rotation()[2]))
def getScale(self):
u"""
戻り値:
float() : パーティクルのスケール情報をタプルで取得
"""
return self.matrix.scale(om2.MSpace.kWorld)
class Instance(Matrix):
u"""
ParticleAttributeクラスを継承
"""
def __init__(self):
super(Instance,self).__init__()
def copyInstanceObj(self,particleID,instance):
u"""
戻り値:
string[] : コピーしたオブジェクト名をリストで取得
"""
#個々のパーティクルのオブジェクトインデックス値、マトリックスを取得
if self.getObjectIndex() == None:
self.ids = 0
else:
self.ids = int(self.getObjectIndex()[particleID])
#オブジェクトインデックス値がインスタンスオブジェクトの数を超えていた場合、最大値を超えないように均一化
if len(self.getInstanceObject())-1 < self.ids:
self.ids = int(len(self.getInstanceObject())-1)
if instance == False:
self.obj = cmds.duplicate(self.getInstanceObject()[self.ids],n=self.getInstanceObject()[self.ids]+"_"+unicode(particleID))
elif instance == True:
self.obj = cmds.instance(self.getInstanceObject()[self.ids],n=self.getInstanceObject()[self.ids]+"_"+unicode(particleID))
return self.obj[0]
def bakeInstancer(instance=True,currentFrame=False):
u"""
引数:
instance : True の場合 インスタンスコピー
False の場合 デュプリケートコピー
currentFrame : True の場合 現在のフレームだけベイク
False の場合 タイムスライダ分ベイク
戻り値:
string[groupNode[copyNode]] :
groupNode : 作成したグループオブジェクト名
copyNode : コピーしたオブジェクト名
"""
cmds.undoInfo(openChunk=True)
#パーティクル単位の情報を格納する変数を宣言。
allObject = [] #ベイク後のオブジェクト
particlePosition = {} #パーティクルの位置情報
particleRotate = {} #パーティクルの回転情報
particleScale = {} #パーティクルのスケール情報
particleVisibility = {} #パーティクルの可視性情報
particleID = {} #パーティクルID
copyObj = {} #フレーム単位で増えるパーティクルのオブジェクト情報
deleteObj = {} #フレーム単位で消えるパーティクルのオブジェクト情報
#クラスを宣言
mat = Matrix()
sets = Instance()
#現在のフレーム or タイムスライダ
if currentFrame == True:
frame = 1
elif currentFrame == False:
startF = cmds.playbackOptions(q=True,minTime=True)
endF = cmds.playbackOptions(q=True,maxTime=True)
frame = endF-startF+1
#オートキーがONの場合、一旦OFFに
autoKey = cmds.autoKeyframe(q=True,state=True)
if autoKey == True:
cmds.autoKeyframe(state=False)
#タイムスライダに表示されているフレーム数でループ。
for frame in range(int(frame)):
"タイムスライダの開始フレームを求める"
if currentFrame == True:
frames = cmds.currentTime(q=True)
elif currentFrame == False:
frames = int(frame+startF)
cmds.currentTime(frames)
"パーティクルの情報を取得"
id = {}
for count in range(mat.getCount()):
mat.getMatrix(count)
particlePosition[mat.getIDs()[count]] = mat.getPosition()
particleRotate[mat.getIDs()[count]] = mat.getRotation()
particleScale[mat.getIDs()[count]] = mat.getScale()
if mat.getVisibility() == None:particleVisibility[mat.getIDs()[count]] = 1.0
else:particleVisibility[mat.getIDs()[count]] = mat.getVisibility()[count]
id[mat.getIDs()[count]] = count
particleID[frames] = id
"前フレームと比較して増えたパーティクルの数分、オブジェクトをコピー"
#最初のフレームでパーティクルがゼロの場合
if frame == 0 and mat.getCount() == 0:
continue
#最初のフレームでパーティクルが存在している場合
elif frame == 0 and mat.getCount() != 0:
newParID = particleID[frames]
delPatID = []
else:
#増えたパーティクルのID番号を取得
newParID = list(set(particleID[frames]) - set(particleID[frames-1]))
#消えたパーティクルのID番号を取得
delPatID = list(set(particleID[frames-1]) - set(particleID[frames]))
#発生したパーティクル分、オブジェクトをコピー
if newParID != []:
for newpts in newParID:
#インスタンスオブジェクトをコピー
obj = sets.copyInstanceObj(particleID[frames][newpts],instance)
#コピー情報を格納
deleteObj[newpts] = obj
copyObj[newpts] = obj
allObject.append(obj)
#パーティクルが消滅した場合、リストから削除
if delPatID != []:
for delpts in delPatID:
copyObj.pop(delpts)
"現在のフレームで存在しているオブジェクトすべてに値をセット"
for objs in particleID[frames]:
cmds.setAttr(copyObj[objs]+".translate",*particlePosition[objs])
cmds.setAttr(copyObj[objs]+".rotate",*particleRotate[objs])
cmds.setAttr(copyObj[objs]+".scale",*particleScale[objs])
cmds.setAttr(copyObj[objs]+".visibility",particleVisibility[objs])
cmds.setKeyframe(copyObj[objs],time=frames)
"パーティクルの出現、消滅のタイミングを可視性に書き込むために再ループ"
for nodes in allObject:
animCurve = cmds.listConnections(nodes+".visibility")
firstF = cmds.findKeyframe(animCurve,which="first")-1
lastF = cmds.findKeyframe(animCurve,which="last")+1
cmds.setKeyframe(nodes,at="v",v=0,time=firstF,s=False)
cmds.setKeyframe(nodes,at="v",v=0,time=lastF,s=False)
#オートキーがONだった場合、ONに戻す
if autoKey == True:
cmds.autoKeyframe(state=True)
#コピーしたインスタンスオブジェクトをグループでまとめる
group = cmds.group(allObject,n=mat.instance.fullPathName()+"_instanceBakeObject_Grp")
cmds.undoInfo(closeChunk=True)
return [group,allObject]
bakeInstancer(instance=True,currentFrame=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment