November 12, 2016
マンガじゃない Houdini チュートリアル ーーParmTemplateーーー
前回はPySideを使ってパラメータを挿入するスクリプトを作りましたが、それを事を踏まえて指定のパラメータをレイアウトの中で上下させるスクリプトを作ってみました。
今回はPySideと言うよりはPythonによるパラメータのレイアウト書式であるparmTemplateについて説明してみたいと思います。少しだけね。

今回はPySideと言うよりはPythonによるパラメータのレイアウト書式であるparmTemplateについて説明してみたいと思います。少しだけね。
先ず始めにこんなパラメータが在ったとします。

この全体のレイアウトに関しては、ノードから.parmTemplateGroup()から取り出せます。
例えばAのテンプレートを取り出したい場合、Aは3番目のパラメータでリストは0からなので
parmA = nodeTemp.parmTemplates()[2]
という事になります。
別にテンプレートグループからたどらなくても直接これでもいけます。
parmA = hou.parm('/obj/geo1/nullA/a').parmTemplate()
もしくはテンプレートグループからfindで名前検索も出来ます。これも同じです。
parmA = nodeTemp.find("a")
そして前回のようにこのAの下にパラメータを作りたい場合。
newParm = hou.FloatParmTemplate("newParm", "NewParm", 1)
こんな感じで新しいパラメータテンプレートを作り。
nodeTemp.insertAfter(parmA,newParm)
でAの下に挿入します。これでnodeTempは更新されましたが、parmTemplateGroupはノードとレイアウトをコピーしただけであってノードのほうとの直接の互換性はないので、これを.setParmTemplateGroup()によってノードに当てはめやらないければパラメータは更新されません。
node.setParmTemplateGroup(nodeTemp)
なのでこれを走らせることで始めてノードのパラメータレイアウトが更新されます。

今回の場合をひとつ上に上げたり下に下げたりする必要があるので自分のパラメータの番号を知る必要があります。それによって指定番号のパラメータにinsertBefore()もしくはinsertAfter()を使い挿入しなおします。
自分の番号自体はfindIndices()によって探せます。
myIndex = nodeTemp.findIndices(parmA)
もしくは
myIndex = nodeTemp.findIndices(”a”)
これによって
(2,)
と返ってきます。 リストで帰ってくるのはフォルダ構造がある場合の為でこれがちょっとめんどくさいのでここでは省略。
とりあえず今回はこうしておきましょう。
myIndex = nodeTemp.findIndices(parmA)[0]
これによってひとつ下のパラメータがこのように探せます。
parmNext = nodeTemp.parmTemplates()[myIndex - 1]
なので自分自身を.remove()で一旦消して
nodeTemp.remove(parmA)
それからafter結合&更新すればひとつ下に
nodeTemp.insertAfter(parmNext,parmA)
node.setParmTemplateGroup(nodeTemp)
大まかにはこんな感じなのですがめんどくさいのはフォルダー階層。
例えばこんなパラメータがあるとして

これのDのインデックス
(4, 2, 0)
これはtemplateGroupのナンバー4のフォルダ内のナンバー2のフォルダないのナンバー0がパラメータDと言う事を意味します。
フォルダもparmTmplate()として取り出せるのですがフォルダの場合更にそこからparmTmplates()によって下の階層のパラメータ取り出す事が出来ます。
なのでさっきのインデックスからパラメータDを取り出すとすると
nodeTemp.parmTemplates()[4].parmTemplates()[2].parmTemplates()[0]
となりますが、
これじゃああんまりなので僕の場合は階層フォルダのリストを取り出すことにしました。
と言う感じで階層をループしてfoldersというリストが出来ます。最後の自身のパラメータをは含まないようにしています。indexcisは.findIndices()によって取り出した(4, 2, 0)の事です。
これによって
folders[-1].parmTemplates()[indecis[-1]]で自分自身の居場所が分かります。
ひとつ上の場合は
folders[-1].parmTemplates()[indecis[-1]-1]
ただ現パラメータの位置がフォルダのトップの場合はフォルダを飛び越えてそのフォルダ自身の上に生きた印尾でその場合単純に
folders[-1]
となるifによる分岐が必要です。
そうして出来たのがこれです。

