Maya Script Python スキニングウェイトのインポート、エクスポート

DoraMaya
Mayaでよく使われているスキニングウェイトのインポート、エクスポートのmelです。
確かMayaのバグによって2011から正確に動作しないかと思います。
ウェイトの取得で一工夫する必要があったように思います。
忘れました。

 

で、まとめてちゃちゃっと出力したい。と、いう状態になったので、
一部関数をお借りする形で使っておりました。
そうすると、今度はPythonで組んだらどうなるのだろう?という疑問が頭をもたげたので、作ってみました。
UVや頂点の座標は無視です。頂点番号とウェイトの値、ジョイントの名前が保存出来ればいいや。
と、簡略化し、どれくらい早くなるのか楽しみにしながら作ったら、意外とすぐに出来ました。
で、今回も色々と勉強になりました。なるほど、そうやって取ればメッシュノードとシェイプノードを確実に区別できるのですね。

import maya.cmds as cmds
import maya.mel

def gkn_skin_weight_export():
	oMeshs = cmds.filterExpand(sm=12)
	if oMeshs == None:
		return
	gMainProgressBar = maya.mel.eval( '$tmp = $gMainProgressBar' )
	oCount = len(oMeshs)
	if oCount == 1 :oCount = 2
	cmds.progressBar( gMainProgressBar, edit=True,beginProgress=True, status='Now Export...', maxValue=oCount )
	for oMesh in oMeshs:
		oShapes = cmds.listHistory(oMesh)
		oShape = cmds.ls(oShapes,type="shape")[0]
		oCls = cmds.ls(oShapes,type="skinCluster")
		if oCls == []:
			cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
			return
		oCls = oCls[0]
		oJoints = cmds.skinCluster(oCls,q=1,inf=1)
		oJoints = [ x.rsplit("|",1)[1] if x.find("|") != -1 else x for x in oJoints ]
		for oJoint in oJoints:
			if oJoint not in oJoints:
				cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
				cmds.error("Overlap["+oJoint+"]")
		oVtxs = cmds.ls(oMesh+".vtx[*]",fl=1)
		oFileName = cmds.workspace(q=1,fn=1)+r"/gksw"
		oFileName = r"//".join(oFileName.split("/",1))
		cmds.sysFile(oFileName,md=1)
		oMesh = oMesh.rsplit("|",1)[1] if oMesh.find("|") != -1 else oMesh
		oFile = open(oFileName+"/"+oMesh+r".gkw", "w")
		cmds.progressBar( gMainProgressBar, edit=True, step=1 )
		oJoints.append("\n")
		oJoints = ",".join(oJoints)
		oFile.writelines(oJoints)
		for oVtx in oVtxs:
			oWei = [ "{0:}".format(x) if x >= 0.0 else "0.0" for x in cmds.skinPercent(oCls,oVtx,q= 1,v= 1) ]
			oWei.append("\n")
			oWei = ",".join(oWei)
			oFile.writelines(oWei)
		oFile.close()
	cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
gkn_skin_weight_export()

素材、と言ってもいいくらいのコードです。
使い方は、
1.スキニングされたオブジェクトを選択(複数可)
2.上記のスクリプトをMayaのスクリプトエディタにコピペし、実行。
以上です。
すると、カレントのプロジェクトディレクトリに「gksw」というディレクトリを作成します。
すでにある場合は、作られません。
その中に、「メッシュの名前+.gkw」のファイルが出来ます。
テキストエディタで開けるので、内容を編集してもいいし、ファイル名を変えれば頂点数と使われているジョイント名が同じ場合、
違うメッシュにも適用できます。もっともファイル名の変更はしないほうが良いかと思います。

import maya.cmds as cmds
import maya.mel
import glob

