ZBrushのスクリプト Zscriptを書いて動かす


概要

VRでモデリングしてそいつをいい感じにリトポしたりするのにZBrushを使ってるんだけど、

VR側のモデリングでかなり精度を出せるようになってきたので、ZBrushでやる作業がほぼリトポだけになってきた。


で、これをいちいちモデルの全パーツに対してやってるのがしんどくなってきたので、Zscriptを書いてZBrushの動作を自動化しようみたいなはなし。



Zscriptって何

リファレンス

http://docs.pixologic.com/user-guide/customizing-zbrush/zscripting/technical/


なんというかスクリプトで、ZBrushの動作を記述してloopとかifでサブツール(ZBrushのオブジェクト単位)に対して操作を加えることができる。

もっと簡単に言うと、ボタンを増やしてそのボタンを押したらどうなるかを作成できる


動かし方

1.ZBrush > Zscriptメニュー > Record > なんか適当に自動化したいことをする > Zscriptメニュー > End Rec で、動作内容をテキストファイルとして出力できる

その際、「初期化する?」とか聞くダイアログが出るんだけど、対象モデルを用意した上でYesとか押すと対象モデル搔き消えるんで、断固Noを押すケースの方が多いと思う。

スクリーンショット 2018-01-19 22.26.19.png

2. 1で吐き出したtxtとにらめっこしながらスクリプト(txt形式)を書く。

<このときコツというか言外の仕様がいくつかある。後述>


3.書いたスクリプトを、ZBrush > Zscriptメニュー > Load で読み込む。

このとき、UIがこんな感じになっていることを確認しとく。

スクリーンショット 2018-01-19 22.24.11.png


4.なんか実行できないエラーがあったら画面下部のところに赤く表示される。

これ困ったことにテキストではなく映像としてエラーが表示されるんで、エラー内容ググるのが大変だった。


5.実行できる場合、ボタンが画面下部のところに表示される。このボタンを押すと、Loadしたスクリプトが実行される。

スクリーンショット 2018-01-19 22.22.19.png

言外の仕様

ドキュメント見ても書いてなかったと思うんだけど次みたいな仕様があった。


・コメントで日本語を書くのはOK、ただし、Noteなどのメッセージを出す画面では英語以外表示されない

はい。

ちなみにMacroってメニューだとコードにコメントを書くこと自体が不可


・エラーにならないケースがある

どうもメッセージングみたいな挙動をしていて、

・メソッドの引数の型が合わない場合はエラー

・メソッドの引数の内容が見つからない場合はエラー


これらはちゃんとエラーになるんだけど、次のケースはエラーが出ない。

・IPressで存在しないコマンドを実行する

これが結構厄介で、ZBrush自体がRecordで記録するコマンドが間違ってるケースがちょいちょいあるみたいで、

存在しないコマンドを実行することになってしまい、これがエラーを吐かないので停止せずエライことになる。


・continueやskipみたいな概念がない

Loopっていう他言語でのforみたいなのがあるんだけど、これがifでskipしたりcontinueしたりできない。

つらい。



最低限これだけ使えれば試行錯誤できそうなコマンド


Note

[Note, "English!!! only!"]

画面上にメッセージを出す。このままだとクリックしないと消えない。今変更を加えようとしているSubToolがどれなのか、とか

そういったデバッグのための情報を知るのに重宝する。

VarDef, VarSet

[VarDef, 変数名, 初期値]

[VarSet, 変数名, 値]

変数定義と定義済み変数への値の上書きを行う。

値には数字、文字列、リスト(値 or 文字列)がある。


SubToolSelect

[SubToolSelect, 数字]

特定の番号のSubToolを選択した状態にする。後述のLoopと組み合わせると、全てのSubToolに対して何かする、みたいなのが

簡単にできる。


Loop

[Loop, 回数, 処理, インデックス変数]

回数文だけ処理を実行する。


インデックス変数は処理の中で使うことができる。例えば次のようなコードの場合、

// 場にあるSubToolの数を変数 subToolCount にセット

