マガジン

Three.jsで3Dブラウザゲームを作る:最初の一歩

遊びをつくる

執筆にClaudeを使用しています。

しおり・ハート・時計の目印が付いた棚から、小さなゲーム世界の本を取り出すイラスト
記事のテーマをもとに制作したAI生成イラスト。

ブラウザで動く3Dゲームを作りたいとき、最初に名前が挙がるのがThree.jsです。WebGL(ブラウザ上でGPUを使うための仕組み)を直接書くと数百行になる処理を、Three.jsは数十行に圧縮してくれます。インストール不要でCDNから読み込めるため、HTMLファイル一枚から始められるのも利点です。 ただし「3Dだからといって難しい」わけではなく、「2Dと違う概念をどこで覚えるか」が最初の壁になります。シーン・カメラ・レンダラーという三つの役割を理解し、最初の物体を画面に出す手順を一度通しで体験すると、その後の応用が急に楽になります。この記事ではその「最初の一周」を丁寧に追います。

この記事の目次
  1. Three.jsの基本構造を理解する
  2. 最初の3D物体を画面に出す手順
  3. ゲームに必要な要素をどう足すか
  4. よくある詰まりポイントと対処
  5. 2Dゲームと違うThree.js特有の設計判断
  6. 次の行動
  7. 参考資料

Three.jsの基本構造を理解する

Three.jsのコードは必ず次の三役で始まります。

  • シーン(Scene):3D空間そのもの。物体・光源・霧などをここに追加します。
  • カメラ(Camera):視点の位置と向きを決めます。ゲームでよく使うのは遠近感のある PerspectiveCamera です。
  • レンダラー(Renderer):シーンをカメラ越しに見た映像を、<canvas> に描画します。

この三役の関係は「舞台・観客席・スクリーン」に例えると覚えやすいです。舞台に置いた物体がどう見えるかは、観客席(カメラ)の位置によって変わり、スクリーン(レンダラー)に映像として出力されます。

物体を表示するには、さらに二つの要素が要ります。ジオメトリ(Geometry)が形状のデータ、マテリアル(Material)が色や質感のデータで、この二つを合わせたメッシュ(Mesh)をシーンに追加します。立方体を一つ出すだけでも、この流れを一通り書くことになるため、最初の一本が「Three.jsの全体像を学ぶ教材」になります。

最初の3D物体を画面に出す手順

以下の手順で、回転する立方体を表示する最小構成を組み立てられます。

1. Three.jsを読み込む

HTMLの <head> か <body> の末尾に次の一行を置きます。バージョンは公式サイトで最新のものを確認してください。

html
<script src="https://cdn.jsdelivr.net/npm/three@(バージョン番号)/build/three.module.js" type="module"></script>

importmap を使うとモジュール形式で import * as THREE from 'three' と書けて、後からビルド環境へ移行しやすくなります。ただし最初はCDNのscriptタグでも十分です。

2. シーン・カメラ・レンダラーを作る

js
const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(
  75,                              // 視野角(度)
  window.innerWidth / window.innerHeight, // アスペクト比
  0.1,                             // 近クリップ面
  1000                             // 遠クリップ面
);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

PerspectiveCamera の第一引数は視野角で、値が大きいほど広角になります。75度前後がゲームでよく使われる標準的な値です。

3. メッシュを作ってシーンに追加する

js
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

MeshBasicMaterial は光源の影響を受けないため、ライトを追加しなくても確実に色が表示されます。最初の動作確認にはこのマテリアルが便利です。

4. アニメーションループを回す

js
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

requestAnimationFrame はブラウザの描画タイミングに合わせて関数を繰り返し呼び出します。毎フレームごとに rotation を少しずつ変えることで回転アニメーションになります。

ゲームに必要な要素をどう足すか

立方体が回るだけでは当然ゲームになりません。次に追加するべき要素と、Three.jsでの対応方法を整理します。

