3D/CG

NOCTE #00|AIと一緒に、歩ける3D空間の土台を作る

AI・Blender・React Three Fiberで作る、歩ける3D空間NOCTE。第0回は白い地面から始め、200m四方の寸法、一人称移動、性能と通信量の基準値を用意します。
Published
Author
SHIZUYA
NOCTE #00|AIと一緒に、歩ける3D空間の土台を作る

SHARE

この記事を共有

XLINEBluesky

はじめに

水面に光が映り、立方体が静かに浮かぶ。そんな空間をWebブラウザで自由に歩けるようにする、NOCTE — A Quiet Space to Explore の制作を始めました。

AIに実装を手伝ってもらい、Blenderで形を作り、React Three FiberでWebへ持ち込む。完成までの過程を、全8回の制作ログとして残していく予定です。

NOCTEの完成イメージ。水面、浮遊する立方体、発光するフレームと月を配置した参考画像

目指す空間の参考画像です。今回の実装画面ではありません。

第0回で作るのは、この景色を支える土台です。Unityの初期シーンのように、白い地面と太陽光を置き、まずは歩ける状態にします。今回は、広さを決める、移動できるようにする、性能を測る。この三つを進めます。

  • 広さの基準:1 unit=1mとし、200m四方を仮に設定する。
  • 歩ける操作:マウスで見回し、歩く・走る・跳ぶ。
  • 比較できる記録:今の描画性能と通信量を残す。

AIにまとめて作ってもらう方法もありますが、後から形や配置を調整するなら、何を足したのか分かる状態で進めた方が扱いやすいと思うのです。水面やモデルを加える前に、空間の寸法と動作の基準を用意しておきます。

この記事では、細かなコード解説よりも、AIに何を頼み、できたもののどこを確かめたかを中心に紹介します。キーボードとマウスのあるPCを使い、手順を追いながら試せる構成です。

白い地面から始めるNOCTEの制作を、SellaとNeroが一緒に考える導入イラスト

STEP 1|制作環境を用意する

最初に、AIへNext.jsとTypeScriptを使った制作環境の準備を頼みました。3Dの描画にはThree.js、そのシーンをReactで組み立てるためにReact Three Fiber(R3F)を使います。

役割を大まかに分けると、Reactが画面や設定の状態を管理し、Three.jsが3Dを描画し、R3Fが両者をつなぐ、という関係です。Blenderで形を作るのは次回からになります。

Sellaと見るReact・R3F・Three.jsの役割。Reactが状態を管理し、R3FがThree.jsのシーンをReactの部品として組み立て、Three.jsが3Dを描画する

用語の図解は、タップすると原寸画像を開けます。

以下の指示例は、実際に渡した指示を、記事で使いやすい長さに整理したものです。一度にすべて作らせず、各段階で起動と表示を確かめてから先へ進めます。

Next.jsとTypeScriptで、ブラウザ上に3D空間を作るための最小構成を用意してください。Three.js、React Three Fiber、Dreiを導入し、互換性と使用バージョンを確認してください。まずはローカル起動と本番ビルドまで確かめ、移動や演出はまだ追加しないでください。

Next.jsのプロジェクトに3D用のライブラリを追加する場合、基本となるコマンドは次のとおりです。Node.jsとnpmが使える環境で、プロジェクトのフォルダを開いて実行します。

bash
npm install three @react-three/fiber @react-three/drei

これはライブラリを追加するためのコマンドで、これだけで3D画面が完成するわけではありません。今回はAIが設定ファイルや画面を用意し、バージョンを固定して導入しました。ReactとR3Fの対応などは、R3F公式の導入ガイドでも確認できます。

起動は npm run dev。ブラウザに準備用の画面が表示されたら、次の段階へ進みます。

今回使ったライブラリとバージョン

記録時点の構成は、Next.js 16.4.0、React 19.3.0、TypeScript 7.0.2、Three.js 0.186.1、React Three Fiber 9.8.1、Drei 10.7.9です。

DreiはR3F向けの便利な部品を集めたライブラリ。導入はしていますが、第0回の実装では個別の部品をまだ使っていません。実際の準備は設定ファイルの作成から始め、固定した依存関係をインストールしました。

STEP 2|広さを決め、歩けるようにする

今回は、1 unit=1m を共通のルールにしました。後からBlenderで作るモデルも、この基準に合わせます。

空間の広さは、100m・150m・200m四方の候補を比較しました。ここで比べたのは実際に歩いた時間ではなく、移動速度を4m/sとしたときの計算上の目安です。

一辺の長さ端から端までの時間
100m約25秒
150m約37.5秒
200m約50秒

障害物のない直線移動なら「距離÷速度」で求められます。4m/sは、この体験のために選んだ設定で、現実の一般的な歩行速度を再現した値ではありません。

ひとまず200m四方を仮採用し、目線は1.65m、垂直方向の視野角(FOV)は60度にしました。寸法だけで広さの感じ方が決まるわけではないので、歩けるようにしてから調整します。

