MayaのカーブをJSONで保存してみよう!

こんにちは!Rhinoです。
今年は雪が多くて大変ですね。厳しい寒さが続いていますが、皆さん体調にはくれぶれもお気をつけ下さい。
今日はMayaのカーブをファイルに保存するということをPythonで試してみたいと思います。
保存には扱いやすそうなJSONを使ってみました。

JSONとは

JSON(JavaScript Object Notation)は主にデータ交換で使用されているフォーマットです。
テキストベースのため軽量で、名前にもある通りJavaScript表記をベースとしています。

Mayaのカーブはどのようなデータでできているか

簡単なカーブをPencil Curveを使って描いてみます。
スクリプトエディタを見てみますと次のようなコマンドが表示されました。

curve -d 1 -p -19.82586 0 -7.489585 -p -4.692712 0 -15.172568 -p 21.848501 0 -1.552735 -p 43.500543 0 -13.310026 -k 0 -k 1 -k 2 -k 3 ;

マニュアルで確認してみますと各種アトリビュートは次のような説明がありました。
どうやら、これらをJSONとして出入力できれば実現できそうですね。

degree(d)カーブの次数
point(p)ポイントの x、y、z の位置
knot(k)ノット ベクトルにあるノットの値

各種アトリビュート値を取得する

カーブの詳細をアトリビュートエディタで見てみますと様々なアトリビュートが表示されます。
これらを再現して同じカーブを作るのが目的です。

では、実際アトリビュート値を取得していきたいと思います。
いつものgetAttrを使います。
まずは次数から!

#次数を取得
degs = cmds.getAttr( curve + ".degree" )

次はポイント、所謂コントロールポイントの位置ですね。
さらにノットベクトルを取得したいと思います。
但し、これらはカーブオブジェクトから直接取得するとちょっと問題があります。
特に円(Circle)の場合ですね。
実際、Circleを作成してみますと次ようなコマンドがスクリプトエディタに表示されるはずです。
さっきと随分違いますね。
そもそもコマンド名がcircleとなっています。

circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3 -ut 0 -tol 0.01 -s 8 -ch 1; objectMoveCommand;

作成したカーブから試しにポイントを取得してみます。

cmds.getAttr( 'nurbsCircle1.cv[*]' )
# Result: [(0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0), (0.0, 0.0, 0.0)] # 

すべての値が0(ゼロ)として出力されてしまい、これでは後でカーブを再現する際にすべてのポイントが原点に作成されてしまいます。
そこで一旦curveInfoノードを作成し、そこから必要なアトリビュート値を取得することにしました。

#curveInfoノードを作成
curveInfoNode = cmds.createNode( "curveInfo" )
cmds.connectAttr( curveShapes + ".worldSpace", curveInfoNode + ".inputCurve" )
#コントロールポイントを取得
cvs = cmds.getAttr( curveInfoNode + ".controlPoints[*]" )
#ノットベクトルを取得  
knts = cmds.getAttr( curveInfoNode + ".knots[*]" )
#curveInfoノードを削除
cmds.delete( curveInfoNode )

curveInfoノードはUtilityノードの一種でカーブに関する様々な情報を取得することができます。
Materialエディタなどからも作成できますが、今回はpythonで作成しています。
以前カーブの長さを図る記事でも使用しました。

また、これら以外にもカーブが閉じているかどうかを判定するアトリビュートがありますので、こちらも取得しておきます。

form = cmds.getAttr( curveShapes + ".form")

JSONファイルを出力

必要なアトリビュート値が揃ったらJSONファイルに出力してみたいと思います。
通常の辞書型でもいいのですが、順序が変わってしまうのが不便でしたのでOrderedDictを使用しています。

node = OrderedDict((("name", curve), ("form", form), ("degree", degs), ("points", cvs), ("knots", knts)))

書き込みモード”w”を指定し、openでファイルを開きます。
JSONファイルに保存するにはjson.dump()を使用します。さらにdump()には様々な引数があるのですが、今回はファイルを見やすくするためインデントを使用しています。

with open("E:/output.json", "w") as f:
	json.dump( output, f,  indent=4 )

JSONファイルを入力

JSONファイルを入力するには読み込みモード”r”を指定します。
さらにjson.load()でファイルを読み込みます。
簡単ですね!
違う点と言えば、カーブが閉じているかどうかで分岐をさせている点になります。

with open("E:/output.json", "r") as f:
	jsn = json.load( f ) [0]
	if jsn["form"] == 0:
		cmds.curve( per=False, p=jsn["points"], d=jsn["degree"], k=jsn["knots"] )
	else:
		cmds.curve( per=True, p=jsn["points"], d=jsn["degree"], k=jsn["knots"] 

サンプルコード

選択した1本のカーブをEドライブに適当なファイル名でJSONファイルに出力し、そのまま入力するというシンプルなpythonスクリプトを書いてみましたのでサンプルとして掲載しておきます。
このままではduplicateと同じになってしまいますが、ファイルの読み書きなどのインターフェイスなどを付けてあげることで色々とできるのではないかと思いますので試してみたいですね!
では、また!

# -*- coding: utf-8 -*-
import maya.cmds as cmds
import json
from collections import OrderedDict

selection = cmds.ls( sl=True, fl=True )
curve = cmds.filterExpand( selection, sm=9 )[0]
curveShapes = cmds.listRelatives( curve, c = True, pa= True, type = "nurbsCurve")[0]

#次数を取得
degs = cmds.getAttr( curve + ".degree" )

#curveInfoノードを作成
curveInfoNode = cmds.createNode( "curveInfo" )
cmds.connectAttr( curveShapes + ".worldSpace", curveInfoNode + ".inputCurve" )
#コントロールポイントを取得
cvs = cmds.getAttr( curveInfoNode + ".controlPoints[*]" )
#ノットベクトルを取得  
knts = cmds.getAttr( curveInfoNode + ".knots[*]" )
#curveInfoノードを削除
cmds.delete( curveInfoNode )
#カーブが閉じているかどうか
form = cmds.getAttr( curveShapes + ".form")

#出力用のリスト
output = []
#ディクショナリを作成
node = OrderedDict((("name", curve), ("form", form), ("degree", degs), ("points", cvs), ("knots", knts)))
output.append( node )

#Jsonを出力
with open("E:/output.json", "w") as f:
	json.dump( output, f,  indent=4 )

#Jsonを入力
with open("E:/output.json", "r") as f:
	jsn = json.load( f ) [0]
	if jsn["form"] == 0:
		cmds.curve( per=False, p=jsn["points"], d=jsn["degree"], k=jsn["knots"] )
	else:
		cmds.curve( per=True, p=jsn["points"], d=jsn["degree"], k=jsn["knots"] )

コメント

タイトルとURLをコピーしました