テクスチャノード・プラグイン

テクスチャノード・プラグインとは

テクスチャノード・プラグインによって、Maya のテクスチャ・ノードを作成することができます。
ここでは、2Dテクスチャの作成方法を解説します。

テクスチャノード・プラグインに必要なクラス・関数

ノードを作成するためのクラス
クラス名は自由ですが、maya.OpenMayaMPx.MPxNode を継承する必要があります。
クラス内には以下の関数が必要です。
__init__(self)
クラスの初期化関数では、 最低限 maya.OpenMayaMPx.MPxNode.__init__() を実行します。
compute(self, plug, block)
ノードが実行する処理を記述します。
nodeCreator()
クラスのインスタンスを作成する関数です。
nodeInitializer()
ノードのアトリビュートを初期化する関数です。
initializePlugin(mobject)
プラグインがロードされるときに実行されます。
ノードの登録などを行います。
uninitializePlugin(mobject)
プラグインがアンロードされるときに実行されます。
ノードの登録取り消しなどを行います。

2Dテクスチャノードに必要なアトリビュート

2Dテクスチャ・ノードを作成するときには、 最低限以下のアトリビュートを実装する必要があります。

uvCoord(uv)
UV座標を表すアトリビュート
複合アトリビュートなので、以下の子アトリビュートを持ちます。
uCoord (u)
U座標
vCoord (v)
V座標
uvFilterSize
UV方向のフィルタサイズ
ぼかし(ブラー)をかけるための計算などに使用します。 必要なければ使用しなくてもかまいません。
複合アトリビュートなので、以下の子アトリビュートを持ちます。
uFilterSize (ufs)
U方向のフィルタサイズ
vFilterSize (vfs)
V座方向のフィルタサイズ

2Dテクスチャノード・プラグインの例

UV座標が0.5以上の部分に色がつくというテクスチャノードを作成してみましょう。

  1. 以下の Python スクリプトを myTexture1.py という名前で作ります。
    import sys
    import maya.OpenMaya
    import maya.OpenMayaMPx
    
    kPluginNodeName = 'myTexture1'
    kPluginNodeId = maya.OpenMaya.MTypeId(0x87010)
    
    class myTexture1(maya.OpenMayaMPx.MPxNode):
        aUVCoord = maya.OpenMaya.MObject()
        aFilterSize = maya.OpenMaya.MObject()
        aInColor = maya.OpenMaya.MObject()
        aOutColor = maya.OpenMaya.MObject()
        def __init__(self):
            maya.OpenMayaMPx.MPxNode.__init__(self)
    
        def compute(self, plug, block):
            if plug == myTexture1.aOutColor or plug.parent() == myTexture1.aOutColor:
                resultColor = maya.OpenMaya.MFloatVector(0.0, 0.0, 0.0)
    
                uv = block.inputValue(myTexture1.aUVCoord).asFloat2();
                inColor = block.inputValue(myTexture1.aInColor).asFloatVector()
    
                if uv[0] > 0.5 and uv[1] > 0.5:
                    resultColor.x = inColor.x
                    resultColor.y = inColor.y
                    resultColor.z = inColor.z
    
                outColorHandle = block.outputValue(myTexture1.aOutColor)
                outColorHandle.setMFloatVector(resultColor)
                outColorHandle.setClean()
            else:
                return maya.OpenMaya.kUnknownParameter
    
    
    def nodeCreator():
        return maya.OpenMayaMPx.asMPxPtr(myTexture1())
    
    
    def nodeInitializer():
        nAttr = maya.OpenMaya.MFnNumericAttribute()
    
        child1 = nAttr.create('uCoord', 'u', maya.OpenMaya.MFnNumericData.kFloat)
        child2 = nAttr.create('vCoord', 'v', maya.OpenMaya.MFnNumericData.kFloat)
        myTexture1.aUVCoord = nAttr.create("uvCoord", "uv", child1, child2)
        nAttr.setKeyable(True)
        nAttr.setStorable(True)
        nAttr.setReadable(True)
        nAttr.setWritable(True)
    
        child1 = nAttr.create("uvFilterSizeX", "fsx", maya.OpenMaya.MFnNumericData.kFloat)
        child2 = nAttr.create("uvFilterSizeY", "fsy", maya.OpenMaya.MFnNumericData.kFloat)
        myTexture1.aFilterSize = nAttr.create("uvFilterSize", "fs", child1, child2)
        nAttr.setKeyable(True)
        nAttr.setStorable(True)
        nAttr.setReadable(True)
        nAttr.setWritable(True)
    
        myTexture1.aInColor = nAttr.createColor('inColor', 'ic')
        nAttr.setStorable(True)
        nAttr.setReadable(True)
        nAttr.setWritable(True)
        nAttr.setDefault(1.0, 1.0, 1.0)
    
        myTexture1.aOutColor = nAttr.createColor('outColor', 'oc')
        nAttr.setStorable(False)
        nAttr.setHidden(False)
        nAttr.setReadable(True)
        nAttr.setWritable(False)
    
        myTexture1.addAttribute(myTexture1.aUVCoord)
        myTexture1.addAttribute(myTexture1.aFilterSize)
        myTexture1.addAttribute(myTexture1.aInColor)
        myTexture1.addAttribute(myTexture1.aOutColor)
    
        myTexture1.attributeAffects (myTexture1.aUVCoord, myTexture1.aOutColor)
        myTexture1.attributeAffects (myTexture1.aFilterSize, myTexture1.aOutColor)
        myTexture1.attributeAffects (myTexture1.aInColor, myTexture1.aOutColor)
    
    
    def initializePlugin(mobject):
        mplugin = maya.OpenMayaMPx.MFnPlugin(mobject)
        try:
            mplugin.registerNode(kPluginNodeName, kPluginNodeId, nodeCreator, 
                        nodeInitializer, maya.OpenMayaMPx.MPxNode.kDependNode, 'texture/2d')
        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. myTexture1.py をロードします。
    以下の、いづれかの方法でロードします。
  3. ハイパーシェードを開くと、ロードしたmyTexture1が2D テクスチャの中にあるのがわかります。
  4. 新しいLambertシェーダを作成し、myTexture1をマウス中ボタンで作成したシェーダにアサインしてみます。

    通常のテクスチャと同じようにアサインされて、place2dTextureノードがコネクトされているのがわかります。
  5. lambert2 マテリアルのアサインされた NURBS の球体を作成してみると、 U座標が0.5以下、V座標が0.5以下の部分は黒になっているのがわかります。
  6. myTexture1ノードのアトリビュートエディタを開いてIn Colorアトリビュートによって色を変更できます。