Neroと見る空間の基準。1 unitを1mとし、地面は200m四方を仮設定。カメラの側面図で地面からの目線1.65mと垂直FOV60度を示す

200m四方の白い地面と太陽光を用意してください。1 unit=1m、目線1.65m、垂直FOV60度、歩行4m/sを初期値にします。WASD移動、マウスでの見回し、Shiftで走行、Spaceでジャンプに対応させてください。Escで操作を解除し、Rで初期位置へ戻れるようにしてください。

できた空間には、距離の目安になるグリッドと境界線も加えました。走行速度は歩行の1.75倍、7m/sです。

操作キー・動作
操作を始める画面をクリック
歩く・見回すWASD・マウス
走る・跳ぶShift・Space
操作を解除するEsc
初期位置に戻るR
移動とジャンプは、どう動いている?

クリックするとPointer Lock APIでマウスを捕捉し、移動量から視線を更新します。上下の角度を制限して、カメラが反転しないようにしました。

前進方向にはカメラの左右の向きだけを使うため、上を向いても地面に沿って進みます。斜め入力は方向ベクトルを正規化し、前進だけのときより速くならないようにしています。

移動距離は「速度×前フレームからの経過秒」で計算。ジャンプは初速5m/sと重力9.81m/s²で高さを更新する自前の処理で、着地時に地面へ戻します。空中での再ジャンプはできません。

今は平らな地面と外周の制限まで。後から置くモデルとの衝突判定や、坂道・段差への対応は、まだ実装していません。

STEP 3|何も置いていない今を測る

後からモデルや水面を加えたとき、見た目と一緒に動作も変わります。そこで、まだ何も置いていない状態を、比較の出発点として記録することにしました。

Neroと読む性能指標。FPSは毎秒の画面更新回数、今回のFrame Timeは描画呼び出し終了時刻の間隔、Draw Callsは描画命令の回数、Trianglesは三角形の数。線は別に数え、GPU単体の処理時間とは区別する

画面の隅にFPS、Frame Time、Draw Calls、Trianglesを小さく表示してください。30秒間の測定結果をJSONで保存できるようにし、画面サイズや描画DPRなどの条件も一緒に残してください。

画面上の小さな数値表示をHUDと呼びます。今回は、空間を見る邪魔にならないよう左上に置いています。

白い地面を歩いているNOCTEの実画面。左上にFPS、Frame Time、Draw Calls、Trianglesを表示している

今回の実装画面。HUDの118.2 FPSなどは歩行中の1秒平均で、下の30秒測定とは別の値です。

計測には、開発中の画面ではなく本番ビルドを使いました。開発サーバーとは別のターミナルを開き、プロジェクトのフォルダで次を順に実行します。

bash
npm run build
npm run start -- --port 3001

ブラウザで http://127.0.0.1:3001 を開き、Escで操作を解除。右下の「設定 / 計測」から「待機を測定」を選び、終了後に「JSONを保存」で記録を残せます。JSONは、数値と条件を後から読み返せるデータ形式です。

今回残した基準値は、この本番画面をBraveで開き、立ち止まったまま、連続描画を30秒間測った結果です。歩行中の性能をまとめた値ではありません。

項目測定値
平均FPS約120
平均Frame Time8.33ms
Frame Timeの95パーセンタイル9.60ms
Draw Calls3
Triangles2

95パーセンタイルは、測定したフレーム間隔の約95%がその値以下だった、という目安です。平均だけでなく、少し遅くなった側の様子も残しています。

測定条件と、数値の読み方

2026年10月12日、本番ビルド・Brave・描画DPR 1で測定しました。画面は約1288×1239 CSS px、Canvasの実寸は1287×1238px。ブラウザのズームは90%で、DevToolsを閉じ、1秒の準備時間のあとに30秒記録しています。

測定機はMacBook Pro(機種ID:MacBookPro18,2)、macOS 26.3.1、Brave 155.1.97.56。チップ名は記録していません。ブラウザ操作用の拡張機能は有効な状態です。

Draw CallsとTrianglesは、描画直後のThree.jsのrenderer.infoから取得。Frame Timeはperformance.now()で描画呼び出し終了時刻どうしの間隔を測り、その平均からFPSを求めています。GPU単体の処理時間を測った値ではありません。

Draw Calls 3は地面・グリッド・境界線。Triangles 2は地面を作る三角形で、グリッドや境界線は線として別に数えられます。200m四方という広さだけで、三角形の数が増えるわけではありません。参考:Three.jsの計測項目

60 FPSを目指すなら、1フレームの目安は約16.7msです。ただし、今回の約120 FPSが、どのPCでも出るわけではありません。今後はできるだけ同じPC、ブラウザ、画面サイズ、カメラ位置で測り、何を足したときにFrame Timeが伸びたかを見ていきます。

