Houdiniを使った VRChat のワールドづくり:第2回 1weekWC の場合
前回の記事、ワールドを作るとき、序盤に考えること: 第2回 1weekWC の場合 では「どんなワールドを作るか」を決めるところまで書いたので、次は、どんな手順で作っていくのかを第2回 1weekWC の場合について書いてみます。
この 1weekWC では私は「世界の開闢から3つの柱しか存在しない、小さな世界の停車駅」を作ることに決めました。これは普段の私からすると、とても具体的な構想になっていて、製作中にワールドの設定や背景について悩むことは多くはありませんでした。
なので、この記事では、作業日3日間の、ひたすらに作成して、作成中に発生した問題を潰していく過程がつらつらと並びます。
私のワールドの作り方
VRChat のワールドというのは色々な作り方があります。最も一般的なワールドの作り方としては、Unity Asset Store や booth で配布されているアセットデータを組み合わせて所望の景色やギミックを作る方法です。
私の場合は、基本的には配布されているアセットのモデルデータを使わず、自分でモデルデータから作成します。フルスクラッチという呼び方をされる場合もありますね。
せっかく新しい世界を作るなら、自分で形も決めたいよねという思いと、一から作ったほうが、他にない面白さを作れるんじゃないかなという考えから来ています。
Houdini を使ってモデリングする
モデリングソフトというと、 blender というアプリの名前を聞いたことがあったり、使われている方は多いと思います。
ですが、私は、Houdini というアプリを使ってモデリングしています。知っている方は少ないかと思いますが、モデリングソフトとしては変わった種類のアプリになります。
ちょっぴりプログラミング寄りの考え方でこんな感じにブロックを線で組み合わせてモデリングしていきます。
右側がノードをつないでモデリングをしている部分で、左側がその結果です。
人によっては普通のモデリングソフトよりも使いやすいですし、私は手に馴染んで blender よりずっと自然に使えますが、使い方や考え方は他と比べると独特です。
今回作成したワールドは、モデリングとしてみると簡素な作りのものなのですが、だからこそ、記事に書くには使えそうだなと思いました。
ワールド作成の順序を考える
作業時間は三日間です。締切の延長は無く、完成しなかったら未完成品で交流会に参加するか、参加を諦めなくてはならないです。なので、ワールドの作成順序については少しだけ慎重に決めておく必要があります。
早めに安心したい
不安に駆られながらワールドづくりをするのは大変です。そういう経験も重要だみたいな考え方もありますが、私は好みではないです。なので、早めに提出可能な最低ラインを超えることを目指します。最低ラインを超えさえすれば、後は安心して、目指すけど届かない高みに向けて残りの時間を使えます。
構成要素を整理する
作りたい要素はたくさん思いつきますが、最低ラインを満たすことが優先です。そのために構成要素を洗い出します。
柱:表面の装飾
線路:枕木以下の構造
駅:駅周辺の装飾
街:建物の装飾と道
それぞれのデザインは何も決まっていないので、詳細は無いです。和風だといいななんて妄想はありますが、全てを最低ラインで整えることを目指します。
技術的に挑戦しておきたいところを確認する
私はワールドを作りつつ、モデリングとかシェーダーとかUnityの使い方の勉強も兼ねているので、作り始めた時点で出来ないことが作成予定に入っています。
今回の場合は、街の自動生成とライトベイクです。ベイクしていない街とか、手動で建物を配置した街を提出したりはしないという意味です。
幸いにも街の自動生成は、以前に実験したものがあるので、その仕組を今回のワールドに向けて拡張するだけです。最悪、何も発展させずに済ませましょう。
ライトベイクは Bakery があるので、それの使い方を勉強して使います。使えればクリアと言えますが、複数の町をベイクする必要があるので、時間とワールドの容量が懸念のポイントになります。
3日間しかないので、この2つを先に片付けることになります。
作業場所を作る
作業を始めるには場所が必要です。とりあえず以下を用意します。
git リポジトリ
私は自宅の NAS をバックアップ先(push 先)にしています。
Unityのプロジェクト
空の Houdini のファイル
とりあえずアップロードする
私は UnityProject のセットアップの最後は、VRChat SDK のサンプルワールドのシーンをコピーして、自分のシーンとして置き直して最低限のワールドを作っています。
その後、不要なものを省いただけのワールドをとりあえずアップロードして、中に入ってみることにしています。
これが確認できないまま作業をすすめるのは不安なんですよね。もしこのステップを省いて、実は何かが壊れていて、アップロードできないなんてことに後の方で気づいたら絶望しそうです。
街を作る
ここまで来て、やっとモデリングのスタートです。隣の柱の街が見えるような入り組んだ路地を持つ街を作るというのがミッションですね。
路地とは何か
路地というのは、何なのでしょうか。大まかには両サイドを家に挟まれた狭めの道ですね。景色としては綺麗な碁盤の目ではなく、曲がりくねっていて、分岐がたくさんあって欲しいです。迷路と違って行き止まりは少ないほうが良いです。
前にそんな要求を満たせそうな作り方を思いついて実験していました。
地面を作る
まずは、建物や道を作るための地面を設定します。
円の上に街を作ります。 circle というノードで円を作って remesh というノードで小さな三角ポリゴンに割っています。この小さな三角ポリゴンが道になったり建物になる基礎になります。
中央ほど高く設定する
中身は中央ほど頂点のY座標を持ち上げる簡単なプログラムを書いていますね。簡単とは言えプログラムを書いています。
家と道を塗り分ける
いよいよ街の生成の本題です。見た目に現れる道と家を作り分ける作業です。
赤いマスが家になり、青いますが道になります。プログラムはPythonという言語で書きましたね。道が直線で構成されることもなく、分岐は沢山あって、行き止まりも少ないです。前に書いた路地の条件を満たしてくれそうです。
プログラムの詳細は書かないのですが、作られていく過程を貼ってみましょう。
連なる家を作り、その周囲を道にする。空いているマスに家を立てて、またその周囲を道にする。これを繰り返すことで、曲がりくねった道を持つ街を作っています。ふと思いついた方法を試してみたのですが、意外とそれっぽく出来たので良かったです。
広場を作る
このままでは、全ての道は坂道です。これはちょっと詰まらないですよね。そして、この道は広場のような大きな空間がいくつかあります。街の合間にちょっとした広場があったほうが楽しいですよね。
なので、広場に使えそうな空間を検出します。
両サイドを家に囲まれてそうな場所は道、周辺に家がなさそうな場所を広場と定義して、ちょっとだけ範囲を調整しています。
やり方は雑なのですが、広場っぽいところが広場になってそうですね。
広場を平坦にする
広場として検出した場所を平らにします。広場ですからね。坂道のまま広場と言うのはちょっと残念です。
データの確認
ここでは街や道に色をつけているのですが、内部的にはポリゴンの状態を値で持っています。
赤い家の部分が1、青い路地になっている部分が2,平坦になった広場が3になっているのが見えますか?Houdini では、頂点やポリゴンに色んな情報を付与しながらモデリングしていくことがあります。
ただ、その情報が見えないと、正しい値になっているのかどうか分からないので、その都度、数値や色で状態を見えるようにしながら作業をすすめます。
時には、こんな Excel のシートのような数字の画面とにらめっこしながらモデリングしたりすることもあります。目が疲れますね。
家の床を平坦にする
坂道の上に建築されているとはいえ、家の中まで傾斜があっては困ります。なので、家の基礎になるポリゴンには、平坦になってもらいます。
これが取り出された家の基礎になりますね。
家の高さを決める
建築される家には、2階建てや3階建てといった高さの差が欲しいです。今回のワールドでは、中央ほど高い建物を、周辺ほど低い建物を建築したいと思っています。さらに、均等な高さではつまらないので、ばらつきをもたせたいです。
このあたりもこれから作られる予定の家の高さを可視化しつつ、良さそうなバランスに家の高さを「数字で」決定しておきます。
家を建てる
ここまで来て、いよいよ家の建築です。といっても、詰まらないもので、ただの三角柱を建築します。これが家です。
どうでしょう?狭い路地の周辺を様々な高さの家が取り囲んでいるように見えるでしょうか。
前に決めた家の高さの回数だけ、三角柱を積み上げています。非常にシンプルな家ですね。
窓の貼り付け
窓を取り付けます。窓は、明かりのついているものとついていないものに分けています。
先程建築した家の壁のポリゴンには、「このポリゴンは家の壁である」という情報が付与されています。なので、そのポリゴンの中央に一つずつ窓を貼り付けています。
階段の作成
今回の街は坂道を歩きやすいように階段にします。仮想空間の我々にとっては関係ないのですけどね。
まずは道と広場を取り出します。
次にこれを水平にスライスしていきます。
特定の高さごとにカットして、色付けしています。にぎやかですね。ここからカットして色付けされたポリゴンをそれぞれ、水平にします。
そして、最後に膨らませます。
街が階段と広場で埋め尽くされました。
モノリスの作成
街を建てていて気になる問題が発生しました。家は、連なるように建築されるのですが、時々、隙間が足りず、1ポリゴンの家が建築される場合があります。
これが非常に細く、狭そうです。これを家ではなく別のものに変更したほうが良い気がしました。なので、細いモノリスを建てることにしました。
この孤独な家ポリゴンをまずは取り出します。
このポリゴンを縦に伸ばしたりして、こんなモノリスを建てることにしました。
悪くないですね。
コライダーメッシュを作成する
我々が仮想空間で街の中を歩くためには、コライダーを設定する必要があります。
ですが、細かい窓や階段とかのポリゴンはコライダーに使うには細かすぎます。階段の段差でガタガタと歩きたくありませんしね。
なので、今までに作成してきたデータをちょっとずつ拝借することで、Unity の Mesh Collider に設定するメッシュを作成します。
街の完成
これで、大まかに街が完成しましたね。これまでの結果を組み合わせるとこんな形になります。最低限の街が完成ですね。
作成したモデルデータの出力
最後は、余計な情報を削除して、法線を整えたりして、fbx ファイルに出力です。これでやっと Unity での作業に入れます。
Unityへモデルデータの持ち込み
私のワールドはほとんどの場合、ワールド全体をモデリングして丸ごと fbx に出力します。なので、Unity 上でのヒエラルキーでは、最低限のオブジェクトと、スケールを調整したメインのモデルデータをポンと配置するだけだったりします。
後はモデルデータを Houdini で変更して Unity にフォーカスを移すと、自動的にリロードされてシーンビューに反映されます。
なので、以下のような作業をくるくると繰り返す感じになります。割りとお手軽です。
Houdini でちょっと編集
Unity で見た目を確認
Houdini でちょっと編集
時々 VRChat で確認
ベイクの実験
さて、この規模の街のベイクは平和に進むのでしょうか。よく Unity の説明にある 「Generate Lightmap UVs」の有効化ですね。
これを有効化して、Apply を押してみました。ライトマップ用の UV の生成が始まります。時間がかかりそうだったので、早めの夕飯を食べて、お風呂に入りました。まだ終わっていませんでした。
この時点で既にピンチです。私はモデリングとベイクをメインでやる予定なので、ライトマップの生成1回でこんなに待たされるわけにはいきません。
というわけで急遽 Houdini 側でライトマップ用のUVの生成方法を勉強し始めました。
Houdini でのライトマップ用UVの生成
uv2 という名前でライトマップ用のUVを出力すれば良いようです。雑にノードを当てて作ってみました。
使ってみた結果はこちら。
数分かかかりましたが、それでも Unity を待つより圧倒的に早かったです。
しかし、この密度、無事にベイクできるのでしょうか。試してみた感じ、荒いですが、ベイク出来ました。(スクリーンショットはない)
全部一つにまとめてしまうのはあまり良くなさそうです。分離方法を調べ始めました。
Lightmap Parameter の作成
調べてみた所 Lightmap Parameter を作ってタグを分けておくとライトマップのテクスチャも分かれるようになるようです。自動的にもある程度やってくれるようなのですがよく分からない。
とりあえず、マテリアルの種類ごとに Lightmap Parameter を分けてみていました。(このあたりの作法を私は全く分かっていないことに注意してください。)
改めてベイク
パラメータを色々触ってみて、だいぶ良くなってきました。
何か謎の光の線が出ていたりしますが、ふんわりした影が出ていて良い感じです。初日にベイクの実験まで届いてよかったです。
この時点でワールドの容量が 70MB ほどに届いていて、テクスチャの容量に危機感を感じ始めました。
一日目の終了
初日は、最低限の街の構築と最低限のベイクができました。一安心ですね。
後は、線路を引いて駅を置いて、柱を建てて、複数の町を設置して、街の装飾を追加すれば完成です。二日目はどこまで進むでしょうか。
線路の建築
二日目は線路の建築からはじめました。線路は街を取り囲むように走ります。なので、もとの街の形状をもとにこんなラインを引きました。
街の周辺を綺麗に取り囲んでいますね。次の章で説明するのですが、この円の様な全体のサイズに関わる値を正確に定義しておくことは重要です。
街に停車する部分を平らにしつつ、次の階層へ迎えるように線路を坂道に変更します。細い先が線路になります。この高さは、実は丁寧に計算してあって、隣の階層とぴったりつながるように出来ています。
ワイヤーの作成
線路は何に乗せようか考えた結果、巨大なワイヤーの上に乗せることにしました。
こんな感じのノードで、ポンデリングのようなワイヤーの断面を作成します。これを先に作った線路のラインと組み合わせて以下のようなワイヤーが完成です。
レールの作成
レールも断面を作成して、線路のラインに合わせて伸ばします。
断面を定義するたび、線路のルート上に物が増えていくのは楽しいですね。 Houdini では基礎となる構造を定義して、それを装飾する形でモデリングをしていくのは一つのスタイルです。使えるようになると、とても強力です。
枕木の作成
次に、枕木も作っていきましょう。箱を置きます。
今度は、枕木を置く間隔を点で定義します。
この点の上に先程の箱を置くと連なる枕木になります。本来の枕木の間隔はもっと狭いですよ。
線路の完成
これらを組み合わせてワイヤーの上を通る線路の完成です。これは比較的シンプルに作れましたね。
パラメータ化
私のワールドづくりでは、全体構造に関する寸法について、一つのノードに沢山のパラメータを押し込んで作業します。
こんなUIですね。
ここで、柱の高さや、直径、線路の幅などを定義しています。ワールド全体の寸法の定義ですね。
ここの値を変更すれば鉄道の幅も、街の大きさも変更できます。
逆にこの値を使わなかった場合は、街の大きさを変えるたびに様々なパラメータを色々な場所で変更しなければならなくなるので、大変です。
Houdini はこの手の根本になる情報からモデルデータを生成するように作れるので、後からパラメータを変更し放題なのが強みですね。
こういったインタフェースもある程度、手軽に作成できます。
柱の作成
最低限の要素をどんどん埋めていきましょう。柱です。何の工夫もない円柱ですね。作るのは簡単でしたが寂しいものです。
お皿の作成
街の下はどんな構造になっていると良いでしょうか?ぶら下がった街とか、崩れかけた構造物とか色々想像するのですが、とりあえずは、「絶対に壊れなさそうで、人工物っぽいもの」を作る感じで適当に作りました。ついでに中央を光らせて、街のエネルギー源も兼ねてもらいます。きっと柱の中から何かを取り出しているのです。
駅の作成
駅です。非常に寂しい作りになっていますが駅であると言い張りましょう。
ここまでで、モデリングとしては、最低限の要素を埋めることが出来ました。ここからは、Unity 上で組み合わせて3本の柱の上に乗る複数階層の街にしていきます。
ベイクの使い回し
初日の実験で、ベイクで増える街の容量がヤバそうなことが分かっていました。最低限のモデリングが済んだので、ベイクしたテクスチャの使い回しに挑戦です。
情報収集
他の作業でもやっていることなのですが、知らないことを試すときは、調べ物からですね。安定したやり方が見つからなかったので、使い回しができそうな手順が書いてあるページを片っ端からメモしていきます。
実験結果
色々調べて試した結果、一つだけベイクした後、そのテクスチャを参照するシェーダーを書いてしまう方法が安定して使えました。仕組みがわかっている分、安全でもありますね。
ただ、複数のマテリアルに対応したベイク後のマテリアルを作らないと行けないですし、ベイクするたびに設定を更新する必要があります。面倒くさい作業でした。
これは3日めのモデリングの詳細を詰める作業どころではないですね。
二日目の終わり
ベイクの使い回しという新しい問題が出てきてピンチな気分に浸っていました。頑張って手作業で出来なくもないですが、やりたくありません。簡単な拡張を作るしか無いなぁという結論を得つつ寝ることに。
ベイク結果の使い回し用のUnity拡張の作成
貴重なワールド作成最後の三日目の最初の作業は Unity拡張の作成です。簡単なものとはいえ、もったいないことです。
大雑把には以下の作業をする拡張を書きました。
元の全オブジェクトを取得する
ベイク結果の割当先のオブジェクト全てに対して処理する
MeshRenderer のライティングに関する設定をベイク済みのものに合わせる
マテリアルがなければ用意する
ベイク結果のテクスチャをライトマップ設定から取得する
マテリアルにテクスチャを設定する
元のライトマップのテクスチャの座標やスケールを設定する
えらくハイコストな手段に出てしまって色々書いていますが、もっと普通のやり方がある気がしています。知っている方がいたら教えて下さい。
でも、これで何度ベイクしてもすぐに本番のワールドへベイク結果を送ることができるようになりました。
副産物としてライトマップの光加減を後から調整できるようにもなりました。便利ですね。
植林する
やっと、街に詳細を追加できるターンが来ました。残り半日も無いです。残念です。
最初の作業は、広場に植木を置く作業です。
事前に検出していた広場の真ん中に植木を置いていきます。
玄関を置く
家に窓しか無いのは残念です。玄関を置いていきます。
玄関の設置条件は中々に難しいです。
街が坂道の上にあるので、玄関を穏やかに置ける場所は少ないです。そして、穏やかに置ける場所全てに玄関を置くと、特定の地域が玄関だらけになります。
そのあたりをゴニョゴニョ計算して、条件を決めました。この条件が意外と面倒くさくて、玄関を置いたあたりでモデリングの気力が底を付きました。街は完成です。
ライトマップUVの調整
仕上げとして、ライトマップテクスチャの切れ目がどこになるかで、ベイク結果が変わることが分かっていたので、ライトマップUVの展開方法の調整をはじめました。
分離せずに展開するとスペースが無駄になることが分かっていたので、直角になっている部分を片っ端から切り離して Houdini の UV Layout で整列させていました。
こんな感じで複数のテクスチャに分離する前提でレイアウトしていきました。
光加減の調整
最後は、光の調整をして完了です。
シェーダーを自分で書いたおかげで光の強さを後から変更できるようになったのは良かったです。ベイクするたびに何分も待つのは大変です。
完成
というわけで完成しました。
青い月明かりが照らす夜の街に、ふんわりと暖かい家の明かりが漏れている。空には巨大な柱の構造物と、隣町。 よい景色ですね。
色々なトラブルに見舞われて、すごく素朴な外見になってしまいましたが、それもふんわりしたライティングが綺麗なおかげでギリギリ許せます。
おわりに
長い記事になってしまいましたが、 第2回 1weekWC での私のワールド作成の手順を記事にしてみました。
比較的、シンプルな手順でワールドを作れたので、記事に書くのにちょうどよい規模になりそうだなと思って書き始めました。でも、書いてみると、思ったよりボリュームがあって大変でしたね。ワールド自体を作るのと良い勝負です。
作成過程を読まれた方は分かるかと思いますが、かなり技術的な作業をしてしまっていて、申し訳ないことに、プログラミングとかの経験の無い方が真似をするのはちょっと難しい手順になってしまっています。
プログラミングとかに抵抗がない人が Houdini を使ってワールドを作るとどういう手順になるのかの一つの例にはなるのではないかなと思います。
最後に、作成したノード全体の様子を。