[VarSet, subToolCount, [SubToolGetCount]]


[Loop, subToolCount, 

// 上からn番目のツールを選択した状態にする

[SubToolSelect, [Val, n]]

,

n

]

subToolCount回数ぶん、処理 上からn番目のツールを選択した状態にする を実行する。

その際、nには0 ~ (subToolCount -1)までの数字が入る。


nを取り出すのに[Val, n] とか書かなきゃいけないのがなんともキツイが、これは有効に動作する。

これだけで場にあるすべてのSubToolを順に選択することができる。


ZBrushでは選択状態のSubToolに対して何か処理を加える、というのが根幹的な動作になっているので、

選択できさえすればあとは動作をさせればいい感じになる。


IGetTitle

[IGetTitle, Tool:Current Tool]

現在選択されているSubToolの名称を取得する。

このメソッド と 文字列を足すメソッドを組み合わせることで、順番以外の方法でSubToolを指定することが可能になる。

具体例は次。


StrMerge

[StrMerge, "Tool:Sub Tool:", #currentSubToolName]

こんな感じに書くと、変数 currentSubToolName に入っている文字列と、文字列 Tool:Sub Tool: を連結する。

例えば currentSubToolName に A とか入ってたら、Tool:Sub Tool:A が出力される。


VarSetとかと組み合わせて、Tool:Sub Tool:ツール名 みたいな文字列を変数に入れておくことができる。


これがあると、次のような動作が自動化できる。


IModGet, IModSet

[IModSet, currentSubToolPath, [IModGet, currentSubToolPath] + 32]// set visible.

名前で指定したUIのパラメータを変更する。 Getで取得、Setでセット。

例えば上のコードで、currentSubToolPathに書かれているSubToolの表示/非表示を切り替えられる。


このモード値みたいなやつはイマイチよくわかってない。書き方によっては再現性がなかったりする。

この関数では、特定のSubToolの指定を文字列で行なっているんだけれど、SubToolを文字列から指定する場合、

Tool:Sub Tool:ツール名 みたいな文字列にならないと指定できない。なぜこんな、、まあ、、、はい、、、


以上のコマンドと、あとはZscript > Record からの動作 -> サンプルコードが出てくるのでそれらを抜粋、、 をいい感じにやると、

比較的なんでも自動化できる気がする。



注意点

たいへんとっつきにくい要素がこれらだった。いまならもう怖くない、、


・Top Levelという概念

Zscriptに記述できる一番外側のブロックをTop Levelといい、UIに関係するコードや変数定義、関数定義などを記述することができる。

このレベルにダイレクトにLoopとかIfとかの処理を書くことはできない。

処理を書く場合、必ず ボタンを押したら~ みたいな関数の中に書く必要がある。



・Zscript > Record は時々嘘をつく。

例えば Record中に Tool > Geometry > Modify Topology > Delete By Symmetry とかを実行すると

[IPress,Tool:Geometry:Delete By Symmetry]


とか記録されるんだけど、これをそのままコピーしてもDelete By Symmetry は実行されない。 ええ、、、

そう、記録されたコマンドが間違っている。


正しくは、

[IPress,Tool:Geometry:Modify Topology:Delete By Symmetry]


まあ手で実行するときの階層がそうなってるんで、、まあ、、、はい、、、なんで間違うの、、、? バグ、、、?



・変数の寿命が独自

[VarDef, A, "initial"] みたいな感じで変数を初期化、

[VarSet, A, "set"] みたいな感じで変数に値を代入できるのだけれど、


VarDefはTopLevel(すべての関数の外側)にしか書けない。


loop関数の中でVarDefを使うと、挙動がおかしくなる。 具体的にはAが定義済みの場合は[VarDef, A....]は定義を上書きしないみたいだ。

なので、プログラム中で変数として使いたい値がある場合、プログラムの上の方にまとめてVarDefしておく必要がある。


もしくはダイレクトにVarSetだけ使うとか。



感想

いままでいろんな言語扱ってきたけど、そのなかでも一番辛かった。でもこれで自動化できる!! 効率最高になった。