ポリゴン作成プラグイン

メッシュの作成

Maya で mesh のデーターを作成するには、 maya.OpenMaya.MFnMesh クラスの create() メソッドを使用します。
create() メソッドには以下の引数を与えます。

create(numVertices, numFaces, points, faceCounts, faceConnects, outData)
numVertices
頂点数(int)
numFaces
フェースの個数(int)
points
頂点座標値の配列 (maya.OpenMaya.MFloatPointArray())
faceCounts
各フェースがいくつの頂点で構成されているかを表す配列 (maya.OpenMaya.MIntArray())
faceConnects
頂点の結線を表す配列 (maya.OpenMaya.MIntArray())
outData
出力される mesh データ (maya.OpenMaya.MObject)

メッシュ作成プラグイン

ポリゴンメッシュのプレーンを作成するプラグインを作ってみましょう。
作成されるプレーンは、フェースがひとつだけのシンプルなものです。

  1. 以下の Python スクリプトを simplePoly1.py という名前で作ります。
    import sys
    import maya.OpenMaya
    import maya.OpenMayaMPx
    
    kPluginNodeName = 'simplePoly1'
    kPluginNodeId = maya.OpenMaya.MTypeId(0x87007)
    
    class simplePoly1(maya.OpenMayaMPx.MPxNode):
        widthHeight = maya.OpenMaya.MObject()
        outputMesh = maya.OpenMaya.MObject()
    
        def __init__(self):
            maya.OpenMayaMPx.MPxNode.__init__(self)
    
        def _createMesh(self, planeSize, outData):
            numFaces = 1
    
            vtxs = []
            vtxs.append(maya.OpenMaya.MFloatPoint(planeSize, 0.0, planeSize))
            vtxs.append(maya.OpenMaya.MFloatPoint(planeSize, 0.0, -planeSize))
            vtxs.append(maya.OpenMaya.MFloatPoint(-planeSize, 0.0, -planeSize))
            vtxs.append(maya.OpenMaya.MFloatPoint(-planeSize, 0.0,  planeSize))
            numVertices = len(vtxs)
    
            points = maya.OpenMaya.MFloatPointArray()
            points.setLength(numVertices)
            for i in range(numVertices):
                points.set(vtxs[i], i)
    
            faceConnects = maya.OpenMaya.MIntArray()
            faceConnects.setLength(4)
            faceConnects[0] = 1
            faceConnects[1] = 2
            faceConnects[2] = 3
            faceConnects[3] = 0
    
            faceCounts = maya.OpenMaya.MIntArray()
            faceCounts.setLength(numFaces)
            faceCounts.set(4, 0)
    
            meshFS = maya.OpenMaya.MFnMesh()
            newMesh = meshFS.create(numVertices, numFaces, points, faceCounts, faceConnects, outData)
            return newMesh
    
        def compute(self, plug, data):
            if plug == simplePoly1.outputMesh:
                dataHandle = data.inputValue(simplePoly1.widthHeight)
                size = dataHandle.asFloat()
    
                dataCreator = maya.OpenMaya.MFnMeshData()
                newOutputData = dataCreator.create()
                self._createMesh(size, newOutputData)
    
                outputHandle = data.outputValue(simplePoly1.outputMesh)
                outputHandle.setMObject(newOutputData)
                data.setClean(plug)
            else:
                return maya.OpenMaya.kUnknownParameter
    
    def nodeCreator():
        return maya.OpenMayaMPx.asMPxPtr(simplePoly1())
    
    def nodeInitializer():
        nAttr = maya.OpenMaya.MFnNumericAttribute()
        simplePoly1.widthHeight = nAttr.create('widthHeight', 'wh', maya.OpenMaya.MFnNumericData.kFloat, 1.0)
        nAttr.setStorable(1)
    
        typedAttr = maya.OpenMaya.MFnTypedAttribute()
        simplePoly1.outputMesh = typedAttr.create('outputMesh', 'out', maya.OpenMaya.MFnData.kMesh)
        simplePoly1.addAttribute(simplePoly1.widthHeight)
        simplePoly1.addAttribute(simplePoly1.outputMesh)
        simplePoly1.attributeAffects(simplePoly1.widthHeight, simplePoly1.outputMesh)
    
    
    def initializePlugin(mobject):
        mplugin = maya.OpenMayaMPx.MFnPlugin(mobject)
        try:
            mplugin.registerNode(kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer)
        except:
            sys.stderr.write('Failed to register node: %s' % kPluginNodeName)
            raise
    
    def uninitializePlugin(mobject):
        mplugin = maya.OpenMayaMPx.MFnPlugin(mobject)
        try:
            mplugin.deregisterNode( kPluginNodeId )
        except:
            sys.stderr.write('Failed to deregister node: %s' % kPluginNodeName)
            raise
    
  2. simplePoly1.py をロードします。
    以下のどちらかの方法でロードします。
  3. スクリプト エディタ のインプットウインドウで以下のように実行してみます。
    import maya.cmds
    poly = maya.cmds.createNode('transform')
    mesh = maya.cmds.createNode('mesh', parent=poly)
    maya.cmds.sets(mesh, add='initialShadingGroup')
    spoly = maya.cmds.createNode('simplePoly1')
    maya.cmds.connectAttr(spoly + '.outputMesh', mesh + '.inMesh')

