【Maya】ShaderFXをスクリプトから操作する

ShaderFXで作成されたMaterialのパラメーターを差し替えるツールを作る機会があったので、その際に利用したShaderFXのコマンドに関してまとめてみます。

自動的にShaderFXプラグインを読み込む

何はともあれShaderFXのプラグインを読み込む必要があります。
というわけで以下のようにすることでまだ読み込まれていない場合は読み込むことができます。

if not cmds.pluginInfo("shaderFXPlugin", q=True, loaded=True):
    cmds.loadPlugin("shaderFXPlugin")
    cmds.pluginInfo("shaderFXPlugin", e=True, autoload=True)

ShaderFXコマンドのリファレンスを表示

Mayaのコマンドリファレンスにはshaderfxのコマンドに関して記載されていないので、shaderfxコマンドでリファレンスを表示します。

cmds.shaderfx(help=True)

Maya2018.2で実行した結果をこちらに記載してあります。
Maya shadefx command reference · GitHub

ShaderFXシェーダーを作成

これはshadingNodeコマンドを用います。

shader_name = "ShaderFXSample"
cmds.shadingNode("ShaderfxShader", asShader=True, n=shader_name)

既存のグラフを読み込み

f:id:tm8r:20180511133951p:plain
ShaderFXのウィンドウから「.sfx」ファイルとしてグラフ全体または選択したグラフの書出しをすることができます。
このファイルを引数に指定することで読み込みが可能です。

shader_name = "ShaderFXSample"
graph_path = "/Users/tm8r/Documents/maya/shaderfx/sample_graph.sfx"
cmds.shaderfx(sfxnode=shader_name, loadGraph=graph_path)

sfxnodeに対象のShaderFXノードの名前を指定、loadGraphに「.sfx」ファイルのパスを指定する形になります。
ちなみにshaderfxコマンドでは引数に指定した値が存在しないときRuntimeErrorを吐くので、よしなにtry-exceptが必要です。

プロパティを書き換える

まずは書き換え対象のShaderFX内のノードIDを知る必要があります。
ノードIDの取得はgetNodeIDByName引数を用いてノード名を指定することで実現できます。

shader_name = "ShaderFXSample"
node_name = "TextureMap"
node_id = cmds.shaderfx(sfx_node=shader_name, getNodeIDByName=node_name)

指定した名前のノードが見つからない場合もRuntimeErrorを吐くので、上のスクリプトで言うところのnode_idの空チェックは無駄です。かなしみ。

尚、ShaderFXのウィンドウで設定からノードIDを表示するオプションを有効にすることでもノードIDが確認できます。
f:id:tm8r:20180511135851p:plain

ちなみに同名のノードがあると、多分ノードIDが小さい方だけが取得されるので、スクリプトから変更する可能性のあるノード名は一意にしておくとよさそうです。

次にプロパティ名を知る必要があるわけですが、残念なことにlistProperties引数を利用してshaderfxコマンドを実行してもだいたいのプロパティが返ってきません。なぜなの…。
というわけでどうやってプロパティ名を知るかというと、書出した「.sfx」ファイルを見るのが一番早いかと思います。
たとえばTextureMapノードのテクスチャのプロパティは、指定したパスで「.sfx」ファイル内を検索してみると、「texturepath_MyTexture」であることが分かります。

というわけでスクリプトはこんな感じになります。

shader_name = "ShaderFXSample"
node_name = "TextureMap"
node_id = cmds.shaderfx(sfx_node=shader_name, getNodeIDByName=node_name)
texture_path = "/Users/tm8r/Documents/maya/sample/sourceimages/sample.png"
cmds.shaderfx(sfxnode=shader_name, edit_stringPath=[node_id, "texturepath_MyTexture", texture_path])

詳細は上のhelpの実行結果を見てもらえれば分かるんですが、プロパティを書き換える場合は型によって使用する引数が異なります。
stringの場合はedit_stringを使用する、みたいな感じです。

ただパスに関してはちょっと特別で、edit_stringでも格納できるんですが、上のようにedit_stringPathを使えばプロジェクトパスからの相対値がセットされます。
具体的にはプロジェクトのパスが「/Users/tm8r/Documents/maya/sample」でテクスチャのパスが「/Users/tm8r/Documents/maya/sample/sourceimages/sample.png」だったとき、edit_stringではフルパスが、edit_stringPathでは「sourceimages/sample.png」がセットされます。

作成したShaderFXのMaterialを他のMaterialと差し替える

これはもうShaderFX関係ないですけど。
せっかくMaterialを作ったので割り当てたいですよね。

というわけで既に適用済みのMaterialと差し替えるスクリプトはこんな感じ。

# 指定Materialが適用されているオブジェクトを選択
cmds.hyperShade(objects=original_material)

# 現在選択中のオブジェクトに指定Materialを適用
cmds.hyperShade(assign=shader_name)

# 選択をクリア
cmds.select(cl=True)

original_materialには現在適用中のMaterial名を、shader_nameには作成したShaderFXのMaterial名を指定します。
hyperShadeコマンドにobjects引数を渡すと適用対象が選択されるので、最後に選択をクリアしてあげて終了です。

コメントに書いた通りhyperShadeのassign引数は選択中のオブジェクトに指定Materialを適用するものなので、実行前に任意のオブジェクトをcmds.selectを用いて選択しておけば、差し替えではなく任意のオブジェクトに適用することもできます。

おわり

ドキュメントが全然なくてつらみがありますが、無事目的を達成することができました。めでたし。

スポンサーリンク