この記事はHoudiniアドベントカレンダー2017 1日目の記事です。
Houdiniには多くの機能があり、目的に対して様々なアプローチがあります。
(そこが面白いところでもあり、難しい所なのですが。)
今回は僕がHoudiniを最初に使いだした頃に取り組んでいた「階段」をテーマに
いろんな方法で階段を作っていきます。
*hipファイル:https://drive.google.com/open?id=1cGAutLmJvjvVo4fKyvKneLq3ARVIUdiq
#「普通の階段」
利用SOP:Copy Stamp,Duplicate
階段を1段ずつ複製します。
複製はCopy StampとDuplicateどちらでも可能です。
この2つの違いはほとんどありません。duplicateのほうが
copyよりも単純なため少し早い程度の違いです。
#「らせん階段」
利用SOP:Resample,PolyFrame,Copy Stamp
lineやcurveを利用して、階段を作成します
polyframeを利用すると、簡単に法線、接線、従接線を取得できます。
法線が正しく設定されていれば、copySOPが正しい向きに階段を配置してくれます。
#「ぐにゃぐにゃ階段」
利用SOP:Divide,Foreach
階段が常に直線とは限りません。特殊な形状の階段を作るにはどうすればいいでしょうか。
上の段になるほど、横幅を縮めるstampやscaleを利用する方法もありますが、ここではdivideを利用してみます。
まず、階段にしたい形状を用意します。
Wrangleにはupvectorとpscaleのばらつきを設定します。
@up={0,1,0};
@pscale=chf("stairwidth")+rand(@ptnum);
そのあとはdivideで一度内側のエッジを全て削除します。
その直後にもう一度divide(BrickerPolygon)を行います。xとzは仮の数値として1000という大きい数値が入っています。
divide(BrickerPolygon)はバウンディングボックスの端を0として計算しているので、大きすぎる数値が入ると分割がされません。これを逆手にとってy方向のみ段差の高さで分割します。
段差別に分割されたので、段差ごとに平らにしていきます。段差1段につき1primitiveとなっているので、Foreach内でprimitiveのscaleをY座標:0にして平坦化させます。
#「岩の階段」
利用SOP:VoronoiFracture,VDB
ぐにゃぐにゃ階段の応用として、VDBを使って岩の階段を再現します。
岩は人工物ではないので、切れ目がランダムです。しかし、完全なランダムではありません。
なぜならば、人が歩きやすい階段にするために、あるルールをもって配置するからです。
では、この場合の配置ルールを想定してみます。
①1段の高さは等しい
②1段を2つに分割する必要はない
③切れ目は縦に切れている
以上のルールを実現するために、ボロノイを利用します。
ただボロノイをかけると、ボロノイっぽくなってしまうので、段差ごとにForeachをかけてseedの違うscatterを発生させます。
scatterの偏りを生じさせるために、scatter前後にZ方向の縮小をかけます。
右に行くほどscatterを行った際にZ方向の縮小が強くなっています。前段階のtransformでZ:0.5とした場合、元に戻すために後ろのtransformで1/0.5として、元の大きさに戻します。
ボロノイで縦にしすぎると岩らしさが無くなってしまうので、ちょうどいい塩梅を見つけます。
ボロノイの注意点として、gridのように高さのない面の場合はそのまま切れるのですが
高さのある面の場合は、backfaceにサーフェスができることがあります。
ですので、一度上を向いているサーフェスだけ抽出します。
抽出するためには法線が上に向いているかを確かめればよいので、法線と{0,1,0}の内積をとります。
上を向いている場合は-1、下を向いている場合は1になっています。
if(dot(@N,{0,1,0})<-0.5){
removeprim(0,@primnum,1);
}
下向きのbackfaceは一度削除します。
次に岩の角を丸める処理を追加します。今回は、resampleを利用した後にrelaxをかけて丸みを追加します。
そして、polyextrudeを行った後、groupを利用して70度以上のedgeを取得します。そのgroupにpolybevelを
加えます。(なんとなく岩っぽく変形した?)駄目押しで、一度ポリゴンからVDBの変換を行います。
これらの一連の処理を岩1個ずつforeachで回します。本当は重くなるので、やりたくないのですが、
VDBの解像度をかなり上げないと岩同士がくっついてしまいます。
*VDBSmoothで丸みをつけることや、VDBcombineのSDF~で岩の傷をランダムに与えることも可能です。
問題ないレベルになったら、converVDBでポリゴンに戻します。
最後はポリゴン数を抑えて、autoUVを適用します。
#「エスカレーター」
利用SOP:Wrangle(UVアニメーション)
エスカレーターは足場をループをさせる必要があります。
今回は法線の向きに気を付けて、頂点をUVに沿って移動させる手法を取ります。
##UVをNURBS Curveから取得する
UVとNURBS Curveの相性は抜群です。なぜならば、NURBSの始点がUVの0、終点が1になるからです。UVTextureのTextureTypeはUniformSplineを選択します。
UVが取得できたので、一見このまま進めばいいように思えます。しかし、ここで落とし穴があります。
エスカレーターのようにUVがループ状になった場合、頂点とUVでずれが生じます。始点(0)と終点(11)は別のPositionにいるにも関わらず同じUVの値を持っています(0=1)。
例:UV0の頂点位置からUV1の頂点位置に移動すると一周したように思うが実際は頂点0の前の頂点11にいる
この状態を解消するにはNURBS CurveのArc TypeをClosedからOpen Arcに変更するか、Carve(Curveじゃないですよ)を利用する必要があります。Carveの方がポリゴンをNURBSにコンバートした後の始点移動調整が簡単なので便利です。
落とし穴はもう一つあります。
ループさせるために始点と終点をfuseで繋げようとするとどうなるでしょう。
fuseするとattributeが補完されてしまうので(1+0)/2となり0.5となってしまいます。
解決策としては。Wrangleで
if(@ptnum==0){
@uv.x=0
}
を直接代入するか、fuseを利用せず始点か終点のどちらかの頂点を削除した後addSOPで結合させます。
##addSOPでポイント番号順にVertexを繋げる
addSOPを利用してClosedな状態に変換します。addSOPはこのエスカレーター作成の肝となります。
なぜaddSOPか。それはpolyLineやpolyを簡単に作ることができるからです。
これを、ポイント番号が整列された4つのpolylineに適用すると、エスカレーターの形ができます。
##primUVで頂点をぐるぐるする
全ての下準備が完了しました。最後はprimuvを利用して回転を行います。
float uvp=@Time*ch("../control/speed");
float puv=(uvp+@uv.x)%1;
@P=primuv(1,"P",0,set(puv,0));
ポイントはpuv=(uvp+@uv.x)%1の「剰余(%)」です。UVは0から1の範囲で値があるので、単純にオフセットしていくと1を超えてしまいます。そこで余剰を行います。すると0~0.999はそのままに、1.0 が 0.0 、 1.2 が 0.2に変換されて取得できます。結果としてUV内でループが発生します。
そしてprimuvでポイントを@Timeや@Frameなどを利用してオフセット分ずらします。
法線の方向は人が乗っている間は平衡にする必要があります。
そこでバウンディングボックス内に存在するpointのY座標の法線を0にしてnormalizeします。
法線が正しく設定されたのでcopystampで台をコピーすればいい感じの方向に向いてくれそうですね。
最後に、手すりなどいろいろくっつけて、エスカレーターの完成です!
#まとめ
以上5つの階段でした。このように同じテーマだけど違うやつに取り組むと
自分の知らない機能についての知見も増えると思います。
様々な方法を知れば知るほどHoudini力はステップアップしますよ。
次は satoruhigaさんの「HoudiniをOSCタイムラインとして使う」です!