スクリプトの解説

import sys
sys モジュールをインポートします。
エラーの表示をするために必要です。
import maya.OpenMaya
maya.OpenMaya モジュールをインポートします。
import maya.OpenMayaMPx
maya.OpenMayaMPx モジュールをインポートします。
kPluginNodeName = 'myTexture1'
このプラグインの名前を myTexture1 として、変数 kPluginNodeName に代入します。
kPluginNodeId = maya.OpenMaya.MTypeId(0x87010)
プラグインごとにユニークな識別番号を決めます。
プラグインは、この番号によって Maya の中で登録・識別・登録取り消しなどが行われます。
ローカルだけで使用する場合などは0x00000000以上、0x0007ffff以下の番号を、 プラグインを公表する場合は Autodesk からユニークな番号を取得します。
class myTexture1(maya.OpenMayaMPx.MPxNode):
maya.OpenMayaMPx.MPxNode を継承して、 テクスチャノード作成のためのクラスを定義します。
aUVCoord = maya.OpenMaya.MObject()
UV座標のデータを入力するための MObject インスタンスを作成して、クラス変数 aUVCoord に代入します。
aFilterSize = maya.OpenMaya.MObject()
フィルタのサイズデータを入力するための MObject インスタンスを作成して、クラス変数 aFilterSize に代入します。
このプラグインでは出力データの計算に使用していません。
aInColor = maya.OpenMaya.MObject()
色を表す入力データのために、 MObject インスタンスを作成して、クラス変数 aInColor に代入します。
aOutColor = maya.OpenMaya.MObject()
色を表す出力データのために、 MObject インスタンスを作成して、クラス変数 aOutColor に代入します。
def __init__(self):
クラス myTexture1 のインスタンス作成時に実行される初期化関数を定義します。
maya.OpenMayaMPx.MPxNode.__init__(self)
myTexture1 クラスを初期化するために、 親クラス MPxNode の __init__() を実行します。
def compute(self, plug, block):
シェーディングノードが実行する処理を記述しておく関数です。
引数の意味は以下のとおりです。
plug
他のノードにコネクトされているプラグを表します。
block
このノードに関するデータを保存しているオブジェクトです。
if plug == myTexture1.aOutColor or plug.parent() == myTexture1.aOutColor:
プラグまたは、プラグの親クラスが出力 aOutColor かどうか調べます。
resultColor = maya.OpenMaya.MFloatVector(0.0, 0.0, 0.0)
3 つの float をもつ MFloatVector を、 初期値 (0.0, 0.0, 0.0) で作成し、内部変数 resultColor に代入します。
resultColor にこのノードから出力される結果の数値が入ります。
uv = block.inputValue(myTexture1.aUVCoord).asFloat2();
データブロックから、入力データ aUVCoord のデータハンドルを得て、 floatの2つのデータが入った配列として内部変数uvに代入します。
inColor = block.inputValue(myTexture1.aInColor).asFloatVector()
データブロックから、入力データ aInColor のデータハンドルを得て、 asFloatVector() によって float の数値に変換し内部変数 inColor に代入します。
if uv[0] > 0.5 and uv[1] > 0.5:
  resultColor.x = inColor.x
  resultColor.y = inColor.y
  resultColor.z = inColor.z
