HoudiniのPresetについて

# Merry Christmas!

HoudiniAdventCalender2019も今回を含めてあと２回になりましたね。
ここをご覧になってらっしゃる皆さんにおかれましては
毎日Houdini使ってらっしゃることと思いますが
今回は日々のHoudini生活を楽にするノードのPresetについてお話させて頂こうと思います。
(地味な話題ですみません。。。)

#### プリセット前夜
皆さんが日頃ノードを出す度に毎回毎回設定させられる項目があるはずです。
例えばTubeSOPの場合
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/05741ad3-9097-1cf3-3b76-2099935bcd1c.png)
PrimitiveTypeをPolygonにしたりEnd Capsにチェックを付けたりするのは
割と頻繁に行うと思います。
これはSphereSOPでもPrimitiveTypeをPolygonにするのは同様ですね。
毎度毎度めんどくさいですね。
でもまだこの程度なら多少我慢出来ると思います。
しかしLineSOPやBoxSOPの場合
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/477c3f55-de77-2805-7286-d5e25da5f8e0.png)
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/939d9b66-2e84-d88b-9386-68aad1ef75c5.png)
これらは右クリックメニューからCopyParameterとPasteRelativeReffrencesをやった上で
`*0.5`や`*-0.5`を付け足してあげなければならない訳で頻繁にやるにしては度し難い手数です。
極めつけはL-SystemSOPです。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/c6285175-552d-25f4-cb9f-611713912c7a.png)
パラメータお化けとも呼べるこのSOP、ユーザーに毎回膨大な式パラメータを入力させるなどかなり狂気じみた仕様になっており正気の沙汰ではありません。
その為かこのSOPにはデフォルトでプリセットが大量に用意されています。
上の歯車アイコンを押すと出るメニューの中からいろいろ選べる様になっているのですが正直どれもあまり実用に耐えるものでは無いものばかりです。
学術的なサイトで幾何学的な表現を行うための式が紹介されたりしていますが具象を表現したい商業主義的な我々にとってはそんなことよりそれっぽい木を今すぐくれという気持ちでいっぱいなのですが世の中そんなには甘くないのです。
半ばL-Systemの愚痴みたいになってしまいましたがこれはこれで
多彩な表現が出来る良いSOPだと思います。

#### プリセットを使おう
そこで何度も同じパラメータを入力しなくても良い様に今選択しているSOPの全パラメータをプリセットとして登録出来る仕組みがありますのでそれを利用しましょう。
やり方はとても簡単でシンプルです。
上の歯車アイコンから**Save as Permanent Default**を行うだけです。
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/80ddaace-8709-ddca-77a4-9756bdd8ec70.png)
すると登録されたパラメータでSOPが生成される様になります。
プリセットのバリエーションを持たせたい場合は**Save Preset...**で何種類も自分の好きなパラメータを持つことが出来ます。
自分で作ったパラメータは歯車アイコンメニューの一番下にリスト表示されます。
パラメータにアニメーションキーを打っていた場合それも保持されます。

#### プリセットを定義するものはどこにある？
**$HOUDINI_USER_PREF_DIR**に保存した場合だと保存場所は
`C:\Users\(ユーザー名)\Documents\houdini(バージョン)\presets\`
になります。
そこにSopというフォルダが作られ**Sop名.idx**という名前のファイルが出来ます。
それがプリセットの設定が記述されているファイルです。

#### プリセットを外部から編集したい
残念ながらテキストエディタでidxファイルを編集すると壊れて読み込まれなくなります。
バイナリエディタで編集しても同様です。

`C:\Program Files\Side Effects Software\Houdini(バージョン)\bin\hidx.exe`を使ってidxファイルをプリセット毎に編集可能なテキストファイルに分解して編集することが出来ます。プリセットのリネームや値の編集なども出来ます。
`hidx.exe`はコマンドラインツールなのでHoudiniの中からだとPythonを
使って呼び出すのが楽です。
使い方は引数を指定せずに実行してみると分かります。

```
c:\Program Files\Side Effects Software\Houdini 18.0.315\bin>hidx
Usage: hidx [-B] IndexFile
        Lists all sections contained in the specified index.
        If the -B option is specified, only the names of
        each section are displayed. Otherwise more detailed
        information for each section is given.

Usage: hidx -x DestDir IndexFile
        Expands the index into a directory.

Usage: hidx -c SrcDir IndexFile
        Creates a new index by collapsing together the
        external files listed in the source directory. This
        directory should match what is generated by this
        application using the -x option.
```

-xで展開、-cで結合となっています。
Houdini上で選択したノードのプリセットを展開したければ下記の様なPythonコードを書けば可能です。

```
import os
sel = hou.selectedNodes()[0].type().name()
hfs = hou.getenv('HFS')
home = hou.getenv('HOUDINI_USER_PREF_DIR')

