Instancerをフローに乗せるためにいろいろ調べてみた結果のメモ
メモっておかないとすぐ忘れるので。
Houdini 19.5.534でテスト。
- Instancerメモ
- 複数ジオメトリを1つのUSDで書き出す
- ジオメトリの読み込み
- マッチングパターン
- マテリアルアサイン
- ファイルサイズ
- SOPとUSD Pointどっちがいいか?
- Render Scene USDに書き込みたくない場合
- USDのPointにInstanceしたものがRender Scene USDに書き込まれない(動かない)
- Index順をSOPに合わせる
- nameに使用したいアトリビュートを書き出す
- Stage上でTransform Piecesをする
Instancerメモ
- Location PrimitiveやPrototype Sourceの指定は積極的にマッチングパターンを使用しないとミスが起きる
- SOP上(USD内の)のN,up,orient,pscale,scaleを認識する。
- 各種アトリビュートをInstancerがUSD用のorientarions,scales,positionsに変換する。
- 基本的にレンダリング時に変換結果がRender Scene USDに配列情報で書き込まれ、肥大化する傾向にある。どうもこれは回避できない。(Configure Layer等でSave Layer Pathをしない場合)
- USDのPointを使用した場合、生成されるアトリビュートにタイムサンプルがないため、Render Scene USDで書き出した際に動かない。
- Indexは自然順でソートされていないため、SOP上のIndexとずれることがある。
- USD Pointの場合は、Nameアトリビュートを別のアトリビュート名にしないとPrimitive Pathになってしまう。
- USD Pointの場合は、USD Export時にUSD Custom Attributeでnameにしたいものを指定しないと書き出されない。
- Lightのインスタンスの場合はInternal / External SOPで、MethodがReference, Inherit, Specializeのどれかである必要がある。
- Lightのインスタンス時はSOP上のCdをライトの色として認識する。
複数ジオメトリを1つのUSDで書き出す
一度Assembleし、USD Export時のPacked PrimitivesでCreate Xformsにすると簡単に出せる。
Stage上だとこんな感じ。
ジオメトリの読み込み
Add Variant等を使用しなくてもMergeで繋いだものをぶっ刺してもPrototype Primitiveとして読みこめる。
もちろんUSD的には~ということもあるが、後述するUSDとSOPでIndexがずれる問題があるので、
回避するためにnameを直指定したい場合などにAdd Variantを経由するとnameの指定がとてもめんどくさい。ちゃんとしたフローを整えてアセットを読み込まないのであれば、Mergeでも良いんじゃないかと思う。
マッチングパターン
手入力は事故が起きるので、デフォルトを書き換えたほうが良い。Prototype Primitivesの方は、アセットの使用に則って%highest
や%kind:assembly
なども良いと思う。
マテリアルアサイン
アサインする際の仕組みに注意。(以下はPoint Instancerの場合)
先にアサインする場合
以下の画像を参考に。赤枠の方はマテリアルがちゃんと継承される。
なぜかというと、Scene Graph Tree上で以下画像赤枠がInstanceに使用されるので、その階層以下にあるマテリアルも同時に継承される。
右側は階層が並列になっているのでマテリアルが継承がおかしくなる。
あとでアサインする場合
Prototypes階層下にあるジオメトリにアサインする。
ファイルサイズ
Location SourceがInternal / External SOPの場合(SOPを経由している)と、一度PointをUSDに書き出してインスタンスした場合
どちらもちゃんと書き出せていればファイルサイズは変わらない。ただし、SOPを経由する場合は使用していないアトリビュート(例えばスケールしてない場合とか)はアトリビュートを生成しないのでその分ファイルサイズが小さくなる。
USD Pointの場合はその部分を丁寧に処理してあげたほうが良い。
参考までに10万ポイントでのファイルサイズ比較
ファイル | usda | usdc(usd) |
---|---|---|
SOPからのpoint | 1.7GB | 164.8MB |
レンダーシーンUSD | 917.2MB | 201.2MB |
レンダーシーンUSD(スケールなし) | 862.1MB | 82.4MB |
SOPとUSD Pointどっちがいいか?
SOPの方が手間が少し少なくセットアップを組める印象。
ただし、USD Pointの場合はStage上からPointをUnloadすることによって、一度設定した後はレンダリング時以外で大量のインスタンスの計算をしないというのが手軽にできる。
SOPでももちろんできるが一度SOP階層行ったりして少し手間。
中間キャッシュを取る場合もusdaでとらなければファイルサイズはUSD Pointのが少ない。
Render Scene USDに書き込みたくない場合
必ず移動回転などの情報が配列で記録されるのでそのままだとRender Scene USDが肥大化する。
特にusdaでRender Scene USDを記録したい場合はファイルサイズの肥大化が致命的。
その場合はConfigure LayerのSave Layer PathでInstancerの結果だけusdcで保存すればファイルサイズが小さくなる。
もしくは一度手動でUSDとして書き出して再度読み込んでレンダーシーンを作成する。
USDのPointにInstanceしたものがRender Scene USDに書き込まれない(動かない)
以下画像のような構成の場合、USD ROPにインスタンサーの結果が書き込まれない。(※ローカル上では動いて見える)
Modify Point Instancesで回避
これを回避するには、Modify Point Instancesノードを以下のような設定でInstancer後に使用する。(Point InstancerはInstancer名+[*])
VEXで回避
もしくは、以下VEXで再度上書きすると回避できる。ただしこの場合は存在しない値などがあった場合の回避処理なども入れないとファイルサイズの肥大化なども招くので注意。
なぜこの現象が起きるのかというと、USD Pointに対してインスタンスした場合はorientations,scales,positionsにタイムサンプルがつかない(連続したアニメーションと認識されていない)
※緑色がタイムサンプルあり、水色がなし。アニメーションしているものは緑色である必要がある。
Index順をSOPに合わせる
Prototype Primitivesに読まれた順=Indexなので、Scene Graph Tree上は自然順でソートされていてもExpressionでの読み込み後にIndex順がずれる。
このため、数字で2桁に到達する場合は0,1,10,2,3...のようになるので末尾に英語でA,B,C,Dのほうが良い。2桁に到達しないなら問題ない。
nameに使用したいアトリビュートを書き出す
別途書き出して認識させたい場合はUSD Custom Attributeで指定する。RBD Material Fractureなどで生成される値がpiece-0-0のようになるが、USDのPrimitive Pathにはハイフン(-)は使えないのでアンダースコア(_)などに直しておく必要がある。
Stage上でTransform Piecesをする
意味あるのかって言われたらジオメトリとPoint別で出せていいかも。くらい。正直ポイントをSOPで読んだ方が早いし楽。
以下のようなシーンで一度Transform Piecesを使用する。
この際に左側のハイポリも一度Pack状態にしておく。
各破片の処理
ハイポリをそのまま以下の処理をした後に複数ジオメトリを1つのUSDで書き出す
と同じ方法で書き出す。
ポイントの処理
一度Transform Piecesをした後に以下VEXでorientとscaleを取り出し、PointにPromoteする。
matrix3 trans = primintrinsic(0, "transform", @primnum); vector cross = normalize(set(trans.xx,trans.xy,trans.xz)); vector up = normalize(set(trans.yx,trans.yy,trans.yz)); vector normal = normalize(set(trans.zx,trans.zy,trans.zz)); matrix3 rotM = set(cross, up, normal); matrix3 scaleM = trans * invert(rotM); @scale = set(scaleM.xx, scaleM.yy, scaleM.zz); p@orient = quaternion(maketransform(normal, up));
各破片のnameを別のアトリビュート名にし、不要なものを削除。(そのままだとStage上でPrimitive Pathになってしまうため)
そのままだと作成したname用のアトリビュートは認識されないので、認識できるように以下設定をして書き出す。
Stage上の設定
画像のように組む。
InstancerでPrototype IndexをName Attributeにし、Name Attributeを先ほど作成したnameようのものにする。