U座標(vu[0])が0.5以上、V座標(uv[1])が0.5以上のときに 入力の色と出力の色を同じにします。
outColorHandle = block.outputValue(myTexture1.aOutColor)
データブロックから出力データ output のデータハンドルを得て、 内部変数 outColorHandle に代入します。
outColorHandle.setMFloatVector(resultColor)
出力データのデータハンドルに出力データ resultColor を floatVector のデータとして与えます。 (floatVector は float が 3 つ並んだ型です)
outColorHandle.setClean()
プラグをクリーンにします。 これをしないとノードの計算が終わっているとみなされません。
else:
  return maya.OpenMaya.kUnknownParameter
プラグが aOutColor 以外の場合は、kUnknownParameter を返して Maya に処理を任せます。
計算する必要の無いプラグは、kUnknownParameter を返しておきます。
def nodeCreator():
Maya がノードのインスタンスを作成するための関数です。
  return maya.OpenMayaMPx.asMPxPtr(myTexture1())
myTexture1 クラスのインスタンスを作成し、asMPxPtr() 関数に与えます。
asMPxPtr() 関数を使わないとインスタンスが Maya に渡すことができません。
def nodeInitializer():
ノードの初期化関数です。
nAttr = maya.OpenMaya.MFnNumericAttribute()
MFnNumericAttribute のインスタンスを作成します。
child1 = nAttr.create('uCoord', 'u', maya.OpenMaya.MFnNumericData.kFloat)
uCoord アトリビュートを作成し、短縮名は u 、型は float にします。
uvCoordアトリビュートの子アトリビュートになります。
child2 = nAttr.create('vCoord', 'v', maya.OpenMaya.MFnNumericData.kFloat)
vCoord アトリビュートを作成し、短縮名は v 、型は float にします。
uvCoordアトリビュートの子アトリビュートになります。
myTexture1.aUVCoord = nAttr.create("uvCoord", "uv", child1, child2)
uCoordアトリビュートとvCoordアトリビュートを含んだ親アトリビュートuvCoordを作成し、 短縮名は uv にします。
nAttr.setKeyable(True)
uvCoord アトリビュートにアニメーションキーを設定可能にします。
nAttr.setStorable(True)
シーンの保存時に uvCoord アトリビュートの値を保存する設定です。
nAttr.setReadable(True)
uvCoord アトリビュートの値を読み取り可能にします。
nAttr.setWritable(True)
uvCoord アトリビュートの値を書き込み可能にします。
child1 = nAttr.create("uvFilterSizeX", "fsx", maya.OpenMaya.MFnNumericData.kFloat)
uvFilterSizeX アトリビュートを作成し、短縮名は fsx 、型は float にします。
uvFilterSizeアトリビュートの子アトリビュートになります。
child2 = nAttr.create("uvFilterSizeY", "fsy", maya.OpenMaya.MFnNumericData.kFloat)
uvFilterSizeY アトリビュートを作成し、短縮名は fsy 、型は float にします。
uvFilterSizeアトリビュートの子アトリビュートになります。
myTexture1.aFilterSize = nAttr.create("uvFilterSize", "fs", child1, child2)
uvFilterSizeXアトリビュートとuvFilterSizeYアトリビュートを含んだ親アトリビュートuvFilterSizeを作成し、短縮名は fs にします。
nAttr.setKeyable(True)
uvFilterSize アトリビュートにアニメーションキーを設定可能にします。
nAttr.setStorable(True)
シーンの保存時に uvFilterSize アトリビュートの値を保存する設定です。
nAttr.setReadable(True)
uvFilterSize アトリビュートの値を読み取り可能にします。
nAttr.setWritable(True)
uvFilterSize アトリビュートの値を書き込み可能にします。
myTexture1.aInColor = nAttr.createColor('inColor', 'ic')
inColor アトリビュートを作成し、短縮名は ic 、型は Color にします。
nAttr.setStorable(True)
シーンの保存時に inColor アトリビュートの値を保存する設定です。
nAttr.setReadable(True)
inColor アトリビュートの値を読み取り可能にします。
nAttr.setWritable(True)
inColor アトリビュートの値を書き込み可能にします。
nAttr.setDefault(1.0, 1.0, 1.0)
inColor アトリビュートのデフォールト値を (1.0, 1.0, 1.0) にします。
myTexture1.aOutColor = nAttr.createColor('outColor', 'oc')
outColor アトリビュートを作成し、短縮名は oc 、型は Color にします。
nAttr.setStorable(False)
シーンの保存時に outColor アトリビュートの値を保存しない設定です。
nAttr.setHidden(False)
outColor アトリビュートを GUI で操作できるようにする設定です。
nAttr.setReadable(True)
inColor アトリビュートの値を読み取り可能にします。
nAttr.setWritable(False)
inColor アトリビュートの値を書き込み不可にします。
myTexture1.addAttribute(myTexture1.aUVCoord)
uvCoord アトリビュートを myTexture1 ノードのアトリビュートとして設定します。
myTexture1.addAttribute(myTexture1.aFilterSize)
uvFilterSize アトリビュートを myTexture1 ノードのアトリビュートとして設定します。
myTexture1.addAttribute(myTexture1.aInColor)
inColor アトリビュートを myTexture1 ノードのアトリビュートとして設定します。
myTexture1.addAttribute(myTexture1.aOutColor)
outColor アトリビュートを myTexture1 ノードのアトリビュートとして設定します。
myTexture1.attributeAffects (myTexture1.aUVCoord, myTexture1.aOutColor)
uvCoord アトリビュートが変化したとき、 プラグを aOutColor として myTexture1 の compute メソッドを実行するように設定します。
myTexture1.attributeAffects (myTexture1.aFilterSize, myTexture1.aOutColor)
uvFilterSize アトリビュートが変化したとき、 プラグを aOutColor として myTexture1 の compute メソッドを実行するように設定します。
myTexture1.attributeAffects (myTexture1.aInColor, myTexture1.aOutColor)
inColor アトリビュートが変化したとき、 プラグを aOutColor として myTexture1 の compute メソッドを実行するように設定します。
def initializePlugin(mobject):
プラグインがロードされたときに実行される初期化関数です。
mplugin = maya.OpenMayaMPx.MFnPlugin(mobject)
MFnPlugin クラスのインスタンスを作成します。
mobject は MObject のインスタンスです。
try:
  mplugin.registerNode(kPluginNodeName, kPluginNodeId, nodeCreator,
    nodeInitializer, maya.OpenMayaMPx.MPxNode.kDependNode, 'texture/2d')
