[Next.js #48] Three.js × InstancedMeshによる400万ボクセル描画

はじめに

前回の記事([Next.js App Router #47] Procedural Solar System VR)では、宇宙空間の天体をプロシージャルに生成し、VR空間に展開しました。

今回は視点を「大地」へと移します。 ベースとなる理論は、別シリーズの[Noise 入門 #42] で解説した InstancedMesh によるボクセル生成 です。当初の記事では「1回のDraw Callで10万個のブロックを描画する」というテーマで解説しました。

しかし、私の開発環境(Core i7-12700K + RTX 4070 Ti)で10万個を描画しても、GPU使用率はわずか数パーセント。

そこで今回は、「現PCで一体どこまでブロックを敷き詰められるのか?」 という限界突破のストレステスト(ベンチマーク)を行ってみました。

1. パラメータによる地形のリアルタイム変形

まずは実際の動作風景をご覧ください。 (※遠景の描画限界を見るため、今回はあえて環境フォグ(FogExp2)をオフにしています)

動画(FogExp2 オン):

前半では、画面右上のインスペクター(lil-gui)からノイズのパラメータを操作しています。

  • Scale: 地形のなだらかさ
  • Amplitude: 最大高低差(山の高さ)
  • Octaves / Persistence / Lacunarity: FBMノイズの複雑さ(ギザギザ感)

JavaScriptのメインスレッドで fbm() 関数を再計算し、その結果を Math.floor で整数化(ボクセル化)して setMatrixAt に流し込んでいます。数十万個のブロックの座標が、スライダーの動きに合わせてリアルタイムにうねる様子は、まさに数式が形を持つ瞬間です。

2. 限界突破:400万個のボクセルと影の演算

動画の後半では、いよいよ本題のストレステストに移行します。 Stats パネルでFPSを、タスクマネージャーでGPU(RTX 4070 Ti)の負荷を監視しながら、Grid Size を引き上げていきます。

  • 10万個(約 316 × 316): 余裕の60FPS。GPU負荷は一桁台。
  • 240万個(約 1550 × 1550): まだ60FPSを維持。
  • 400万個(2000 × 2000): ついに限界の領域へ。

400万個のブロックを配置した瞬間、GPU使用率は93%〜98% まで跳ね上がりました。FPSも一瞬落ち込み、RTX 4070 Ti がついに牙を剥かれた状態です。

この絶大な負荷の原因は「ポリゴン数」ではありません。InstancedMesh によって Draw Call は1回に抑えられていますが、「400万個のキューブが互いに影(Shadow Map)を落とし合う計算」 がGPUのシェーダーユニットを極限まで酷使しているのです。

とはいえ、負荷MAX状態でも温度が34℃〜35℃付近で安定しているのは、さすがのハードウェア性能といったところでしょうか。

3. 「AIが生成した動画」と「エンジニアのリアルタイムレンダリング」

最近、YouTubeなどで「AI(Geminiなど)にプロンプトを与えてMinecraftのような世界を作らせてみた」という動画がバズっています。

確かにAIが描き出す滑らかな曲線や世界観は魔法のようです。

しかし、私たちが今ブラウザ上でやっているのは、それらとは根本的に異なります。 単なる「動画」の出力ではなく、「1フレーム(16.6ms)の間に、400万個のデータを計算し、行列を更新し、影をシミュレーションして、ユーザーが介入できる(動ける)空間として出力する」 リアルタイムエンジニアリングです。

  • どこで Draw Call のボトルネックが発生するのか?
  • CPUとGPUの役割分担はどうなっているのか?
  • 影の解像度がパフォーマンスにどう直結するのか?

限界まで負荷をかけることで見えてくるこれらの「物理的な境界線」は、自らコードを書き、ハードウェアを唸らせたエンジニアだけが知ることができる手触りです。

次回の予告:無機質な世界に「バイオーム(生命)」を

圧倒的なスケールの大地を生成し、ハードウェアの限界地点(スイートスポット)は把握できました。

しかし、現在の世界は「全て同じ緑色のブロック」で構成されているため、どこか無機質です。 次回は、この数十万〜数百万のブロック群に対して、標高(Y座標)に基づいた動的なカラーリング(海、砂浜、草原、雪山) を実装します。

InstancedMesh に備えられたもう一つの強力な武器、setColorAt を用いて、この緑一色の荒野を「色鮮やかな惑星」へと進化させます。