スクリプトの解説

import sys
sys モジュールをインポートします。
エラーの表示をするために必要です。
import maya.OpenMaya
maya.OpenMaya モジュールをインポートします。
import maya.OpenMayaMPx
maya.OpenMayaMPx モジュールをインポートします。
kPluginNodeName = 'simplePoly1'
このプラグインの名前を simplePoly1 として、変数 kPluginNodeName に代入します。
kPluginNodeId = maya.OpenMaya.MTypeId(0x87007)
プラグインごとにユニークな識別番号を決めます。
プラグインは、この番号によって Maya の中で登録・識別・登録取り消しなどが行われます。
ローカルだけで使用する場合などは0x00000000以上、0x0007ffff以下の番号を、 プラグインを公表する場合は Autodesk からユニークな番号を取得します。
class simplePoly1(maya.OpenMayaMPx.MPxNode):
maya.OpenMayaMPx.MPxNode を継承して、 ノード作成のためのクラスを定義します。
widthHeight = maya.OpenMaya.MObject()
入力データのために、MObject インスタンスを作成して、クラス変数 widthHeight に代入します。
この widthHeight はプレーンの縦横の幅を決めるためのアトリビュートです。
outputMesh = maya.OpenMaya.MObject()
出力データのために、MObject インスタンスを作成して、クラス変数 outputMesh に代入します。
この outputMesh はプレーンの mesh データが入るアトリビュートです。
def __init__(self):
simplePoly1 クラス初期化のためのメソッドです。
maya.OpenMayaMPx.MPxNode.__init__(self)
sineNode1 クラスを初期化するために、 親クラス MPxNode の __init__() を実行します。
def _createMesh(self, planeSize, outData):
プレーンの mesh データを作成するメソッドです。
引数の意味は以下のとおりです。
planeSize
プレーンの縦横の幅
outData
このメソッドで計算された出力用の mesh データの入る変数
numFaces = 1
フェースの数を表す変数 numFaces に 1 を代入します。
vtxs = []
頂点の座標を入れておくリストを初期化します。
vtxs.append(maya.OpenMaya.MFloatPoint(planeSize, 0.0, planeSize))
1 番目の頂点座標 (planeSize, 0.0, planeSize) を vtxs に追加します。
vtxs.append(maya.OpenMaya.MFloatPoint(planeSize, 0.0, -planeSize))
2 番目の頂点座標 (planeSize, 0.0, -planeSize) を vtxs に追加します。
vtxs.append(maya.OpenMaya.MFloatPoint(-planeSize, 0.0, -planeSize))
3 番目の頂点座標 (-planeSize, 0.0, -planeSize) を vtxs に追加します。
vtxs.append(maya.OpenMaya.MFloatPoint(-planeSize, 0.0, planeSize))
4 番目の頂点座標 (-planeSize, 0.0, planeSize) を vtxs に追加します。
numVertices = size(vtxs)
頂点数を表す変数 numVertices にリスト vtxs の要素数を代入します。
points = maya.OpenMaya.MFloatPointArray()
MFloatPointArray のインスタンスを作成して、変数 points に代入します。
MFloatPointArray は頂点のデータを表す MFloatPoint の配列です。
points.setLength(numVertices)
頂点データの配列 points の要素数を numVertices に設定します。
for i in range(numVertices):
変数 i を 0 から numVertices - 1 までインクリメントしながら、 for 文を繰り返します。
points.set(vtxs[i], i)
頂点データの配列 points の i 番目に vtxs[i] を代入します。
faceConnects = maya.OpenMaya.MIntArray()
MIntArray のインスタンスを作成し、faceConnects に代入します。
MIntArray は int の配列です。
faceConnects.setLength(4)
int の配列 faceConnects の要素数を 4 に設定します。
faceConnects[0] = 1
int の配列 faceConnects の 0 番目に 1 を代入します。
この 1 は 1 番目の頂点を表します。
faceConnects[1] = 2
int の配列 faceConnects の 1 番目に 2 を代入します。
この 2 は 2 番目の頂点を表します。
faceConnects[2] = 3
int の配列 faceConnects の 2 番目に 3 を代入します。
この 3 は 3 番目の頂点を表します。
faceConnects[3] = 0
int の配列 faceConnects の 3 番目に 0 を代入します。
この 0 は 0 番目の頂点を表します。
これで、1 → 2 → 3 → 0 の順番で頂点が結ばれたフェースになります。
faceCounts = maya.OpenMaya.MIntArray()
MIntArray のインスタンスを作成し、faceConnects に代入します。
MIntArray は int の配列です。
faceCounts.setLength(numFaces)
int の配列 faceCounts の要素数を numFaces (1) に設定します。
faceCounts.set(4, 0)
int の配列 faceCounts の 0 番目に 4 を代入します。
この 4 は 0 番目のフェースが 4 つの頂点でできていることを表します。
meshFS = maya.OpenMaya.MFnMesh()
MFnMesh のインスタンスを作成して meshFS に代入します。
MFnMesh は mesh を作成・編集するメソッドを集めたクラスです。
newMesh = meshFS.create(numVertices, numFaces, points, faceCounts, faceConnects, outData)
新しい mesh を作成します。
結果は outData に入ります。
return newMesh
新しく作成された mesh データを返り値として返します。
ただし、このプラグインではこの返り値は利用していません。
def compute(self, plug, data):
ノードが実行する処理を記述しておく関数です。
引数の意味は以下のとおりです。
plug
他のノードにコネクトされているプラグを表します。
data
このノードに関するデータを保存しているオブジェクトです。
if plug == simplePoly1.outputMesh:
プラグが出力 outputMesh かどうか調べます。
dataHandle = data.inputValue(simplePoly1.widthHeight)
データブロックから、入力データ widthHeight のデータハンドルを得て、 dataHandle に代入します。
size = dataHandle.asFloat()
入力データをデータハンドルから float のデータとして取り出し、 size に代入します。
dataCreator = maya.OpenMaya.MFnMeshData()
MFnMeshData のインスタンスを作成し、dataCreator に代入します。
mesh データを作成・編集するためのメソッドを集めたクラスです。
newOutputData = dataCreator.create()
mesh データを入れておくための MObject を作成し、newOutputData に代入します。
self._createMesh(size, newOutputData)
simplePoly1 のメソッド _createMesh() を実行して、 newOutputData に結果の mesh データを入れます。
outputHandle = data.outputValue(simplePoly1.outputMesh)
データブロックから出力データ outputMesh のデータハンドルを得て、 outputHandle に代入します。
outputHandle.setMObject(newOutputData)
出力データのデータハンドルに出力データ newOutputData を MObject のデータとして与えます。
data.setClean(plug)
プラグをクリーンにします。 これをしないとノードの計算が終わっているとみなされません。
else:
  return maya.OpenMaya.kUnknownParameter