STEP 4|読み込むデータ量も確認する

画面が滑らかに動くかとは別に、最初にどれだけのデータを読み込むかも確認しておきます。次回以降、モデルやテクスチャを持ち込むときの比較に使うためです。

Chromeの開発者ツールなら、次の順で確認できます。

  1. アプリを開き、開発者ツールの Network タブへ進む。
  2. Disable cache をオンにし、通信記録を消してから再読み込みする。
  3. 読み込みが落ち着いたら、一覧のいちばん下の集計欄を見る。
  4. transferred と resources を、それぞれ記録する。

transferred は転送量、resources は展開後のリソースサイズです。同じ数字ではないので、分けて残します。確認する場所は、Chrome DevTools公式の集計表示の説明でも紹介されています。

今回はBraveのDevToolsで測定しました。Chromeでの実測は、まだ行っていません。 キャッシュを無効にして再読み込みし、対象アプリの通信に絞ると、14件、転送量は約396kB、展開後は約1.40MBでした。

Sellaと読む通信量。Network下部のtransferredは実際に転送した量で約396kB、resourcesは展開後のリソースサイズで約1.40MB。今回のBraveでの測定を説明した図で、実際のDevTools画面ではない

フィルターには domain:127.0.0.1 を指定し、拡張機能の通信と分けています。実際に確認する際は、自分のアプリのドメインに合わせます。

なお、これはDevToolsを開いて行った別の測定です。前の節のFPSはDevToolsを閉じて記録しており、条件を混ぜないようにしています。

STEP 5|歩いて、広さの感覚を確かめる

土台ができたら、画面をクリックして歩いてみます。最初は次の順に確認すると、調整する場所を見つけやすそうです。

  1. まっすぐ歩き、端までの距離がどう感じられるかを見る。
  2. 周囲を見回し、視野角やマウスの動きが合うか確かめる。
  3. 走行とジャンプを試し、移動の速さや高さを見る。
  4. 広さか速度のどちらか一方を変え、元の状態と比べる。

クリックでの開始、WASD移動、走行、ジャンプ、Escでの解除、RでのリセットはBraveで動作を確認しました。実マウスで見回したときの操作感や、歩行動画の収録は、引き続き確認していく部分です。

見た目を加えると、歩きやすさだけでなく、描画の負荷も変わります。まだ追加後の数値はありませんが、次のような点を記録していく予定です。

モデルや演出を加えたら、何が増える?
  • 別々に描くメッシュや材質が増えると、Draw Callsが増えやすくなります。
  • 細かいモデルでは三角形や頂点の数、大きなテクスチャでは通信量やGPUメモリの使用量に注意します。
  • 影、反射、透明表現、後処理は、追加の描画や画素の処理によってFrame Timeが伸びる要因になります。
  • 同じ画面サイズで描画DPRを1から2にすると、縦横がそれぞれ2倍になり、処理する画素数は4倍になります。

繰り返し置く物体にはインスタンシング、遠景には細部を減らすLODなどが候補です。ただ、三角形が少なくても反射や高解像度で重くなることがあります。一律の上限を決めるより、追加前後を同じ条件で比べていきます。参考:R3Fの性能改善ガイド

次回は、Blenderで寸法と配置を考える

今回は、空間の広さ、歩ける操作、性能と通信量の基準値まで用意しました。まだ白い地面だけですが、ここからモデルを足し、変化を確かめていける状態になりました。

次回はBlenderで、簡単な形を使って寸法や配置を考える「グレーボックス」を作ります。中央のフレームはどれくらいの大きさにするか。立方体の間を通れるか。今回の200m四方を仮の基準に、測りながら組み立てていく予定です。

NOCTEの制作ログ:全8回の予定
  • #00 歩ける3D空間の土台を作る — 今回。環境、移動、寸法、計測。
  • #01 Blenderで寸法を決める — グレーボックスで大きさと配置を考える。
  • #02 BlenderのモデルをWebへ — GLBを書き出し、R3Fに読み込む。
  • #03 水面を作る — AIでの素材生成やノーマルマップを試す。
  • #04 発光するフレームを作る — 発光マテリアルとBloom、負荷の比較。
  • #05 空間の演出を追加する — 浮遊オブジェクト、月、空、照明。
  • #06 描画を最適化する — インスタンシング、モデル統合、テクスチャの見直し。
  • #07 完成と性能測定 — ワールドの公開と制作全体の振り返り。

内容や順番は、制作の結果に合わせて調整します。

少しずつ作り、測って、調整する。AIに実装を手伝ってもらいながら、自分でも扱える部分を増やしていくと、完成後の空間も、もっと自由に変えていけるのではないかと思うのです。

SHARE

この記事を共有

XLINEBluesky

AUTHOR

SHIZUYA

Creative Developer / Designer / Musician

フロントエンド開発、3D表現、AI活用、音楽制作などを横断しながら、美しく機能する体験を追求しています。