この記事は Houdini Apprentice Advent Calendar 2022 10日目の記事です。
12月に入って急に寒くなりました。在宅勤務を挟んで数日ぶりに出社しようと外に出ると、前の出社日と比較して数割増しで寒くなっているような気がします。この調子だと年内の最終出社日には体感氷点下になりそうです。
この記事では、ドット積についてお話しします。
ドット積の簡単な解説から始まり、Houdini でどのように使えるか、あるいはなぜドット積が Houdini で重要なのかを説明します。
最終的にはドット積の結果から、ラバートイに雪を降らせてみます。Houdini がホットなアドカレの季節ですから、ラバートイ君もきっと寒くはないでしょう。
ドット積の解説から
まずは方程式からです。
Va * Vb = cos(θ) * ||Va|| * ||Vb||
Va, Vb はそれぞれベクトルを意味し、特に Va は下図の緑線に該当します。
右辺について、cosθ は Va と Vb(緑と青の線)の余弦で、これにベクトルa とベクトルb のそれぞれの絶対値、すなわち線分の長さを乗算したものです。
ベクトルが正規化されると、||Va|| と ||Vb|| はそれぞれ 1 になります。
これが cosθ に乗算されるため、ベクトルが正規化されたとき、ドット積は cosθ と等しくなります。
改めて言いますが、ベクトルa とベクトルb の内積は、ベクトルが正規化されたとき、単純に cosθ に等しくなります。
θ の角度によって値が変化する様子を見ていきます。
まずは θ=0, 視覚的にはベクトルa とベクトルb が同じ位置にある場合、ドット積は1に等しくなります。
これは先述の通り、cosθ=1, ||Va||=1, ||Vb||=1 であるためです。
角度を大きくしていくと、ドット積の値はどんどん小さくなっていきます。90度に達すると 0 になります。これは cosθ=0 であるためです。
更に角度を大きくし鈍角(90度以上)になると、ドット積は負の値を取り始めます。が、さらに 180度になると -1 を取り、その先 -1 より小さくはなりません。
これは θ がベクトル間の最短角度であり、画像で言う下側が θ になるためです。
それ以降は θ が上にあったころと同じ値を取り、一周したところでまた 1に戻ります。
Houdini で何に使えるのか?
ではドット積について簡単に理解出来たところで、それが Houdini でどのように活用できるかについてお話しします。
サンプルのラバートイですが、テクスチャを削除しています。この上に雪を降らせたいとなったとき、一般的にはレイキャストを用いることもできますが、今回は代わりにドット積を使ってみます。
まず最初に、ドット積には 2つの異なるベクトル a と b が必要です。
今回は法線と Y軸をそれぞれのベクトルと考えることにします。法線と Y軸の角度の差 θ を利用して、そのドット積が 1 に等しくなる、あるいは限りなく 1 に近くなる場所を探します。
また法線が Y軸の正の方向を向いている場合と、負の方向を向いている場合とで考えます。
先ほども言ったように、互いに同じ方向を向いている場合はドット積は 1 になり、反対の方向を向いている場合は -1 になります。
これを利用して、ドット積の値の増減から、雪が積もっていく場所を決め、グラデーションできるというわけです。
実際の値のグラデーションを視覚化するために、Attribute VOP を使いました。
内部はこのようになっています。
geometryvopglobal1 で法線ベクトルを取得し、normarize2 で正規化します。
vec2 と normarize1 についても、Y軸を正規化したものです。
そして正規化したものを dotproduct に入れてドット積を計算し、fit1 を使って -1-1 の値を 0-1 にフィッチングします。これは Houdini が -1 以下の値をモノクロで表示できないためです。
その後 rainbow1 で虹色のスペクトルに変換し、Cd に出力します。
bind1 は値を可視化するものです。
dot_result がオンになれば、各ポイントでのドット積の値を確認することができます。
例えば紫の部分は法線がほぼ Y軸に沿っているので、1 に限りなく近い値になります。
逆に Y軸の負の方向を向く、つまりラバートイの腹の部分は -1 に近い値を取ります。
これで、法線と Y軸の角度の差によるカラーグラデーションができました。
実際にドット積を計算させる
新しい attribute VOP を使います。
内部はこんな感じです。
前半は既に説明したものと同じノードを使っていますが、今回は bind1 以降を新規で繋げています。compare1 の第二入力にまた別の Parameter(input2) が入っていますが、この Parameter で作った dot_threshold と dot_result を比較し、大きい方(Greater Than)を取得します。
で最後にその取ってきた値をモノクロのスペクトルにして終了です。
dot_threshold パラメータを使うとモノクロが推移します。
例えば dot_threshold=0 の場合 90度であるため、Y軸が真上にあるということを指します。
なので 90度より大きいものはすべて白で表現されます。
<dot_threshold=0.5>
<dot_threshold=0>
<dot_threshold=-0.5>
結果を視覚化しても、dot_threshold によってモノクロの境界が生まれているのが分かるはずです。
その後 scatter で白部分のポイントを抽出し、
attribute wrangle の pscale で体積を決定します。
vdb ボリュームを置き、smooth で滑らかにします。
merge の第二入力にはラバートイを入れて雪とラバートイを合体させ、FINAL とします。
dot_threshold の値を変えれば、雪の積もり具合を変えることもできます。
作業ファイルの共有はありませんしパラメータも全部は公開していませんが、Houdini でドット積が何に使えるのかご理解いただければ幸いです。
以上、軸と法線の角度の差から生まれるドット積を利用した領域分けでした。
2022/12/10
株式会社ボーンデジタル