プラグが outputMesh 以外の場合は、kUnknownParameter を返して Maya に処理を任せます。
計算する必要の無いプラグは、kUnknownParameter を返しておきます。
def nodeCreator():
Maya がノードのインスタンスを作成するための関数です。
return maya.OpenMayaMPx.asMPxPtr(simplePoly1())
simplePoly1 クラスのインスタンスを作成し、asMPxPtr() 関数に与えます。
asMPxPtr() 関数を使わないとインスタンスを Maya に渡すことができません。
def nodeInitializer():
ノードの初期化関数です。
このノードが作成されるときに実行されます。
nAttr = maya.OpenMaya.MFnNumericAttribute()
MFnNumericAttribute のインスタンスを作成します。
simplePoly1.widthHeight = nAttr.create('widthHeight', 'wh', maya.OpenMaya.MFnNumericData.kFloat, 1.0)
widthHeight アトリビュートを作成し、短縮名は wh 、型は float 、デフォールト値は 1.0 にします。
nAttr.setStorable(1)
シーンの保存時に widthHeight アトリビュートの値を保存する設定です。
typedAttr = maya.OpenMaya.MFnTypedAttribute()
MFnTypedAttribute のインスタンスを作成し、typedAttr に代入します。
simplePoly1.outputMesh = typedAttr.create('outputMesh', 'out', maya.OpenMaya.MFnData.kMesh)
outputMesh アトリビュートを作成し、短縮名は out 、型は mesh にします。
simplePoly1.addAttribute(simplePoly1.widthHeight)
widthHeight アトリビュートを simplePoly1 ノードのアトリビュートとして設定します。
simplePoly1.addAttribute(simplePoly1.outputMesh)
outputMesh アトリビュートを simplePoly1 ノードのアトリビュートとして設定します。
simplePoly1.attributeAffects(simplePoly1.widthHeight, simplePoly1.outputMesh)
widthHeight アトリビュートが変化したとき、 プラグを outputMesh として simplePoly1 の compute メソッドを実行するように設定します。
def initializePlugin(mobject):
プラグインがロードされたときに実行される初期化関数です。
mplugin = maya.OpenMayaMPx.MFnPlugin(mobject)
MFnPlugin クラスのインスタンスを作成します。
mobject は MObject のインスタンスです。
try:
  mplugin.registerNode(kPluginNodeName, kPluginNodeId, nodeCreator, nodeInitializer)
