株式会社デジタル・フロンティア-Digital Frontier

Header

Main

  • TOP
  • DF TALK
  • |砂箱|の向こう側 ~ Softimage & Mentalray Shader ~

|砂箱|の向こう側 ~ Softimage & Mentalray Shader ~

2012/8/27

Tag: ,,,

ども~ご無沙汰してます。
この夏の暑さにバテ気味の開発室ゴトー[@jackybian]です。

前回紹介した『砂箱』ですが、シェーダーUIのとこで終わってましたのでその辺りのことを今回お届けします。

●前回までのお話

si2011以降で実装されたsandboxのダイナミックシェーダービルド機能のおかげで
mentalrayの.miがそのまま使えるよっ!ヽ(゚∀゚)ノワーイ でもシェーダーのパラメータはズラズラズラズラと…ガ━(゚Д゚;)━ン
というお話でした。

●シェーダーUIも整理整頓した~い

てな訳で今回は”止めどなく連なるだけだったパラメータ”を整理しちゃうお話です。
そもそもSIで.spdlによるシェーダーの場合、その中でパラメータレイアウトが定義されていた訳です。
じゃあ同じmentalrayのシェーダーでもmayaやmaxはどうなってるの?
mayaは、AEテンプレートと呼ばれる.melで定義されています。つまり.miとは別ファイルで定義されています。
じゃあmaxも?と思いきやmax用の.miは中に独自の記述ブロックがあり、UIが定義されてるじゃありませんかっ!
つまり.miファイルと.dllだけでいいわけです。これスマ~トなんで採用しまっす!

●ShaderDefオブジェクトとsiOnCreateShaderDefイベント

兎にも角にもPPGLayout(所謂パラメータレイアウト)を弄れないかとSDKガイドを読み調べてみると、
”ShaderDefは、レンダツリーにシェーダノードをビルドする方法をSoftimageに伝えます。Softimageはシェーダノードをその入力および出力パラメータ(データタイプ、接続に関する制限、デフォルト値など)とともにビルドします。シェーダはインスタンス化されるときのみジャストインタイム方式でビルドされるため、極めてダイナミックになります”(SDKガイドより抜粋)
そこでShaderDefオブジェクトについて調べてみると、PPGLayoutプロパティが在るじゃないですか!
これで.AddItem()や.AddEnumControl()が使えるのでレイアウトをカスタム出来ます!!
さらに調べるとレンダーツリーにシェーダーをD&Dしたときに発生するsiOnCreateShaderDefイベントがあることを発見!
このイベントスクリプトを使えばうまく行けそーっす♪

●miファイルとイベントスクリプトの関係

ではmiファイルにどうレイアウトを定義するか?
これはmaxと同様に.miに独自のレイアウトブロックを記述しておき、
そのブロックをイベントスクリプトが解析してレイアウトを定義することにします。
そこで独自なレイアウトブロックの書式をどうするか?
①【ユーザーにとってわかり易い記述で実際のレイアウトが想像できる記述】
実際にユーザーが書き込む部分ですからコレ重要!
②【他ソフトでも問題なく動く互換性】
今回の手法はSI独自のものなので他ソフトでもレイアウトが共有できる訳じゃありませんが.miファイルとしてはソフトに非依存であるべき!

この点を考慮して.miファイルに独自のレイアウト定義を追記することにしました。
【レイアウト定義の書式】
Tab,Group,Parameterの名前やラベルをインデントで記述して<shader名:LAYOUT>タグで囲みコメント行にする

#<shaderName:LAYOUT>
#Tab "tab1"
#	Group "group1"
#		Param "param1",			"param1_label"
#	EndGroup
#	Param "param2",				"param2_label"
#	Group "group2"
#		Param "param3",			"param3_label"
#		Param "param4",			"param4_label"
#	EndGroup
#</shaderName:LAYOUT>

あとはイベントスクリプトの方でこのブロックを読み取り.AddItem()メソッド等の書式に変換した上で置換文字列を実行してやればOK。

という訳でいつもの如く、お便利なSDK_Wizardsを使ってイベントスクリプトの雛型をサクッと作って

あとはsiOnCreateShaderDefEvent_OnEvent()に処理を書くだけです。
いざっコーディング!!

