HoudiniのParameter Interfaceで使えるPython②

この記事は[Houdini Advent Calender 2018](https://qiita.com/advent-calendar/2018/houdini)の24日目の記事で
15日目の記事の続きになります。　https://qiita.com/yuya_torii/items/9ae1248380c47b79efa3

前回の記事で、次は**レイアウトをPythonで保存して複数のHDAで使い回す方法** を紹介しますと予告していたのですが
21日目の@shun-tumnoriさんによる[ノード作成時に独自パラメターを追加する方法](https://qiita.com/shun-tsumori/items/f8d566864feee987ccae)という記事で紹介されている
「asCodeで関数として書き出し、OnCreateイベントで読み込む」というのがまさしく自分が紹介したい方法でした！
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/2404275b-522b-0d6e-755f-ff13afeb3221.jpeg" width=720>
自分もディスパッチャー用の拡張に使ったりしていますが
こんな感じで、**数が多くて階層が複雑でも、ExpressionやHide When〜などのイベント含めて丸ごと書き出せる**ので便利です。
（手打ちで書いたことがある人は辛さがわかるハズ・・！）

というわけで、今回も引き続き**ParameterInterfaceで使えるPython**の話で
**個人的によく使う組み合わせ**などを紹介していこうと思います。

### OrderdMenu + CallbackScript
各ParameterにCallbackScriptが仕込める事を前回紹介しましたが、
**OrderdMenu**では **Menuを変更する度にCallbackScriptが実行** されます。
この時**kwargs**の**script_value**というキーに、**選択中のmenuのtokenが入ってます**ので
こんな感じに書いておくと、OrderdMenuの項目に応じた処理が書けたりします
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/b5aa3ab1-15bf-88c0-4176-a67377c21781.png" width=720>
これ、完全に**普段PySideでUIを作ってる人向けの例え**なんですが
**QComboBox の currentIndexChanged()** がHoudiniの**CallbackScript**にあたり
**currentText()**や**currentItem()**の代わりに、**kwargs["script_value"]を使う**、という感じです
(HoudiniでHDA作りを頼まれたTD/TAさん、参考にして下さい！)

kwargsの中身については、前回もご紹介した[こちら](http://www.sidefx.com/docs/houdini/hom/locations.html#parameter_callback_scripts)にかかれています

OrderdMenuを使ったHDA,処理の分岐に関しては、個人的にかなり使うネタなのですが
これだけではピンとこないと思うのでもう少しサンプルを紹介してみます

### OrderdMenu + CallbackScript + Error SOP 

「OrderdMenuで選択した環境変数が定義済みでなければエラーを返す」というのを作ってみます
まずは、こんな感じで任意の環境変数を選択できるOrderdMenuを作っておきます。
あとで書きますが、callbackには先程のようにkwargsが渡るようにしておきます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/f151b0aa-b92c-c178-7e01-79871592cd2e.png" width=720>
エラーに関しては、**error sop**を使います
こんな感じで用意しましょう。
ちなみに、Report This Errorを、HDAにenv_errorというparameterを作ってそちらにリンクしてありますが
汎用性を高めるためにそうしてあるだけなので、必ず必要な処理では無いです。
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/3f920714-f13b-5162-c9aa-626c4374fd7a.png" width=720>
OrderdMenuとError SOPが用意出来たら、PythonModuleに以下のような処理を書きます

```python
def envCheck(kwargs):
    node = kwargs["node"] # 自身のノードオブジェクトを取り出す
    token = kwargs["script_value"] # Orderd MenuのTokenを取り出す
    
    if hou.expandString(token): # tokenが存在する環境変数か判定
        node.parm("env_error").set(0)
    else:
        node.parm("env_error").set(1)
```

これで、定義されていない環境変数が選択された場合、エラーが出るHDA、が作れました
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/4d13c7ba-72c9-8d98-41ff-2045a36627da.png" width=1024>

この例で言えば、**キャッシュツールの書き出しに必要な環境が正しくセットされているか？**とか
処理を変えて、**Inputされている内容と、選択しているMenuの組み合わせがあっているか？**　など
OrderdMenu + CallbackScript + Error Sop　の組み合わせ、個人的によく使うので紹介しました。




###  + - ボタン
次に、**+-ボタン**の作り方について紹介します
何それ？　って感じだと思いますが・・・個人的にはこれは**Houdini標準でついて欲しい！**そんなParameterです
サクっと説明します
まず、IntergerやFloatのParameterを作った時、こんな感じで自動でFieldとSliderの組み合わせになりますが
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/4a0b89c7-a626-af2f-75dd-6a9d6bcd4a51.png" width=720>
コレ、Houdiniお馴染みの**MMB＋ドラッグ**で値が変えられるのは便利なんですが
**ぴったり正確な値を入れるのが難しくないですか？**　**１動かしたいのに２〜３動いてしまったり・・・しませんか？**
よく、Versionやtakeの入力にコレを使ってるHDAを見るのですが・・・自分は結局数字キーで**直接入力**してしまいます。
ではどうするのが望みかというと、こんな感じになって欲しいと思っています。
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/12d17de9-76e2-6969-a204-2b3759cfcc99.png" width=720>
たぶん見た目通りでわかって頂けると思うのですが、ボタンをポチポチ押すと数字が１つずつ上下する。そんな仕組みです。

作り方を解説します（といっても、新しい知識は必要ありません）

まず、VersionやTakeなどのParameterはStringで用意します。
+ -はButtonですが、CallbackSciprtに以下のように書いておきます。
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/76d8383e-f6ca-eafc-a5e0-8950e3e08207.png" width=1024>
はい、もうこれで想像ついたと思いますが
pythom moduleにこのように書く、それだけです！

```python
def count(parm_name, num): # 変えたいParameterの名前とカウントしたい数（増やすなら１、減らすなら-1)を与える
    parm = hou.pwd().parm(parm_name)
    cur_value = parm.eval()
    next_value = int(cur_value) + num
    clamp_value = max(min(999, cur_value),1) # 最大９９９、最小１でClamp
    parm.set(str(clamp_value).zfill(len(cur_value))) # 桁を揃える

```
最大値や桁数は任意に変更して下さい。
自分の場合は、Versionが上がったらTakeは初期化されるように
少し処理を加えたりしています

```python 
def count(parm_name, num, reset_parm_name=None):
    parm = hou.pwd().parm(parm_name)
    cur_value = parm.eval()
    next_value = int(cur_value) + num
    clamp_value = max(min(999, cur_value),1)
    parm.set(str(clamp_value).zfill(len(cur_value)))
    if reset_parm_name:
        hou.pwd().parm(reset_parm_name).set("01")
```
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/9a2fb9d3-ad8f-000f-c07c-afc486aa9a48.png" width=1024>

＋ーボタンに関しては以上です。
画像を見ていて気になった人も居ると思いますが、ボタンを並べるとあんまり見た目が綺麗に揃わないんですよね
ぜひ標準で＋ーできるボタン、もしくはQtにあるこんなやつ、つけて欲しいです。SideFX様・・
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/d79bac65-2423-6d5a-5978-50e14e766d11.png" width=360>


### Default Value

はい、正直あまりネタが浮かば無いので、**ParameterのDefaultValueにHscriptやPython入れる時のこと**について
少し解説しようかな、と思います。
default Valueに関しては、ParameterDescriptionのこちらにありますが
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/8c051f1e-3b2b-c2c1-6e56-03f44ace4bda.png" width=1024>
例えば、環境変数の**HIPNAME**と**USER**を繋いだ文字をデフォルトにしておきたい、とかいうケースがあったとして
こういう設定をしている人をたまに見かけます
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/820735a5-8d27-78bc-434a-d54003a5e1c6.png" width=720>
これ、間違いでは無いのですが、ノードを作った時、こういう風に表示されます
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/95772c8c-fbf3-1cc2-8245-e0efa04a8484.png" width=720>
普通、**ParameterにExpression書くときはこうする**と思うので、**普通じゃん！と思うかもしれません** が..!
これ、**LabelのところをMMBクリックしないと結果が表示されません**よね。こんな風に
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/9245a392-92da-d0a1-4231-20660e127cef.png" width=720>
とても細かい事なんですが、これってアーティストにとって**使いづらい（見づらい）**と思いませんか？

実はこれ、既にあるParameterに対してExpressionを書くときは仕方ないと思いますが
**Default Valueを設定する場合はこれを美しく回避する方法がある**んです
それがコレです
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/78543a5f-e59e-2f4a-0066-e0d6083824c5.png" width=720>
**電卓みたいなアイコンのところをクリックして、HScriptに変える**です
いや当たり前でしょ！っていう人が多いとは思いますが
HScriptに変えた場合、Expressionを**｀（シングルクォーテーション）で囲う必要が無くなります** というか囲うとエラーになるので
この場合であれば ```$HIPNAME + "_" + $USER```　と、囲わずに書くのが正しくなります。
これが間違えやすいのでは無いかと思っていて、たぶんエラーになるのでそのままにしてる人が居るのでは・・？と思っています
正しく設定すれば、ノード作成時に、MMBクリックしなくてもこのように表示されます
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/ec7ed8d2-13e9-5fd6-562f-2e1ae5b84d1c.png" width=720>
ハイライトされて、Expressionが入っていると明示された上で結果のみ表示されます
これはPythonでも同じで、Pythonを書く場合は先ほどの電卓マークをPythonのマークにするだけです
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/6231a8c5-2b5c-92d6-d122-d74a620f16d3.png" width=1024>
特に、長い文字列を生成するときはPythonのほうが便利なので、個人的にはPythonもよく使います。

ちなみに、これはCallBackScriptも一緒ですが、あらかじめ作っておいたModuleから関数を呼びたいときは
<img src="https://qiita-image-store.s3.amazonaws.com/0/153791/f1ba8c1d-0965-eede-fba1-72689bbfc06d.png" width=480>
という感じで、```__import__```を使えば動的にModuleを読んで関数を使ったりできます


以上

ちょっと地味な内容だったかもしれませんが、ParameterIntafaceで使えるPythonの話でした


ご質問、ご依頼などあればお気軽にどうぞ
toriivfx@gmail.com