WebGLライブラリを作ってみよう

はじめに

 R&D Slack管理人のemadurandalです。

今はUnityやUnreal Engineなどの便利なゲームエンジンがたくさんあるので、詳細を知らなくても3Dキャラやエフェクトが派手に動く凄いゲームを簡単に作れてしまいます。

「どういう仕組みでこれらのゲームは動いているんだろう」と思ったことはないでしょうか。

別コーナーの「WebGLでゲームを作る」では、ブラウザで実行できる手軽な3DAPIであるWebGLで今どきの本格的なゲームを作ることは可能である、と説明しました。

しかしながら、こうした3D APIをただ愚直に呼び出すだけでは、本格的なゲームを作ることは困難です。多くのゲームでみられる、「よくある共通の処理」を効率的に実行する仕組みをソフトウェアとして設計する必要があります。いわば、UnityやUnreal Engineに相当する部分が必要です。

この記事連載では、そうしたゲームエンジンまたはライブラリに相当するものを、WebGLとTypeScript言語を使って自作を試みます。

連載を通してWebGLライブラリをゼロから作っていくことで、以下のことを学ぶことができます。

  • WebGL APIの使いこなし
  • レンダリングライブラリやゲームエンジンの設計の考え方
  • スケルタルアニメーション(キャラアニメーション)や物理ベースレンダリングなどの、ゲームでよく使われるテクニックの習得

 いかがでしょう。ワクワクしてきませんか?

進行の予定

全体の進行としては、以下の流れで行こうと考えています。

  1. プロジェクトを作ろう
  2. 三角形を描画してみよう
  3. ライブラリっぽくしてみよう
  4. ユーザー指定のシェーダーを使えるようにしよう
  5. クラス構文を使ってもっとライブラリっぽくしよう
  6. 色んな種類のポリゴンデータを表示できるようにする
  7. glTFからポリゴンデータを読み込む
  8. glTFから読み込んだポリゴンデータを表示する
  9. glTFのマテリアルを描画に反映しよう
  10. glTFで全てのプリミティブを表示しよう
  11. トランスフォーム(姿勢の変換)について理解する
  12. プロジェクト全体をリファクタリングする
  13. 行列クラスを作成する
  14. クォータニオンクラスを作る
  15. トランスフォームクラスを作る
  16. エンティティとTransformコンポーネントを作る
  17. SceneGraphコンポーネントを作る
  18. Meshコンポーネントを作り、glTFから位置情報も読み出す
  19. Cameraコンポーネントを作る
  20. リファクタリングする
  21. Orbitカメラコントロールを追加する
  22. AABBを実装する
  23. Walkカメラコントロールを追加する
  24. テクスチャに対応する
  25. glbに対応する
  26. 古典的ライティングを実装する。
  27. アニメーションを実装する。
  28. スケルタルアニメーション(キャラクターアニメーション)を実装する。
  29. シャドウマッピング(影描画)を実装する。
  30. VR(WebXR)に対応する。
  31. 物理ベースレンダリングを実装する。
  32. ブレンドシェイプを実装する。
  33. VRoid Studioで作ったVRMキャラを動かしてみよう
  34. VRoid Studioで作ったVRMキャラを使って3Dアクションゲームを作ってみよう
  35. コラム:2021年5月現在のTypeScriptとES Moduleの状況

 最後までいければ、ゲームエンジンとまではいかなくとも、一端のレンダリングライブラリを名乗るくらいのところまでいけるでしょう。その後は、皆さんでどんどん拡張していってください。

ライブラリのポリシー

 ライブラリを自作するにあたって、ポリシーを決めたいと思います。検討を重ねた結果、次のように落ち着きました。

  • シンプルさを最優先する
  • TypeScriptを採用する

シンプルさを最優先する

当初この連載では、ライブラリを作ることよりもスケルタルアニメーションや物理ベースレンダリングなどのテクニックをお伝えすることを意図していました。しかし、扱う内容が内容だけに3D APIを呼び出すだけでなく、ボーンやマテリアルを分かりやすく扱うためのクラス群を作らなければ、可読性の良いプログラムになりません。

 ならばいっそのこと、シンプルな3Dライブラリを作っていくことをテーマにしよう、ということになりました。

 しかし、ふつうの人はこみ入った設計や実装ではコードを見ただけで嫌になってしまいます。そのため、容易にコードを理解できるシンプルさを重視します。最適化などで読みにくいコードになってしまったり、コード量が増えることは避けるということです。

その引き換えとして、最適化を行わないために処理効率の点はある程度諦めることになります。

TypeScriptを採用する

TypeScriptについては導入の手間や文法の学習コストがありますが、同言語の型チェックにはそれを十二分に正当化できるほどの恩恵があります。

素のJavaScriptでは、ささいなスペルミスや型の不一致によるエラーを、実際に動かして遭遇するまで気づくことができません。一つ直して再度実行しても他の部分でまたエラー。これをエラーが無くなるまで都度ブラウザを立ち上げて実行・操作しなければならない過大なストレスの大半はTypeScriptを採用するだけで減らすことができます。

実際にJavaScript系のライブラリ開発では、ほとんどの現場でJavaScriptではなくTypeScriptが選択されています。

ライブラリの名前はーー「スピネル」

 せっかくなので、この連載で開発するライブラリに名前をつけることにしました。私事ですが、個人的に宝石や鉱物から名前を取ることがマイブームになっています。このライブラリには「スピネル」という名前をつけました。「Spinel 」です。宝石ですから、きれいなライブラリに育ってくれるといいですね。

読み進めるにあたって

各回で、新たに記述するコードや作業について大まかに解説をしていますが、後半に行くほど、指示の通りにお手元で実施してもうまくビルドできない可能性が高いです。これは、後半に行くほどコード編集の量が多くなり、全ての作業をテキストで解説しきれないためです。そのため、各回でのコード説明は主要な変更点の概略を掴むためのものとご理解いただき、細部・全体のコード変更については各回の最後で案内するGit履歴(Gitタグ)の方をご確認ください。

 次回から、さっそく内容に入っていきます。

1日目:プロジェクトを作ろう >>