と言う感じになります。
ここまでやっておいてなんですがこれが出来たからといってCGが上手くなったりとかは全くありません。
普通にEdit Parameter Interfaceを開けば良いだけの話です。
ただ仕事でアセットを提供するような立場になってくるとただのHDAだけ使うよりもスクリプトも交えて提供するほうが使用する側にフレンドリーな場合もあったりなかったりするので手数は多いに越した事はないかと。ガチガチなHDAだとかだと更新に対して軟弱だったりとか。
その辺はそれぞれのアーティストの哲学とかもあったりでいろいろ一筋縄ではいかない部分ですけど。。。
この全体のレイアウトに関しては、ノードから.parmTemplateGroup()から取り出せます。
node = hou.node('/obj/geo1/null')
nodeTemp = node.parmTemplateGroup()
それぞれのパラメータのテンプレートは.parmTemplateGroup()のparmTemplates()階層下にリストで入っています。
それぞれのパラメータのテンプレートは.parmTemplateGroup()のparmTemplates()階層下にリストで入っています。
例えばAのテンプレートを取り出したい場合、Aは3番目のパラメータでリストは0からなので
parmA = nodeTemp.parmTemplates()[2]
という事になります。
別にテンプレートグループからたどらなくても直接これでもいけます。
parmA = hou.parm('/obj/geo1/nullA/a').parmTemplate()
もしくはテンプレートグループからfindで名前検索も出来ます。これも同じです。
parmA = nodeTemp.find("a")
そして前回のようにこのAの下にパラメータを作りたい場合。
newParm = hou.FloatParmTemplate("newParm", "NewParm", 1)
こんな感じで新しいパラメータテンプレートを作り。
nodeTemp.insertAfter(parmA,newParm)
でAの下に挿入します。これでnodeTempは更新されましたが、parmTemplateGroupはノードとレイアウトをコピーしただけであってノードのほうとの直接の互換性はないので、これを.setParmTemplateGroup()によってノードに当てはめやらないければパラメータは更新されません。
node.setParmTemplateGroup(nodeTemp)
なのでこれを走らせることで始めてノードのパラメータレイアウトが更新されます。
今回の場合をひとつ上に上げたり下に下げたりする必要があるので自分のパラメータの番号を知る必要があります。それによって指定番号のパラメータにinsertBefore()もしくはinsertAfter()を使い挿入しなおします。
自分の番号自体はfindIndices()によって探せます。
myIndex = nodeTemp.findIndices(parmA)
もしくは
myIndex = nodeTemp.findIndices(”a”)
これによって
(2,)
と返ってきます。 リストで帰ってくるのはフォルダ構造がある場合の為でこれがちょっとめんどくさいのでここでは省略。
とりあえず今回はこうしておきましょう。
myIndex = nodeTemp.findIndices(parmA)[0]
これによってひとつ下のパラメータがこのように探せます。
parmNext = nodeTemp.parmTemplates()[myIndex - 1]
なので自分自身を.remove()で一旦消して
nodeTemp.remove(parmA)
それからafter結合&更新すればひとつ下に
nodeTemp.insertAfter(parmNext,parmA)
node.setParmTemplateGroup(nodeTemp)
大まかにはこんな感じなのですがめんどくさいのはフォルダー階層。
例えばこんなパラメータがあるとして
これのDのインデックス
(4, 2, 0)
これはtemplateGroupのナンバー4のフォルダ内のナンバー2のフォルダないのナンバー0がパラメータDと言う事を意味します。
フォルダもparmTmplate()として取り出せるのですがフォルダの場合更にそこからparmTmplates()によって下の階層のパラメータ取り出す事が出来ます。
なのでさっきのインデックスからパラメータDを取り出すとすると
nodeTemp.parmTemplates()[4].parmTemplates()[2].parmTemplates()[0]
となりますが、
これじゃああんまりなので僕の場合は階層フォルダのリストを取り出すことにしました。
curFolder = nodeTemp
folders = [curFolder]
for i in indexcis:
curItem = curFolder.parmTemplates()[i]
if curItem.type().name() == "Folder":
curFolder = curItem
folders.append(curItem)
と言う感じで階層をループしてfoldersというリストが出来ます。最後の自身のパラメータをは含まないようにしています。indexcisは.findIndices()によって取り出した(4, 2, 0)の事です。
これによって
folders[-1].parmTemplates()[indecis[-1]]で自分自身の居場所が分かります。
ひとつ上の場合は
folders[-1].parmTemplates()[indecis[-1]-1]
ただ現パラメータの位置がフォルダのトップの場合はフォルダを飛び越えてそのフォルダ自身の上に生きた印尾でその場合単純に
folders[-1]
となるifによる分岐が必要です。
そうして出来たのがこれです。
from PySide import QtCore from PySide import QtGui parm = kwargs["parms"][0] parmTmp = parm.parmTemplate() node = parm.node() parmGroup = node.parmTemplateGroup() class Example(QtGui.QWidget): def __init__(self): super(Example, self).__init__() self.initUI() def initUI(self): Lbox = QtGui.QVBoxLayout() mpos = QtGui.QCursor().pos() self.setGeometry(mpos.x() - 100 ,mpos.y() - 200 ,250,120) self.setWindowTitle('Parm Up & Down') self.checkBox = QtGui.QCheckBox('Keep in Current Folder', self) Lbox.addWidget(self.checkBox) upButton = QtGui.QPushButton('Up', self) Lbox.addWidget(upButton) upButton.clicked.connect( self.upButtonPress ) downButton = QtGui.QPushButton('Down', self) Lbox.addWidget(downButton) downButton.clicked.connect( self.downButtonPress ) self.setLayout(Lbox) def HierarchyIndexies(self): return parmGroup.findIndices(parmTmp) def HierarchyFolders(self): curFolder = parmGroup parmHierarchy = [curFolder] for i in self.HierarchyIndexies(): curItem = curFolder.parmTemplates()[i] if curItem.type().name() == "Folder": curFolder = curItem parmHierarchy.append(curItem) return parmHierarchy def upButtonPress(self): index = self.HierarchyIndexies()[-1] folder = self.HierarchyFolders()[-1] if index == 0: parmNext = folder else: parmNext = folder.parmTemplates()[index-1] if not (index == 0 and self.checkBox.isChecked()): parmGroup.remove(parmTmp) parmRef = parmGroup.find(parmNext.name()) if index != 0 and parmRef.type().name() == "Folder" and not self.checkBox.isChecked(): parmGroup.appendToFolder(parmRef,parmTmp) else: parmGroup.insertBefore(parmRef,parmTmp) node.setParmTemplateGroup(parmGroup) def downButtonPress(self): index = self.HierarchyIndexies()[-1] folder = self.HierarchyFolders()[-1] folNum = len(folder.parmTemplates())-1 if index == folNum: parmNext = folder else: parmNext = folder.parmTemplates()[index+1] if not (index == folNum and self.checkBox.isChecked()): parmGroup.remove(parmTmp) parmRef = parmGroup.find(parmNext.name()) if index != folNum and parmRef.type().name() == "Folder" and not self.checkBox.isChecked(): if len(parmRef.parmTemplates()) != 0: parmGroup.insertBefore(parmRef.parmTemplates()[0],parmTmp) else: parmGroup.appendToFolder(parmRef,parmTmp) else: parmGroup.insertAfter(parmRef,parmTmp) node.setParmTemplateGroup(parmGroup) dialog = Example() dialog.show() |
と言う感じになります。
ここまでやっておいてなんですがこれが出来たからといってCGが上手くなったりとかは全くありません。
普通にEdit Parameter Interfaceを開けば良いだけの話です。
ただ仕事でアセットを提供するような立場になってくるとただのHDAだけ使うよりもスクリプトも交えて提供するほうが使用する側にフレンドリーな場合もあったりなかったりするので手数は多いに越した事はないかと。ガチガチなHDAだとかだと更新に対して軟弱だったりとか。
その辺はそれぞれのアーティストの哲学とかもあったりでいろいろ一筋縄ではいかない部分ですけど。。。