# ShaderDefEvent Plug-in
# Initial code generated by Softimage SDK Wizard
# Executed Mon Nov 22 15:37:41 UTC+0900 2010 by hiro510
#
# Tip: To add a command to this plug-in, right-click in the
# script editor and choose Tools > Add Command.
import win32com.client
from win32com.client import constants as c
app=Application;log=app.logmessage
null = None
false = 0
true = 1
#===================================================
def ReplaceStr(in_str, PatternList, ReplacementList ):
    import re
    for i in range(len(PatternList)):
        in_str = re.sub(PatternList[i],ReplacementList[i],in_str)
    return in_str
#===================================================
def XSILoadPlugin( in_reg ):
    in_reg.Author = "hiro510"
    in_reg.Name = "ShaderDefEvent Plug-in"
    in_reg.Major = 1
    in_reg.Minor = 0
    in_reg.RegisterEvent("siOnCreateShaderDefEvent",c.siOnCreateShaderDef)
    #RegistrationInsertionPoint - do not remove this line
    return true
 
def XSIUnloadPlugin( in_reg ):
    strPluginName = in_reg.Name
    app.LogMessage(str(strPluginName) + str(" has been unloaded."),c.siVerbose)
    return true
 
# Callback for the siOnCreateShaderDefEvent event.
#------------------------------------------------------
constStr = '''
from win32com.client import constants as c
def main(in_ctxt):
 oLayout = in_ctxt.GetAttribute("ShaderDef").PPGLayout
'''
#------------------------------------------------------
def siOnCreateShaderDefEvent_OnEvent( in_ctxt ):
    #TODO: Put your code here.

    oShaderDef = in_ctxt.GetAttribute("ShaderDef")
    sParser = oShaderDef.Parser
    sMiPath = oShaderDef.DefinitionPath
    sShaderName = oShaderDef.Name.split(".")[1]
    if sParser == "mentalray":
        oFile = open(sMiPath,'r')
        sStr = oFile.read()
        oFile.close()
        if len(sStr.split('#<' + sShaderName + ':LAYOUT>')) != 1:
            sStr = sStr.split('#<' + sShaderName + ':LAYOUT>')[1].split('#</' 
            + sShaderName + ':LAYOUT>')[0]
            ## Add Process for .mi LAYOUT BLOCK ParamE parameter order ##
            import re
            for m in re.finditer('ParamE(.*)', sStr, re.MULTILINE):
                list=m.group(0).split(',')
                list.append(list[1])
                list.pop(1)
                sStr=sStr.replace(m.group(0),','.join(list))
            ####################################################################
            aPattern = ['\s*Tab (?P<name>.+)','\s*Group (?P<name>.+)',
            '\s*Param (?P<name>.+)',
            '\s*ParamEcombo (?P<name>.+)',
            '\s*ParamEradio (?P<name>.+)',
            '\s*EndGroup','#']
            aReplacement = [' oLayout.AddTab(\g<name>)',' oLayout.AddGroup(\g<name>)',
            ' oLayout.AddItem(\g<name>)',
            ' oLayout.AddEnumControl(\g<name>, c.siControlCombo)',
            ' oLayout.AddEnumControl(\g<name>, c.siControlRadio)',
            ' oLayout.EndGroup()','' ]
            rStr = ReplaceStr(sStr, aPattern, aReplacement)
            rStr = constStr + rStr
            print "             Defined LAYOUT!!"
            app.ExecuteScriptCode(rStr,'Python','main',[in_ctxt])
 
    #Return value is ignored as this event can not be aborted.
    return true

こんな感じで完成っ♪

この結果、ズラズラズラ…だったレイアウト

という訳で、すっきりわかり易くUIが整理できますたー(゚ー゚)!
皆さんもより良いものをより良い形で使えるように色々カスタム!カスタム!!してみてください。
ではでは (´∀`*)ノ マタ~

Shader is taken from the following Web sites.
○MyMentalray:
http://www.mymentalray.com/
Special Thanks ctrl.studio!

※免責事項※
本記事内で公開している全てのコードの有用性、安全性について、当方は一切の保証を与えるものではありません。
これらのコードを使用したことによって引き起こる直接的、間接的な損害に対し、当方は一切責任を負うものではありません。
自己責任でご使用ください

Pocket

コメント

コメントはありません

コメントフォーム

コメントは承認制ですので、即時に反映されません。ご了承ください。

*