kick the base

Houdiniと、CG技術と、日々のこと。

Houdini: 裏面ポリゴンを自動反転するシステムをつくった話 - 後編

今回は前回に引き続き裏面ポリゴンを自動反転する仕組みをつくった話についてです。

  • システム作成の背景
  • そもそも裏面ポリゴンとはなにか
  • 裏と表、どう判定すればいいのか

ここまでは前回お話したので、今回は作成したツールを拡張して最終形態にブラッシュアップしましょう。

具体的にはこの画像のように面法線がバラバラでも対応できるようにしたい!ということです。(ついでにアニメーションしていても動作するようにします)

f:id:kickbase:20210403202629p:plain

これら全部に対して裏面ポリゴンがキレイに無くなってる状態を目指します。

それでは行ってみましょう。

目次

データ配布

記事で使用したシーンはこちらからダウンロードできます。

  • Windows10
  • Houdini 18.5.408

手を動かす前に

例のごとくHoudiniを起動する前になぜ現状では対応できないか、またどうすれば対応できるようになるのかについて思いを馳せましょう。

現在のシステムの課題

前回作ったシステムではとある方向(面法線)その逆向きの方向(面法線)のふたつだけに対応し、それらの数が少ない方を反転させるという仕組みを使っていました。

この方法も悪くはないのですが、本記事の最初に貼ったブタさんのように、それぞれの面が色んな方向を向いているものには対応できません。つまりこのシステムは面法線が真逆のものしか使えないということになります。

対応したいもの

理想は高く、下記を全部クリアできるものにしましょう。

  • 面がどんな方向を向いていてもOK
  • アニメーションしていても対応できる
  • ジオメトリのトポロジーは制限なし

さあ、どうする?

「対応したいもの」を考えると割と手詰まりな感じがしますね。

「どんな方向」でも「どんなアニメーションをしていて」も「トポロジーは制限なし」など、広すぎる範囲をすべてカバーする仕組みを漠然と考えるのはかなり難しいことです。

今手元にあるシステムは反対向きのふたつの面法線にしか対応していないんでしたね。これを「無数の方向に対応する」のは骨が折れそうです。

逆に考えるんだ
「立体を平面にすればいいさ」
と考えるんだ

おや。どこかからありがたいお言葉が聞こえてきました。

3次元のデータを2次元にマッピングする技術、僕たちは日常的に使っているんです。それを利用してやれば良い。

そう、それはUV座標です。

UV座標はアジの開きと評されるようにジオメトリをポリゴンの島ごとに分け、プレパラートにペタペタ貼り付けたような状態になります。つまりポリゴンが一枚の平面上に並ぶわけです。この状態なら面法線は反対向きのふたつの方向に絞られる。

Houdiniに慣れていない方は「UVが2次元なのはわかったけどそれが何?」という気持ちかもしれませんが、Houdinistにとってはもう答えが出たのと同じことです。なぜならUV空間をXYZ座標に持ってくることなど朝飯前だからです。

さあ、あとは手を動かすだけです。やっていきましょう。

ツールをブラッシュアップしよう

UVを利用してポイントを平面上に展開する

f:id:kickbase:20210407002548p:plain XYZ空間でUV座標を利用するために、まずはUVシームでポイントを切り離しましょう。UVの切れ目ではひとつのポイントを複数の頂点が共有しているためです。

ここらへんのお話は以前の記事に詳しく書いておきました。

f:id:kickbase:20210407002845p:plain 最後に元の形状を復元するために現在のポイント位置をrestアトリビュートに保持します。使うノードはもちろんRestPositionSOPです。

f:id:kickbase:20210407002951p:plain 頂点に付与されていたuvアトリビュートをポイントに移植します。各ポイントを自身のアトリビュートを参照して移動させるためです。

f:id:kickbase:20210407003118p:plain @P = @uv

たった一行のコードでUV座標をポイントの位置に与えることができました。便利ですね!

参考までにもとの位置情報@restとUV座標@uvを行き来するようなアニメーションを作ってみました。「UVといえばテクスチャ用!」と固く考えず、様々なケースで役立てましょう。

