Web表現の可能性を探るため、スクロールに連動した3Dアニメーションを作成しました。
変形!黄金剣士ドラン!
https://htanjo.github.io/goldran/
「黄金勇者ゴルドラン」のファンメイド作品です。インタラクティブな3D Webアニメーションになります。ページのスクロールに合わせて、車からロボットへと変形していきます。
普通の動画と違い、マウスの動きやスマートフォンの傾きに合わせてカメラの位置がリアルタイムで調整されます。変形の様子をグリグリと視点を変えて眺めることができます。
また、画面下部には「自動再生」や「フルスクリーン」ボタンも配置しました。
技術面の解説
アニメーションキーフレーム付きの3DデータをglTF 2.0形式で作成し、WebGL APIを使ってHTMLの<canvas>
要素にレンダリングしています。特定のランタイムをインストールすることなく、全てのモダンブラウザで動作します。
このように、さまざまなオープンソース技術を組み合わせて実装しました。主要なものについて解説します。
Babylon.js
高品質な3DコンテンツをWebページ上にレンダリングするためのJavaScriptフレームワークです。PBR(Physically Based Rendering/物理ベースのレンダリング)をサポートした高度な3Dエンジンを持ちます。
豊富なドキュメントとオンラインデモ、公式フォーラムでの情報量の多さがとても役立ちました。同様のライブラリとしてThree.jsも有名ですが、レンダリングのパフォーマンスと開発コミュニティの活発度からBabylon.jsを選びました。
今回Babylon.jsは、モデルデータの読み込み、ライティング、リアルタイムレンダリング、ポストプロセシング(画面エフェクト)、アニメーションの再生管理に使用しています。
Blender
無料かつオープンソースで提供されている、統合型の3Dグラフィックスソフトウェアです。商用ソフトに引けを取らない完成度だと思います。
モデリング、マテリアル作成、アニメーション作成はすべてBlender上で行いました。1つのソフトウェアで各工程をシームレスに作業できるのは、個人開発において大きなメリットでした。
作成した3Dデータは単一のglTFファイル(.glb)としてエクスポートし、Babylon.jsを通じてHTMLへとインポートされます。
このプロジェクトのglTFファイルには、3Dモデル、テクスチャ、アニメーション、カメラの情報がすべて含まれています。
例外的にライトだけはglTFに含めず、Babylon.jsで手作業によって配置しました。これは、最終的なビジュアルの微調整をブラウザ上で行うためです。同じライトを設定しても、Blender上のライティングとBabylon.jsでのレンダリング結果はやはり差があります。
また、リアルな質感を表現するために、Fluent MaterializerとSimplebakeアドオンを購入しました。これらを使用してPBRマテリアルの色/光沢/凹凸/陰影/発光などの情報は事前にテクスチャとしてベイクされており、その分Babylon.jsでの処理負荷が軽減されます。結果的に描画品質を上げながら高いフレームレートを維持することができました。
glTF Transform
このプロジェクトはスマートフォンも動作対象にしています。
そこで課題になってくるのが、CPUとGPUへの動作負荷、メモリ消費量と通信データ量です。
動作負荷については、描画解像度やポリゴン数、光源の数によって制御できます。fpsをリアルタイムに計測することで比較的簡単に最適化できました。
一方、メモリ消費はデータサイズとある程度連動しているものの、どの程度が適切か調整するのに苦労しました。特にiOSでは、少しでも過負荷が検知されるとブラウザごと落ちてしまうため、デバッグするのも難しい状況でした。
結論としては、各テクスチャの解像度を落とすのが効果的でした。少ない数の高解像度テクスチャで構成するよりも、低解像度テクスチャがたくさんあった方が遥かに安定するようです。そこで肩/腕/腰などのパーツごとにテクスチャを分割し、PC用には2Kテクスチャ(2048 x 2048px)、モバイルには1Kテクスチャ(1024 x 1024px)を使用したglTFファイルを2つ用意して、出し分けるようにしました。
またglTFファイルに含まれる各テクスチャをWebP形式に変換することで、ファイルサイズの削減も行いました。
さて、前置きが長くなりましたが、これらの最適化処理を自動化するのがglTF Transformというツールです。Node.js上で動作します。
私はnpm-scriptsに組み込んで、コマンド1つでファイルを最適化できるように設定しました。
React
人気のあるWeb UIフレームワークの1つです。2DのUIと、アプリケーションとしての外枠部分はReactを使って実装しました。react-spring、react-tooltip、react-i18nextなどのプラグインも活用しています。
Babylon.jsとの連携は、babylonjs-hookというライブラリを使いました。これはReactアプリ内にBabylon.jsのcanvasを生成するのに特化した、非常にシンプルなライブラリです。つまり、ReactとBabylon.jsはかなりの疎結合になっています。
以前Three.jsのプロジェクトで、react-three-fiberという強力なライブラリ(ざっくり言うと、JSXで3D要素が宣言できる)を使っていたのですが、パフォーマンスの最適化や細部の作り込みが逆に難しく感じました。
今回、技術選定やファイル構成を考える際には、"Do one thing well"を心掛けました。
virtual-scroll
「スクロール」こそがこのプロジェクトにとって重要な要素です。
しかし、モバイルデバイスでは実際にページをスクロールすると、なめらかなスクロール再現のためにGPUリソースが占有され、3Dのフレームレートがかなり不安定になることに気付きました。
そこで、このプロジェクトでは本当のページスクロールは発生させないことにしました。代わりにタッチムーブやマウスホイールのイベントを検知して、擬似的なスクロールを再現しています。
それらを自力で実装するのは大変です。virtual-scrollライブラリには本当に助けられました。
Vite
Web用のビルドツールです。簡単に導入でき、驚くほどクイックに動作します。間違いなく開発スピードの向上に貢献してくれました。
このプロジェクトはReact + TypeScriptのテンプレートを使用しました。Babylon.jsの各Classは非常に複雑なプロパティやメソッドを持つのですが、VSCodeの補完機能と相まってTypeScriptの恩恵をとても大きく感じました。
ソースコード
GitHubにてソースコードを公開しています。
https://github.com/htanjo/goldran/
謝辞
黄金勇者ゴルドランを含む勇者シリーズは、子供の頃からの憧れでした。
二次創作ではありますが、この作品を作るのは本当に楽しかったです。
「黄金勇者ゴルドラン」はサンライズの著作物です。