def gkn_skin_weight_import():
	oMeshs = cmds.filterExpand(sm=12)
	if oMeshs == None:
		return
	oCount = len(oMeshs)
	if oCount == 1 :oCount = 2
	oFiles = glob.glob(cmds.workspace(q=1,fn=1)+r"/gksw/"+"*.gkw")
	if oFiles == []:
		return
	gMainProgressBar = maya.mel.eval( '$tmp = $gMainProgressBar' )
	cmds.progressBar( gMainProgressBar, edit=True,beginProgress=True, status='Now Import...', maxValue=oCount )
	oFiles = [x.split("\\")[1].split(".")[0] for x in oFiles]
	for oMesh in oMeshs:
		oMesh2 = oMesh.rsplit("|",1)[1] if oMesh.find("|") != -1 else oMesh
		if oMesh2 in oFiles:
			cmds.progressBar( gMainProgressBar, edit=True, step=1 )
			oShapes = cmds.listHistory(oMesh)
			oShape = cmds.ls(oShapes,type="shape")[0]
			oCls = cmds.ls(oShapes,type="skinCluster")
			if oCls == []:
				cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
				return
			oCls = oCls[0]
			oVtxs = cmds.ls(oMesh+".vtx[*]",fl=1)
			oFileName = cmds.workspace(q=1,fn=1)+r"/gksw"
			oFileName = r"//".join(oFileName.split("/",1))
			oFile = open(oFileName+"/"+oMesh2+r".gkw", "r")
			oLines = oFile.readlines()
			oJoints = [x for x in oLines.pop(0).split()[0].split(",")if x!=""]
			oJnts = cmds.skinCluster(oCls,q=1,inf=1)
			for oJoint in oJoints:
				if oJoint not in [ x.rsplit("|",1)[1] if x.find("|") != -1 else x for x in oJnts ]:
					cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
					cmds.error("Not Find["+oJoint+"]")
			if len(oVtxs) == len(oLines):
				[cmds.skinPercent(oCls,oVtxs[i],nrm= 0,zri= 1,tv= (zip(oJoints,[float(x) for x in oLine.split(",")if x!="\n"]))) for i,oLine in enumerate(oLines)]
#				for i,oLine in enumerate(oLines):
#					oWei = [float(x) for x in oLine.split(",")if x!="\n"]
#					cmds.skinPercent(oCls,oVtxs[i],nrm= 0,tv= (zip(oJoints,oWei)))
			oFile.close()
	cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
gkn_skin_weight_import()

で、こちらがインポートです。
ファイル名とメッシュの名前が同じで、かつ頂点数が同じであれば読み込むことが出来ます。
DoraMayaのように頂点の座標や、UV座標で補正する機能はありません。
Maya2011くらいからでしょうか、ウェイトのコピーが付いたので必要ないかと思います。
ウェイトを設定したモデルをそのままの状態で複製しておき、メッシュの編集を行ったモデルにコピーすれば良いかと思います。
使い方は、
1.スキニングされたメッシュを選択し(こちらも複数可)
2.スクリプトを実行
エクスポートされたデータ(gkwファイル)が存在しすれば実行されます。

 

因みにシーン内に同一の構造体を持つ場合でも使用できます。
で、速度なのですが、書き込みは非常に高速です。
しかし、読み込み、むしろウェイトの適用部分なのでしょうか、とても遅いです。
元のmelよりは早いかと思うのですが、書き込みの早さと比べると、げんなりします。
ウェイトのノーマライズを頂点ごとではなく、クラスタごとにしても代わり映えはしませんでした。
悔しいので、リスト内包表記で書いてみましたが、ほぼ変わりません。
因みにコメントアウトされている部分は、リスト内包表記で書かれているものをベタ書きにしたものです。
コメントアウトされている行の一行上をコメントアウト、もしくは削除し、コメントアウトを解除するとそちらを実行できます。

 

MacやUNIXで動くかは知りません。多分動かないのではないでしょうか?ディレクトリの記述が少し違いますよね、確か。
多分Maya2011以上で使えるのではないでしょうか?2010でも使えるかも知れません。
少なくとも2012、2013では使えます。

 

そのままでも一応使えますが、編集して使いやすいようにしてください。

コメントする

post date*

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トラックバックする

トラックバック用URL:

アニメーションが親切に解説されております

レンダリング、ライティングの基本が分かります

図版が見やすい美術解剖書です