裏面ポリゴンの反転

ここは今まで作ったシステムをまんま利用します。上記の手順で面法線が反対向きのふたつの方向に絞らているからです。

全く同じシステムなので解説は割愛し、スクリーンショットのみ貼っておきます。

f:id:kickbase:20210407003308p:plain

f:id:kickbase:20210407003609p:plain

f:id:kickbase:20210407003623p:plain

f:id:kickbase:20210407003639p:plain

無事裏面ポリゴンを反転できました!

形状をもとに戻す

難しいことはありません。たった2ステップです。

f:id:kickbase:20210407003713p:plain @P = @rest

下準備で保持していたポイントの位置を上記コードで戻してあげます。簡潔でいいですね。

f:id:kickbase:20210407003827p:plain 切り離したシームをくっつけるためFuseSOPを使用しましょう。

完成です!!

検証

最初の要望を思い出してみましょう。

  1. 面がどんな方向を向いていてもOK
  2. アニメーションしていても対応できる
  3. ジオメトリのトポロジーは制限なし

今回のシステムが上記を満たしているかテストするのはしんどそうですね。

しかしよくよく考えてみると、UV展開後であれば1.面がどんな方向を向いていても平面上に並ぶため表裏の判定は可能ですし、2. アニメーションの前にUV展開が終わっていればどんな激しい動きをさせても良いですよね。*1

また3. ジオメトリのトポロジーについてもUV展開さえできればいいので、閉じていても開いていても凹凸もNゴンも、ポリゴンの交差すら関係ありません。

十分なテストを行う必要もなく、理論上問題がないということがわかりますね。素晴らしい!

次元を上げるのではなく、次元を下げる方向で今まで作った資産を利用する。今回はそんな実装を行ったことになります。

別解

これにて裏面ポリゴンを自動反転するシステムについては完成です。が、UVがないモデルでも使いたい!ということで別解をひとつ用意しました。制限もあるし、あまりイケてない実装なのですが様々な角度から物事を捉えるのは勉強になるものです。別記事にしようかなとも思ったのですがネットワークを追えばわかるかなということで解説は割愛です。以下に簡単に要点だけまとめます。

  1. 面法線をリセットする
  2. 面の中心座標にポイントを生成、先程作った面法線をポイントアトリビュートとして移植
  3. ポイントノーマル方向に少し押し出す
  4. もとのジオメトリ(作例ではブタさん)をボリューム化し、ポイントがその内部にあるか外部にあるか判定する
  5. 「ポイントが内部に移動したものはポリゴンが内側向きだった」という事がわかるので、該当の面を反転させる

ボリュームを利用するため閉じたジオメトリでないとうまく行きませんし、ポイント移動やAttribute Transfarも距離ベースなのでやりすぎるとジオメトリを突き抜けたりしちゃいます。

というわけでUVを使った方法のほうが汎用性が高そうですね。

まとめ

ポリゴンの表裏の判定にUVを使うなんて、そんなトンチ思いつくかよ!(怒)と思う方もおられるかと思いますが、その誤解はここで解いておきましょう。

このUVを利用するというのは天からのインスピレーションを待ったわけではなく、Houdinistにとっては普通の、再現性のある考え方なのです。

簡単に言えば「使いやすい場所で処理をして、後で戻す」この理念に基づき、「使えるものは何でも使え」という精神でモノづくりをしていると自然と身についてくる技術なのです。

今回はUVを使いましたが、ポイント番号を使ってもいいし距離を使ってもいい。面積を使ってもいいしカラーを使ってもいい。そんな思考回路の積み重ねが柔軟な解法を生んでくれます。

イメージとしてはサンドウィッチを作ったあとに残るパンの耳。あれを揚げて砂糖をまぶしてラスクにすると二度美味しい!こんな感覚といいましょうか。

みなさんも使えるものは何でも使って、よきHoudiniライフをお楽しみください。

参考サイト

本記事で登場したエクスプレッション、ポイントと頂点の違い、理解のサポートになりそうな記事などを記載しておきます。

*1:プリミティブの総数が変化するような状況はそもそも表裏の判定というシステムの対象外です