hidx = os.path.join( hfs, 'bin','hidx.exe')
outputDir = os.path.join(home , 'presets' )
path = os.path.join(outputDir,'Sop' )
idx = sel + '.idx'
idxFile = os.path.join(path,idx)
os.chdir(path)
command = '{0} -x "{1}" "{2}"'.format( hidx, outputDir, idxFile )
command = command.replace('/','\\')
os.system(command)
```
ここでは作業用のフォルダは一つ上のフォルダにしてあります。
展開されたファイルは
![2019-12-18 (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/153910/6dc70cf9-ac49-36c3-4c84-3c57f96b36d1.png)

この様な形で生成されます。
中身を見てみると

```
#PSI_PRESET
version 2.0a
opvalues
{
version 0.8
type	[ 0	locks=0 ]	(	"poly"	)
surftype	[ 0	locks=0 ]	(	"quads"	)
orient	[ 0	locks=0 ]	(	"y"	)
cap	[ 0	locks=0 ]	(	"on"	)
consolidatepts	[ 0	locks=0 ]	(	"on"	)
vertexnormals	[ 0	locks=0 ]	(	"off"	)
t	[ 0	locks=0 ]	(	0	0	0	)
r	[ 0	locks=0 ]	(	0	0	0	)
rad	[ 0	locks=0 ]	(	0	1	)
radscale	[ 0	locks=0 ]	(	2.5	)
height	[ 0	locks=0 ]	(	1	)
rows	[ 0	locks=0 ]	(	2	)
cols	[ 0	locks=0 ]	(	12	)
orderu	[ 0	locks=0 ]	(	4	)
orderv	[ 0	locks=0 ]	(	2	)
imperfect	[ 0	locks=0 ]	(	"on"	)
}

```
という様な形でパラメータと値の組み合わせが記述されているのが分かります。
いろいろ編集したりバリエーションをPythonで増やしたり出来ますのでひとしきりやりたいことをやり終えたら先程のhidxの-cオプションを使ってidxに戻してあげましょう


#### バージョンをまたいだプリセットの引っ越し
**presets**のフォルダをコピーしてあげれば良いでしょう


#### Presetを指定してノードを呼び出す
まだプリセットを設定するコマンドはPython化されておらずHSCRIPTを
使用するしかない様です。
HSCRIPTでのコマンドは**oppresetload**です。
Pythonでは以下の様に記述してノードを作成しプリセットを適用します。

```
b = geo.createNode('box','hako')
b.setDisplayFlag(1)
b.setSelected(1)
cmd = "oppresetload %s %s" % (b.path(), 'top' )
hou.hscript(cmd)
```

#### HDAのプリセット
通常のノードと同様にプリセットを追加出来ます。

#### 消えたパラメータ、増えたパラメータの扱い
HDAを作っているとパラメータを増やしたり減らしたりする事があります。
元々あったパラメータが減っても減らしたタイミングの値が引き継がれるだけで特に問題無くプリセットは動作します。
消したパラメータを元に戻しても保存されたファイルは別にあるので元通りに正しく動作します。
元々無かったパラメータが増えた場合もプリセットを変更してもデフォルト値のまま動作します。
プリセット情報が保存されたidxはHDAとは独立している為この様な挙動になるものと思われます。
長時間かけて調整したパラメータはプリセットに保存しておくと良いでしょう。
変更したものをちょっと変えて比較したい場合などにも有効です。

#### Presetの共有方法
HDAは環境変数**HOUDINI_OTLSCAN_PATH**でパスを指定すれば共有出来ます。
ではそのHDAのPresetはどうすれば共通の資産として使えるのでしょうか？
~~実は仕組みとしては整ってはいない状態なので$HOUDINI_USER_PREF_DIRに各自でpresetsフォルダを
コピーして使う様な運用しか今の所ないでしょう。~~
<font color="#ff0000">
**2019/12/31追記**</font>
Twitterで @d658t さんからご指摘を頂きました。
<blockquote class="twitter-tweet" lang="ja"><a href="https://twitter.com/d658t/status/1209696164204859392">環境変数にHOUDINI_PATHもしくはHSITEを設定していれば共有も出来ました。</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
**環境変数にHOUDINI_PATHもしくはHSITEを設定していれば共有も出来る**のだそうです。
ドキュメントに見当たらなかったので諦めていました。
@d658t さん情報共有の方ありがとうございました！

#### まとめ
いちいちHDA化するまでも無いけど毎回手で入力するのも面倒なものにはPresetがかなり効きます。手作業を減らしましょう。

Houdiniはパラメータが命のソフトですのでパラメータの扱いを自由自在に扱える様になっておく＝Presetを自由に扱える様になることで作業の効率をかなり上げていくことが出来ます。