光源と影:MeshBasicMaterial から MeshLambertMaterial や MeshStandardMaterial に変えると光源の影響を受けます。DirectionalLight(平行光源)と AmbientLight(環境光)の組み合わせが最初の定番です。光源を追加しないとマテリアルが真っ黒になるため、必ずセットで追加します。

キー入力と当たり判定:Three.jsはレンダリングのライブラリであり、物理エンジンや入力管理は含んでいません。キー入力は keydown / keyup イベントで自前管理するのが基本です。当たり判定が必要なゲームでは、Cannon.jsやRapierといった物理エンジンをThree.jsと組み合わせる方法が一般的です。

GLTFモデルの読み込み:複雑な形状は THREE.GLTFLoader で .glb ファイルを読み込みます。Blenderなどで作ったモデルをGLTF形式でエクスポートし、loader.load('model.glb', (gltf) => { scene.add(gltf.scene); }) のパターンで追加できます。GLTFLoader はThree.jsの本体には含まれず、three/examples/jsm/loaders/GLTFLoader.js から別途インポートが必要です。

カメラ操作:OrbitControls(マウスでぐるぐる視点を回す機能)も同じく examples/jsm 以下にあります。ゲームのデバッグ中に視点を自由に動かしたいときに重宝します。

よくある詰まりポイントと対処

画面が真っ黒になる:原因の多くは「カメラが物体を向いていない」「ライトが必要なマテリアルを使っているがライトを追加していない」「renderer.render() の呼び忘れ」の三つです。MeshBasicMaterial に変えて試すことで、ライトの問題かどうかを切り分けられます。

モデルが表示されない:GLTFファイルをローカルで file:// プロトコルから読もうとするとCORSエラーになります。VSCodeの「Live Server」拡張や npx serve などで簡易的なローカルサーバーを立ち上げてから読み込みます。

フレームレートが落ちる:アニメーションループ内でジオメトリやマテリアルを毎フレーム生成していないか確認します。new THREE.BoxGeometry() はループ外で一度だけ作り、参照を使い回すのが基本です。同じ形状を大量に表示したい場合は InstancedMesh を使うと描画コールを減らせます。

ウィンドウリサイズへの対応:初期サイズで固定したままだと画面を広げたときに映像が引き伸ばされます。window.addEventListener('resize', ...) でカメラのアスペクト比と renderer.setSize() を更新するコードを一つ追加するだけで解決します。

2Dゲームと違うThree.js特有の設計判断

2Dキャンバスゲームに慣れた人がThree.jsで詰まりやすいのが「座標系の違い」です。Three.jsはデフォルトで右手座標系を使い、Y軸が上、Z軸が手前(画面手前方向)です。2Dゲームで慣れた「左上が原点・Y軸が下」とは異なるため、最初に意識して覚えておく価値があります。

パフォーマンス設計も2Dとは異なります。3Dでは「ドローコール(描画命令の回数)」を減らすことが重要で、テクスチャは一枚の画像に複数のパターンをまとめた「テクスチャアトラス」にする、同じジオメトリを使い回す、見えないオブジェクトは visible = false にしてシーンから外す、といった判断がゲームの規模が大きくなると効いてきます。最初の小さなゲームでは気にする必要はありませんが、「重くなってきたら何を見直すか」を知っておくと詰まったときに早く対処できます。

Three.jsは公式サイトにドキュメントと多数のサンプルが用意されており、コードをブラウザ上でそのまま編集して動作確認できます。新しい機能を試したいときは、まずそのサンプルをコピーして改変する方法が最も効率よく学べます。

次の行動

まずThree.jsの公式サイトにある「Getting Started」のサンプルを手元のHTMLにコピーし、立方体を表示するところまで動かしてみてください。それができたら色・サイズ・回転速度を一つずつ変えて、各パラメータが何に影響するかを確かめると理解が定着します。ゲームとして公開できる形になったら、ZIPまたはHTMLとしてアソバースに投稿する方法も選択肢の一つです。

参考資料

  • Three.js 公式ドキュメント(threejs.org)
  • Three.js 公式サンプル集(threejs.org/examples)
  • MDN Web Docs:WebGL の概要