ブラウザベースのメタバースを作る1
はじめに
この記事シリーズではブラウザベースのメタバースを作っていきます。
正確には、メタバースを構成する要素のうち、
「ユーザーが自分で用意したアバターを使って他のユーザーと交流する。」
をブラウザ上で実現するシステムの開発の流れを書いていきます。
既存のメタバース用のサービスは使いませんが、フルスクラッチというわけではなくThree.js及びthree-vrmなどのオープンソースなライブラリは使用します。
インターネット上のサーバを持ってない人でも自分で試せるように、ローカルPC上でサーバも動かして完結できる形で記事は書いていきます。
独自実装する部分についてはコードを記載していきます。
最終的にこんな感じの動きをするものが出来上がります。
設定を調整すればインターネット上で動かすことも可能ですが商用サービスを作るのには向かないのでそういう目的の場合はお勧めしません。
どちらかというと家庭内や学内のネットワーク上で教材として動かすことを想定しています。
また、この記事は環境構築や設計の検討を含めた通しの形で書いてるので分かっている人には不要な内容多めです。
この記事を書くに至った動機
実はブラウザベースのメタバースを比較的簡単に構築するためのライブラリとサービスが過去に存在しています。
2023年6月にアップランドから公開されたVerseEngineです。
自分なりにその特徴をピックアップすると
- ワールドを作りたい場合は公式のサンプルページを自分のサーバにコピーしてきてカスタマイズすればいい。
- カスタマイズについてはThree.jsの知識があればかなり自由な表現ができる。
- ワールド移動したい場合はlocation.hrefとかで移動先ワールドのurlを指定すればいい。
- ユーザー間の接続を仲介するシグナリングサーバを無償公開していて自分のサーバにバックエンドを置く必要がない。
という非常にシンプルかつ自由度の高いシステムでした。
ただ大きな欠点としてjsコードをブラウザ上で実行するという性質上、アバターモデルとソースコードの保護が困難なので商用利用には向きません。
しかし、中身が見えるのは教育目的であればメリットとも言えます。
また、学習においてモチベーションは重要な要素ですが、メタバース空間で自分のプログラムで動く物体を他の人に見せることができるのはかなりモチベーションが上がりそうです。
授業中だけの話ではなく、過去の在校生が作ったワールドに未来の学生が名所として訪れるような文化ができれば楽しそうです。
そこでVerseEngineを使って自分のワールドを作りたい人向けに、自分なりに調べたカスタマイズのための情報を自分のサイトに公開していました。
なぜ過去形で話しているかというと残念なことにVeseEngineは2024年7月以降公式のシグナリングサービスが停止しているためです。
このため今はお手軽に試すことはできない状態です。
フロントエンドの動作を見ることはできますが、他のプレイヤーとの接続がされないので自分しか表示されません。
ほぼ同時期に、シグナリングサーバ(VerseEngineではエントランスサーバと称しています)のソースが公開されているので自分で動かすという選択肢もあるのですが、
- 認証機能が付いていない
- ソースはあるものの運用のためのドキュメントがほとんどない
- クライアント側の通信処理がソース非公開なのでアバター以外の大きいデータの転送ができない
という理由で私は通信周りを自作する道を選びました。
VereseEngineは公式の説明の記述を見ると大きく分けて
- シグナリングサービスを提供するverse-entrance-server
- クライアント側の通信処理を提供するverse-core
- クライアント側のアバター処理を提供するthree-avatar
- 2と3を使ってフロントエンド機能を実現するverse-three
の4つで構成されていますが、このうちthree-avatarは他の3つに依存していないので単体で利用可能です。
公式のガイドに書いているように、通信処理はWebRTCで実現しているので、シグナリングサーバを自分で立ててクライアント間のWebRTCのp2p接続を確立し、あとは位置やチャットやアバター更新などの同期処理を実装すればエントランスサーバ抜きでも動作するはずです。
その辺の詳細は過去記事に書いているので興味のある人はここを見てください
この方向性で最終的に作ったものがこのシステムになります。
システム開発中にsnsにアップした動画
デモ動画1 ログインから部屋移動まで
デモ動画2 オブジェクトのアップロード
デモ動画3 移動地形
デモ動画4 視線が遮られる場合のカメラ制御
デモ動画5 月面地形データによるメッシュ表示1
デモ動画6 月面地形データによるメッシュ表示2
デモ動画7 ゲームパッド対応
しかし、three-avatarのサンプルコードを基に手探りで実装したのでかなり汚い構造になっていました。
そこで、1から作り直すことにしてその過程を記事にしようと考えました。
この記事シリーズでのゴール
メタバースという言葉はあまりに曖昧なので、個人製作で限られた時間でも実現可能な具体的な落としどころとして以下の機能を実装することを目標とします。
- ページにアクセスした他のプレイヤーのアバターが表示される。
- 自分のアバターを移動させることができる。
- 移動は他のプレイヤーの画面にも反映される。
- 自分のアバターをアップロードして置き換えることができる。
- 置き換えたアバターは他のプレイヤーの画面にも反映される。
- 他のプレイヤーとチャットできる。
- モーションデータをアップロードして、アバターをそのモーションで動かすことが出来る。
- 他のプレイヤーの画面にもその動作は反映される。
- ログインしないと参加できないようにする。
使用する技術
ブラウザで利用可能な技術はある程度限られます。
その中でメタバースの開発に使えそうなものをピックアップします。
-
WebRTC
メタバースでは位置、所作、チャット、アバターモデルといったデータをリアルタイムで同期する必要があります。
専用クライアントを使わずにブラウザで実現する関係で利用可能なプロトコルは、HTTP・Websocket・WebRTCのいずれかになります。
大きいアバターモデルを転送する間、位置やチャットが反映されないのは困るので多重化が必要です。
WebRTCは1つの接続についてデータチャネルを複数追加することが可能なので多重化が容易です。
そこで同期処理にはWebRTCを使うことにします。 -
Websocket
WebRTCはP2P通信を行いますが、P2Pの接続を確立するにはSDPという情報をクライアント間で交換する必要があります。
P2P接続確立前なのでSDPの交換(シグナリングと言います)は別の通信手段を使う必要があります。
消去法でHTTPかWebsocketになりますが、今回はWebsocketを使います。
クライアント側は他のクライアントのネットワーク上の場所を知らないので、ネットワーク上の場所が確定しているサーバにWebsocketで接続し、サーバを経由してSDPの交換を行うことになります。
これについては絶対的な正解でありません。
大規模なシステムの場合には向かないかもしれません。 -
VRM
ユーザーが自分のアバターをアップロードして表示するには、プログラム側がアバターファイルに対応できる必要があります。
また、ユーザーが特殊な手段を使わずにアバターを作成してアップロード用のファイルを用意できる必要があります。
これを満たすアバターファイルの形式がVRMです。
VRMは比較的一般的なアバターモデルのファイル形式です。
ブラウザ上での表示についてはpixivがthree-vrmというライブラリをオープンソースで公開しています。
また、VRMファイルを用意する方法は多数あるのでアバターを用意する難易度が低めです。 -
THREE.JS
3でも触れましたが、VRMの表示に使うthree-vrmはTHREE.JSを使っています。
またアバター以外の表示もあるのでそれについてはTHREE.JSで表示することになります。 -
Node.js
シグナリング処理を行うサーバはブラウザでは実行できません。
バックエンドで動かす必要があります。
サーバを動かす処理系はWebsocketを処理できればなんでも構いませんが、今回はNode.jsを使います。
理由は、「クライアント側と同じjavascriptで記述できる」、「参考資料が豊富である」という点です。
必要な環境
ChromeとNode.jsがインストール可能な、アバター用VRMの複数表示に十分な性能を持つPCが必要です。
Chromeを指定しているのは全ブラウザ対応すると単純に動作確認に手が回らないからです。(調べもの用ブラウザとしては私はFireFoxを常用しています)
性能については、windowsやmacの場合であればVRoid Studioが軽快に動く程度はあったほうがいいと思います。
VRoid Studioを基準に挙げたのは、どのみちアバター差し替えの際に自作vrmを作ることになるのと、そこそこ重いソフトだからです。
OSに関してはこの記事ではx86_64版Windows環境の場合について記述していきます。
適切な設定に変えれば他の環境でも動く可能性はありますがこの記事では扱いません。
環境構築過程でインターネットからライブラリやツールをダウンロードするのでインターネット接続環境は必要です。
開発PC上でサーバを立てるのでインターネット上のサーバは要求しません。
htmlやjsを編集することになるので使いやすいテキストエディタも用意したほうがいいでしょう。
私はサクラエディタを使っていますが、最近の主流はVisual Studio Codeかもしれません。
必要な知識
ネットワークについて最低限の理解は必要です。具体的には
- urlとサーバの違い
- ipアドレスとポート
- クライアント間のルータ越え接続は通常は難しいこと
また、javascriptについてある程度わかっている必要があります。具体的には、
- dom操作
- クラス
- 連想配列
- コールバック関数
- async/await
- promise
この辺について知っていないとソースコードを見ても意味が分からない可能性が高いです。
ただこれらはネットで検索すれば手に入りやすい情報でもあります。
htmlについてもある程度の知識が必要ですが、
- タグの意味
- セレクタの意味
- インポートマップの意味
- 基本的なcss
がわかっていれば十分です。
数学的な知識については、ベクトルと三角関数の意味が分かる程度で十分です。
難しい問題が解ける必要はありません。
設計方針
- ライブラリはオープンソースのものを使う。
- 独自実装部分はjsで記述してソース(githubへのリンク)を記載する。
- 外部サービスに依存しない設計にする。ただし、環境構築や素材作成のツールやサービスは例外とする。
基本的に、サーバを構築してワールドのページを作成したら、外部サービスと関係なく運用できることを目指しています。
ロードマップ
以下の流れで記事を書いていきます。各項目のボリュームは一定しないので、1回の記事にまとまる場合や複数に分割する可能性があります。
- 環境構築
- three-vrmのサンプルを基にしてプレイヤー操作でアバターを動かせるようにする
- WebRTCによるチャットを実装する
- WebRTCによるdom要素の位置同期と画像同期を実現する。
- 他のプレイヤーのVRMアバターを表示して同期する
環境構築
今回は環境構築を行います。
-
Node.jsがインストールされてない場合はインストールします。
ここでダウンロードできますが環境によっては違う手順になるかもしれません。
私はWindowsで確認しています。 -
開発用のディレクトリを決定します
配置場所については特にルールはありません。
私は勝手に同期されたく無いのと後で探しやすいように
C:/work/localverse
のようなディレクトリを切っています。
以下、この記事でファイルを配置する場合はここで決定したディレクトリを基準として記述します。 -
web用リソースのディレクトリを作成します
ターミナル(Windowsの場合はコマンドプロンプトやパワーシェル)を起動します。
以下のコマンドを実行してディレクトリを作成します
cd 2で作成したディレクトリ
mkdir ssl
mkdir config
mkdir web
mkdir web/asset
mkdir web/asset/animation
mkdir web/asset/model
mkdir web/asset/vrm
- ssl証明書の作成
-
証明書が必要な理由
ブラウザ上でメタバースを動かすには、比較的新しいブラウザの機能(API)を利用する必要があります。
ところが多くの場合、ssl対応したページでないと利用できません。
今回はローカル環境にウェブサーバを構築するので、sslの設定も行う必要があります。
このためssl証明書を用意する必要があります。
警告の出ないsslページを表示するには、有料のサービスでssl証明書を購入する必要がありますが、これはそもそもインターネット上の話です。
ローカル環境でのテストの場合はssl証明書を自前で作ることになります。
このような証明書の場合、ブラウザは安全でない接続として警告を出しますが、API自体は有効になります。
そこでssl証明書をopensslを使って作ります。 -
opensslのインストール
opensslをインストールする方法はいくつかありますが、今回は
https://slproweb.com/products/Win32OpenSSL.html
のものを使います。
ダウンロードするファイルは環境によりますが、2025年3月時点ではWin64 OpenSSL v3.4.1 Lightでよいでしょう。
ダウンロードしたファイルを使ってインストールします。 -
opensslのパスを通す
※これはWindows固有の話です。
インストールしただけではPowershell等でopensslの場所が認識されずにコマンドが使えないので、以下の手順で設定する必要があります。- エクスプローラを開く
- PCアイコンを右クリックしてプロパティを選択
- システムの詳細選択をクリック
- 環境変数と書かれたボタンをクリック
- Pathを選択して編集ボタンをクリック
- 新規作成ボタンをクリック
- 新しくできた行にopensslコマンドのあるディレクトリを設定します。
opensslのインストール先を変更してなければ、C:\Program Files\OpenSSL-Win64\bin でよいはずです。
そうでない場合は、openssl.exeが存在しているディレクトリを指定してください。
-
opensslコマンドで証明書を作る
以下のコマンドで証明書を作ります。
cd 2で作成したディレクトリ
cd ssl
openssl genrsa -out server.key 2048
openssl req -out server.csr -key server.key -new
openssl x509 -req -days 3650 -signkey server.key -in server.csr -out server.crt
2つ目のコマンドでいくつかの質問がされますがすべて規定値で問題ありません。
- npmパッケージのインストール
以下のコマンドを入力してこの記事で使うことになるパッケージをインストールします。
cd 2で作成したディレクトリ
npm init
npm install fs
npm install http
npm install express
npm install three@0.169.0 @pixiv/three-vrm
npm install ws
npm install uuid
npm install cannon-es
npm install cannon-es-debugger
- ウェブサーバの作成
既存のhttpサーバをインストールしてもいいのですが設定が意外と面倒なのでnode.jsで簡単なものを実装します。
2で作成したディレクトリに以下のスクリプトを作成します。
- コードの説明
リクエストに対応したリソースを返すだけの単純な実装ですが1点だけ特殊処理が入っています。
npmでインストールしたモジュールを/npm/のパスでアクセスしたいので/npm/で始まるリクエストをnode_modules以下のファイルにアクセスできるように書き換えています。
もし別のhttpサーバを使う場合は/npm/がnode_modulesを参照するように設定してください。
わざわざこういう設定にしているのは、参照するリソースはすべてローカルサーバに配置したいからです。
インターネット上のファイルはいつまでもあるとは限りません。
- httpサーバの動作確認
以下のコマンドでサーバを起動します。
node httpd.js
ブラウザを立ち上げて https://localhost:10443/ にアクセスします。
「この接続ではプライバシーが保護されません」 と表示されるので、詳細設定を選択してそこから 「localhost にアクセスする(安全ではありません)」のリンクをクリックします。
HTTP ERROR 404 と表示されることを確認します。
webディレクトリに以下のファイルを作成します。
<html lang="ja">
<head>
<meta charset="utf-8" />
</head>
<body>
httpd.jsのテスト
</body>
</html>
https://localhost:10443/ に再度アクセスします。
httpd.jsのテスト と表示されることを確認します。
次回予告
次回はローカルプレイヤー処理の下準備としてthree-vrmの公式サンプルのhumanoidAnimationを参考にして、ブラウザ上でアバターを表示してキー操作で移動できるところまで進めます。
少し長めになる可能性があります。
Discussion