except:
  sys.stderr.write('Failed to register node: %s' % kPluginNodeName)
  raise
MFnPlugin のインスタンスに、myTexture1 に関する設定を与えています。
もし設定に失敗した場合は、メッセージを出力して例外を送出します。
引数の最後の 2 つは以下のような意味です。
maya.OpenMayaMPx.MPxNode.kDependNode
ノードのタイプを表します。
'texture/2d'
シェーダノードの種類を詳しく説明した文字列です。
GUI の表示などで利用されます。 この場合は、ハイパーシェードの2d テクスチャの部分に表示されます。
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. 上の myTexture1.py を参考にして myTexture2.py という Python スクリプトを作ってください。
    myTexture2.pyには、以下のアトリビュートを追加してください。
    squareSize (ss)
    色の違う正方形の範囲
    myTexture1.pyではif文で0.5となっている部分です。
    例えば、このアトリビュートを 0.3 にすると、 U 座標とV 座標が 0.0 から 1.0 - 0.3 = 0.7 までが inColor1、 0.7 から 1.0 までが inColor2 の色になります。
    inColor1 (ic1)
    正方形の部分の色
    inColor2 (ic2)
    正方形以外の範囲の色
    myTexture2.pyでは、以下のアトリビュートを削除してください。
    inColor (ic)
    正方形の部分の色
    (実行例)
    実行方法は、myTexture1.pyと同じです。
    アトリビュートエディタの設定。

    以上の設定の結果。
  2. 前回の練習問題2.とおなじ模様のテクスチャプラグインを作成してください。
    上の練習問題のsquareSizeアトリビュートは必要ありません。
    (追加するアトリビュート)
    number (長い名前)
    n (短い名前)
    縞模様の分割数 (float)


    place2dTextureのアトリビュートを以下のように設定した結果。
    UVの回転
    90
    ノイズUV
    0.0 0.035

  3. 上の練習問題2.を参考にして波模様のテクスチャプラグインを作成してください。

参考


Prev
Home | Contents
Mail