「Sci-Fiな通路」制作記録
はじめに
3Dモデリングとお絵かきをしたのでその過程を残します。
Houdiniで背景のモデリング
背景はHoudiniでモデリングしました。
最初にGeometryノードを作成し、ダブルクリックかiキーでネットワーク内部に入ります。
Gridノードを作成します。
Orientationを「YZ Plane」に、Sizeをそれぞれ「6」「3」に、 RowsとColumnsを「2」にします。
Scatterノードを接続します。
Force Total Countのチェックを外します。 点の数ではなく密度で指定するようになります。
Point Wrangleをつなぎます。
次のようにVEXを書きます。
これで点が格子点上に配置されます。 スライダはそれぞれの軸の格子の大きさを決めています。
fuseをつないで重複した頂点を削除します。
Keep Unused Pointsにチェックを入れます。 これで面や辺を構成していない点が保持されます。
もう一つPoint Wrangleをつなぎます。
次のVEXを書きます。
ランダムに頂点を削除するプログラムになります。
Voronoi Fractureノードをつなぎます。
Scatterから直接ボロノイ分割した場合と比べると、 より整列した印象になっていることがわかります。
この量子化した点をボロノイに渡すというのは次の動画を参考にしました。
Procedural Hard Surface Design | Akira Saito | SIGGRAPH Asia 2018 (Tokyo) on Vimeo
この動画には他にもボロノイの実践的なテクニックが紹介されているのでおすすめです。
nullノードを作成します。
Zキーからnullノードの形を変更します。
Cキーからnullノードの色を変更します。
右上のギアマークから「Edit Parameter Interface」を選びます。
Floatをドラッグアンドドロップして追加します。
ラベルを「Seed」と名付けます。
nullに新しく追加された「Seed」を右クリックから「Copy Parameter」します。
Scatterの「Global Seed」と、頂点を削除しているPoint WrangleのSeedに 「Paste Relative References」します。
これでnullノードでSeedをコントロールできるようになりました。
同様にして各Quantizationの値と頂点削除のしきい値をnullノードでコントロールするようにします。
しきい値のRangeを0から1までに変更します。
最初からあるパラメータは使わないので隠します。
nullノードにコントロールするパラメータが集約されてわかりやすくなりました。
これまでのノードを全部選択してShift-Cでサブネットに格納します。
右クリックから「Create Digital Asset」を選択します。
デジタルアセットの名前を適当につけます。
Type Parameterの画面が自動で開きます。
平面のOrientationとSizeをドラッグ・アンド・ドロップします。
nullノードに集約したパラメータをドラッグ・アンド・ドロップします。
ToolsのContextから追加するタブメニューを指定します。 こんかいは「Digital Assets/Sci-Fi」としました。
これでこのノードがタブメニューから作成できるようになりました。
作成したノードは一つのノードのように扱われ、パラメータを自由にいじれます。
すでに作成してあるノードを右クリックから「Match Current Definition」でロックします。
For-Each Primitiveループを追加します。
「Create Meta Import Node」を追加します。 このノードのiterationを利用します。
Poly Extrudeノードをfor-eachループ内に追加します。
Distanceに「rand(detail("../foreach_begin1_metadata1/", "iteration", 0))
」と記述します。
イテレーション回数をシードとしてランダムに押し出ししています。
Front Groupを有効にし、Output Backも有効にします。
poly bevelをつなぎます。
extrudeFrontに対してわずかにベベルをつけます。
normalノードをつないでBy Face Areaを指定します。
これで次のようなものができます。
新しく先ほど作成したデジタルアセットを作成します。
次のようにノードを組みます。
次のようなものが作られます。
一つずつパラメータを解説していきます。
最初にprimitive wrangleを追加します。
次のようなVEXを記述します。 ランダムにプリミティブを削除するプログラムになります。
次にforeach primitiveを追加します。 メタデータも作成しておきます。
foreachの内部では最初にpoly extrudeをつなぎます。
Distanceで少しだけ押し出しをして、extrudeFrontグループを作成し、 Output Backを有効にします。
polyextrudeのあとは2つに分岐しています。 右側から見ていきます。
右側はpoly bevelにつないでいるだけです。
わずかにベベルを与えました。
分岐の左側を見ていきます。
BlastノードでextrudeFrontグループ以外を削除しています。
その後、Convert Lineノードを接続します。
その後foreach primitiveループを作成します。 これで作成されたエッジごとにループが回るようになります。
resampleノードを接続します。
poly frameでtangentをNとして出力します。
これで線の方向に沿ってNが作られました。 copy to pointでこの法線が重要になります。
つぎにpoint wrangleを接続します。
次のVEXを書きます。
最初と最後の要素を削除し、指定された個数以上の点を削除しています。
「@ptnum == @numpt
」ではなくて「@ptnum == @numpt - 1
」が正しそうな気がします。
これで最初の方の3つの点が残りました。
この点に対してcopytopointします。
コピーされる物体の方を見ていきます。 最初にTubeを作成します。
End Capsを有効にして大きさを適当に小さくします。
Group Createノードを接続します。
上半分の領域を選択します。
transformで作成したグループを上方向に移動します。
次のtransformで全体を下に下げて中心を合わせます。
さらにtransformで縮小しました。
ノードをcopytopointsに接続します。
各ラインに3つ複製されるようになりました。
複製したものをbooleanで引き抜きます。 booleanノードに接続します。
SubtractでB-Aに設定します。 右側から左側のジオメトリを引きます。
transformノードを接続して各パネルを微妙にずらします。
Translateのxに「rand(detail("../foreach_begin2_metadata1", "iteration", 0)) * 0.2
」と書きました。
これでforループの内部は終わりです。
最後にnormalノードを接続しBy Face Areaに変更します。
長くなったのでsubnetに格納します。
transformでx軸方向に少しだけ動かします。
mergeノードで作成した2つをマージします。
次のようになりました。
新しくノードを右側に作成してmergeに追加します。
一つずつノードのパラメータを見ていきます。
最初にGridノードを作成しています。
グリッドのサイズをこれまでのと合わせました。
次にSubdivideノードを接続してきとうに分割します。
その次にFind Shortest Pathノードを接続します。
Start Pointsとして右側の頂点を選択します。
End Pointsとして左側の頂点を選択します。
From each start to each endにします。
Omit Distance from Costにします。
これで次のようなラインが作られました。
poly wireとnormalノードを接続し、transformで適当な位置に移動します。
mergeノードに組み合わせます。
これで次のようになりました。
最初のグリッドのサイズを少し大きくしました。
ここからSubstance Painter用のIDマップを作成していきます。
Colorノードを接続して適当な色を与えていきます。
前面のパネルには2色で塗り分けをしたいのでサブネットの内部で色を与えます。
primitive wrangleとattribute promoteをforループの前に追加しました。
追加したprimitive wrangleには次のようなVEXを記述します。 プリミティブごとにランダムに2色に塗り分けています。
attribute promoteノードを接続します。
Cdをprimitiveからpointに移動します。
これで次のように塗り分けられました。
マージの仕方を変えて右側と左側の両方にuv unwrapとuv flattenノードを接続します。
Game ToolsのSimple Bakerノードを接続します。
適当に名前を変更しました。 normalとaoもベイクしましたが、basecolorしか使いません。
右側でも同様にベイクします。
オブジェクト階層に行くとなぜか表示が白黒になってしまいましたが 原因不明なので気にせず作業を進めます。
作成した壁を複製してサイズやシードを変えて配置します。
それぞれでベイクを行います。 なんか色がバグっていますがデータは問題なく作成されているようなのでそのまま進めます。
次にケーブルを作成していきます。 新しいGeometryノードを用意します。
curveを作成します。
poly frameでNormalをup、tangentをNとします。
lineを作成し、Directionを1, 0, 0にします。
lengthをコピーしてOriginのxにペーストし、「-」と「/2」を加えます。
pointsを適当に増やします。
Copy Stampノードに接続します。
Stamp Inputsを有効にして$PT
を用意します。
コントローラ用のnullを作成します。
右上のギアからEdit Parameter Interfaceを開きます。
最初からあるパラメータは必要ないので隠します。
Floatをドラッグ・アンド・ドロップしてSeedと名付けます。
nullノードにSeedが追加されました。
lineノードにsortノードをつなげます。
Point SortをRandomにして、Seedに「stamp("../copy1/", "p", 0) + ch("../null1/parm")
」と記述します。
コピーしたポイント番号とnullのSeedを足し合わせたものをランダムのシードとして使います。
コピーされたラインの頂点がランダムになっていることがわかります。
point jitterをつなげます。
scaleを小さくして、seedには先程と同様のものを記述します。
コピーされたラインが少しがたがたになりました。
point wrangleを追加します。
次のVEXを記述します。
ポイント番号を文字列にして@name
アトリビュートに追加しています。
copy stampの下にaddノードを接続します。
Delete Geometry But Keep the Pointsを有効にします。 これで頂点のみが残ります。
foreachループを接続します。
Piece ElementsをPointsに、Piece Attributeをnameにします。 これでnameが等しいものはまとめられてループが回るようになります。
ループの中でAddノードを作成します。
PolygonのBy GroupでAll pointsにします。 これでランダムにソートされたlineの頂点番号が等しい者同士が繋がります。
resampleノードを接続します。
restノードを接続します。
for feedbackループを接続します。
iterationsを32にします。
detangleノードを接続します。
Previous Positionをrestにします。
このdetangleのつなぎ方は次の動画を参考にしました。
Houdini 17 is here! Vellum quickstart pt 4 5 The Detangle SOP - YouTube
コントローラ用のnullにパラメータを追加します。
Cable Radiusという名前にしました。
Cable Radiusをコピーします。
DetangleのDefault ThicknessにPaste Relative Referencesします。
Rangeを適切に調節します。
ここまでで次のようになりました。
ちょっとガチャガチャしすぎているのでResampleのLengthを少し長くしました。
次のようになります。
Subdivideをつないでなめらかにします。
polywireをつなぎます。
Wire RadiusにCable Raduisをペーストします。
次のようになります。
コントローラのnullにパラメータを増やします。 JitterのスケールとLineのポイントの一人長さをパラメータにしました。
カーブを除いて全部のノードを選択します。
サブネットにまとめます。
Create Digital Assetします。
適当な名前をつけます。
nullに集めておいたパラメータを全部ドラッグ・アンド・ドロップします。
Input/Outpuからinputのラベルを適当にに変更します。 ここでは「User Curve」としました。
ToolsのContextから「Digital Assets/Sci-Fi」としました。
作成したケーブルを配置していきます。
IDマップ用に色を与えます。
uv unwrapとuv flattenを接続してSimple BakerでIDマップを焼きます。
以上で次のようになりました。
fbxの書き出しを行います。
Substance Painterでマテリアルを割り当てる
書き出したfbxをSubstance Painterに持ち込みます。
作成したidマップを適切に与えます。 作業が面倒だったのでSubstance Painter側でidマップもベイクしたほうが楽そうです……。 次回からはそのように作業することにします。
適当にマテリアルを割り当てました。
BlenderのCyclesでレンダリングをする
Blenderにfbxを読み込ませると、 マテリアルに黒色が指定されていたようで真っ黒になります。
MatCapで描画するときちんと描画されます。
レンダラをCyclesに変更し、 Substance Painterから書き出したテクスチャをPrincipled BSDFノードにつなぎます。
Emissionを割り当てた光源を適当に配置します。
レンダリングした結果はこのようになりました。
以前作成したキャラクターのモデルを 読み込んで配置しました。
Kritaで加筆する
レンダリング結果をKritaに読み込んで加筆しました。
おわりに
Houdiniでのモデリング部分についてだいぶ丁寧に書きました。 とても大変だったので今後はこんなに丁寧に書くことはないと思います……。