except:
  sys.stderr.write('Failed to register node: %s' % kPluginNodeName)
  raise
MFnPlugin のインスタンスに、simplePoly1 に関する設定を与えています。
もし設定に失敗した場合は、メッセージを出力して例外を送出します。
def uninitializePlugin(mobject):
プラグインをアンロードするときに実行される関数です。
mplugin = maya.OpenMayaMPx.MFnPlugin(mobject)
MFnPlugin クラスのインスタンスを作成します。
mobject は MObject のインスタンスです。
try:
  mplugin.deregisterNode(kPluginNodeId)
except:
  sys.stderr.write('Failed to deregister node: %s' % kPluginNodeName)
  raise
プラグインをアンロードします。
もしアンロードに失敗した場合は、メッセージを出力して例外を送出します。

練習

  1. 上の simplePoly1.py を参考にして simplePoly2.py という Python プラグインを作り、 フェースが 4 つのポリゴン平面が作られるようにしてみましょう。
    (作成例)
    simplePoly2.py をプラグインマネージャなどで読み込んだ後、 以下の関数を実行します。
    import maya.cmds
    poly = maya.cmds.createNode('transform')
    mesh = maya.cmds.createNode('mesh', parent=poly)
    maya.cmds.sets(mesh, add='initialShadingGroup')
    spoly = maya.cmds.createNode('simplePoly2')
    maya.cmds.connectAttr(spoly + '.outputMesh', mesh + '.inMesh')

参考


Prev | Next
Home | Contents
Mail