MagicaVoxelでVRChatのワールドを作る
VRChatは自分の分身たるアバターともう一つ、ログイン先のワールドも自分で作ったものを使用することができる。
前回はアバターを作成することができたので、次はワールドも作ってみたいよねというのでやってみたのが今回のメモ。
使用するもの
・MagicaVoxel 0.99 alpha
現時点での最新版だけど、モデリングするだけならどのバージョンでもいい。
・Unity 5.6.3p1
前回と同じ。この記事を書いている時点ではこのバージョンが必須なので注意。
・VRChat SDK
こちらも前回と同じく公式からダウンロードする。
前回の記事からアップデートがあって、今回使用したのは「VRCSDK-2018.02.23.18.45_Public.unitypackage」である。
お品書き
ボクセルモデルを作る
まずはMagicaVoxelを使って、ワールドを構成する素材となるモデルを作っていく・・・のだけど、いきなり説明をぶん投げてしまって申し訳ない。こちらからは素材を提供する術が無いので、ここは各自でモデリングを頑張って作ってもらうしかない。
面倒だったら、Minecraftの豆腐ハウスよろしく板を数枚で部屋なり屋外なりを作ってもいいけど、そもそもそれならUnity標準の3Dオブジェクトでいいか・・・。
もし過去にいい感じのモデルを作ったことがあるのなら、それは積極的に使いまわしていこう。
今回、自分は過去にTwitterにあげていたこれから素材を流用することにした。
ご存知ポケット・クエリーズ社のアイドル、クエリちゃんをボクセルで作って、和室でだらだらと過ごす様を投稿したもの。
この和室をワールド化していく。
部屋にするためには、手前側の壁2枚と天井が必要なので、これらは新たに作成した。
ここで、もしこれを読んで今から部屋なりをボクセルモデリングしようとしている方がいたら一つ注意。
画像の右上に数字が出ているように、この和室はMagicaVoxel上で作成できる一番大きい数字をとっているけど、Unity上に持っていくと1ボクセルが1mくらいの大きさで実用的じゃないため、スケールを小さくして違和感ないレベルに縮小することになる。そうすると、この広さでも最終的にはかなり窮屈な出来になるのだ。いや、まぁ四畳半だから窮屈なのは当たり前なのだけど・・・。
広めの部屋を作りたいときは、床も壁もパーツに分解してモデリング、それを組み合わせて作るようにした方が良いと思う。
さて、部屋に置く小物類は以前作ったものをそのまま使うので手は入れない。
作ったものはobj形式でエクスポートしてこの工程は終了。
Unityに取り込む
Unity 5.6.3p1を起動して新しくプロジェクトを作成する。
まずは後の作業のためにちょっと準備をしておく。
標準だとUnityの右側、Inspectorビューの隣にLightingという項目があるのでそれを選択。
その一番下に、画像のような「Auto Generate」というチェックボックスがあるので、このチェックを外しておこう。この機能は後で使うので、自動で動くと邪魔になるのだ。
VRChat SDKもこのときにインポートしておく。
本題に戻って、上でエクスポートしたobjファイルをドラッグ&ドロップで取り込んでいく。エクスポートしたときに一緒に出力されたpngファイルも一緒に選択して放り込むこと。
ここで一手間加える必要がある。
恐らく放り込んだら、UnityのProjectビューはこんな感じになっているはず。
Materialsフォルダの中に、○○○Matというファイルがあるので、これを選択してInspectorビューを見てみよう。○○○は元ファイル名によって変わる。
「Albedo」と書かれている右の四角をクリックして、色の要素を全部255へ。
「Albedo」のすぐ左の◎をクリックして、一緒に放り込んだpngファイルを選択。
変にテカらないように「Smoothness」も0にする。(好みによる)
面倒だけど、放り込んだobjファイルそれぞれにこの作業を繰り返す。
これでobjファイルをHierarchyビューに配置する準備ができた。
ワールドを組み立てる
objファイルをHierarchyビューに置いて、縮尺を合わし、思うが侭に空間を組み立てていく。
このとき、いつもUnityでやっているのと同じように、関連するオブジェクトは空オブジェクトの子にしてまとめてしまったほうが扱いが楽になっていい。
例えば、この画像の「TV」と「TVdai」は別々にモデリングしたものなので別のGameObjectになっているけど、どちらも空オブジェクトの「TV」の子にしているので移動や回転がやりやすくなる。(名前がややこしい点ではとても良くない例
試行錯誤しつつ、置き終わった。
全方位が壁に囲まれて暗いので、中心にPoint lightを設置している。
最初から置いてあるDirectional Lightは不要なので削除した。
物を置く場所が決まったら、各オブジェクトにAdd ComponentからBox Colliderを選択して当たり判定をつけていく。あまり詳細につけても重くなるだけだし、ざっくりとでいい。
上の画像だと、天井・床・壁、みかん箱、こたつ、ストーブ、TVにボックスをつけているだけ。大体の移動制限があるのが分かる程度で良い。
ライティングを設定する
上の画像は中心にRealtimeモードのPoint lightを1つ浮かべているだけだけど、ワールド自体が狭い四畳半なので見た目は特に不都合は無い。
ただ、もうちょっと複雑な形や広さの部屋だったり屋外だったりすると、大量の光源を置くことになってRealtimeの光源だけで表現するのは非常に重い。ただでさえVRという重いコンテンツに使用するものなのだから、できるだけ負荷のかかることは避けたいところ。
ということで、ライトマップのベイク(Baked)というものに手を出してみる。
※ここは初めて手を出して理解が追いついていないので、いつも以上に間違った記述がある可能性が高いので注意。
「ここにこういう光源があるから、ここにあるものはこんな感じに見えてこんな影ができるよね」というのを常に計算して表示するRealtimeとは異なり、Bakedは一度だけ計算した結果をライトマップという専用の領域に保存して、それを表示するらしい。
つまり、光源やものが動いてしまったら破綻してしまうのだけど、絶対動くことがないものに対してはとても有用だということ。今回の部屋にも使えそうだ。
まずはオブジェクトがライトマップを使用するように設定する。
Unityに取り込んだobjファイルを選択して、Inspectorビューに表示された赤線の部分にチェックをつける。
次に、Hierarchyに置いた床や壁、家具等の絶対に動かさないもの全部に対して、staticのチェックをつける。
赤線の部分。まとめたオブジェクトの親にチェックをつけて、子もまとめて一緒に設定しても問題ないはず。
念のため、各オブジェクトでMeshRendererを持っているもの(モデリングした形本体を持っているオブジェクト)を見て、Cast ShadowsがOnに、Receive Shadowsにチェックが入っていることを確認する。(多分初期から入っているはず)
計算に使用するライトは、今浮かべているものを使う。
ライトを選択してInspectorビューを確認。
「Mode」をRealtimeからBakedに、「Shadow Type」はSoft Shadowsを選択。
ここまでできたら、プロジェクト作成時にAuto Generateのチェックを外した隣にある「Generate Lighting」ボタンを押してみよう。
しばらく右下でバーが動きつつ計算が行われる。
こんな感じになった。
ぱっと見では見分けがつかないけど、これは計算しながら表示しているのではなく、ライトマップに保存された計算結果を表示している・・・はず。
Realtimeのときにはくっきりしていた影がいい感じにぼんやりとなっていて、かなり現実に近い気がする。この表現を制御しているパラメータは、ライトのInspectorの「Shadow Type」の下にある「Baked Shadow Radius」とのことなので、表示が満足できなければここを調整してみるとよさそうだ。
ライトプローブを設定する
そろそろ頭がショートしそうになるけどもう一踏ん張り。
VRChatのアバターに当たるライティングの計算は、ライトプローブというものを使用して行われるらしい。
確かに、この時点で試しにVRChatにアップロードして確認したところ、移動時に見える自キャラは暗がりにいるような色であった。
まだVRChat上で他の人と交流を持ったことが無いからわからないけれど、多分今の状態で誰かを招待してもお互いに暗く見えるのだろう。これではいけない。
さて、ライトプローブとはなんぞや。
・・・なるほどわからん。
詳細は置いておいて、明るいところと暗いところのような光量の差が大きいはずの隣接したところや、高低差があるところに黄色い球を配置すればいいようだ。
新しく空オブジェクトを作成して、それにAddComponentでライトプローブを追加してみた。立方体の頂点のように置かれているのがライトプローブ。
白い球はなんだと思ったらただのアイコンだった。紛らわしい。
ものすごくわかりにくいけれど、試行錯誤してこのように配置した。
最初の8つはより部屋の隅の方へ。
新たに一番明るい蛍光灯の真下、少し暗くなる椅子の裏に球を追加。
これでいい感じに計算してくれるのではなかろうか。
必要か調べてもわからなかったけれど、念のため「Generate Lighting」ボタンを押してライティングの再計算をしておく。
座れるようにする
これは自分が作っているワールドの話なので、関係ない方は読み飛ばしてもいい。
こたつの周囲に椅子を置いているので、これに座れるようにしたい。
アバターが座れる機能というのは、VRChat SDKにPrefabで用意されているのでそれをお借りする。
VRCSDK→Prefabs→Worldの中にあるVRCChairがそれである。
Cube2つは椅子っぽく見えるために使われているだけなので、不要なら削除してもいい。
EnterPointが座ったときのアバターの位置、ExitPointが椅子から立ち上がった(Exitした)ときにアバターが立つ位置・・・のはず。
VRCChairをこたつの椅子の子にして同じ位置に配置、Cubeを削除した。
EnterPointにアバターが移動すると、いい感じに埋まってこたつに入っているように見える・・・はず。
ExitPointは埋まらないように、椅子の後ろ少し余裕を持たせた位置にした。
スポーン位置の設定
ワールドにログインしたとき、アバターが最初に出現する位置を設定する。
VRCSDK→Prefabs→Worldの中にあるVRCWorldをHierarchyに配置する。
実はこのVRCWorldさえ配置すれば、VRChatにワールドをアップロードする準備は整うらしい。
VRCWorldのInspectorを見てみると、その中にスポーン位置の設定がある。
標準ではVRCWorldオブジェクトが存在する位置にアバターがスポーンする。
複数増やしたければ、Sizeを増やしてGameObjectを指定する。複数の位置からスポーンするときにどの位置から選ぶかはSpawnOrderで制御できるようだ。
一応部屋なので、VRCWorldを扉の前に配置した。
ワールドをアップロードする
いよいよ作成したワールドをVRChatにアップロードする。
上のメニューからVRChat SDK→Show Build Control Panelを選択する。
一番下のPublishの中にあるNew Buildを選択する。
アバターのときと同じようにビルドが走り、Gameビューにアップロード用のインターフェイスが表示される。
同じワールドで何度目かのテストなので、画像ではConfigure Worldになっている。
アバターのときと同じく、名前と説明の入力、VRCCamの位置調整でサムネイル撮影。
ワールドだけの項目としては同時接続最大数があるようだ。
埋めたら左下のチェックボックスにチェックを入れてUploadボタンを押してしばし待つ。
やはりVRChat側の調子が悪いときがたびたびあるようで、最後の最後でBad Gatewayだかでエラーになるときがあった。
しばらく待つなりリトライなりで根気良くやり直す。
エラーがでなければ、作業は終了。お疲れ様でした。
アップロードしたワールドは、アバターと同じようにVRChat内メニューのワールドリストの下の方に追加されているので、検索しなくてもそこから飛ぶことが出来る。