SpaceX社が推進する衛星インターネット計画「Starlink(スターリンク)」は、高度約550kmの地球低軌道(LEO)にすでに6,000機以上を配備し、最終的には数万機規模の巨大人工衛星網(メガコンステレーション)を構築しようとしています。地球の夜空を見上げると、夜間や夕暮れ時に無数のスターリンク衛星が光の帯となって横切る光景が日常のものとなりつつあります。
SatViewer3Dでは、この前代未聞の規模で地球を取り囲むスターリンク衛星群を、PCだけでなくスマートフォンのWebブラウザ上でも遅延なく(60fps固定で)スムーズに3D追跡・描画するアーキテクチャを確立しました。本記事では、数千個の動的オブジェクトを描画する際のGPUボトルネックの解消法と、Three.jsにおけるInstancedMeshの高度な最適化テクニックを解説します。
1. なぜ素朴な実装(Individual Mesh)は即座にフレーム落ちするのか?
Three.jsで数千機の衛星を描画しようとする際、初心者が最も陥りがちなアプローチは、衛星ごとにnew THREE.Mesh(geometry, material)を生成してシーンに追加することです:
// ❌ 致命的なパフォーマンス低下を招くアンチパターン
satellites.forEach(sat => {
const mesh = new THREE.Mesh(satGeometry, satMaterial);
scene.add(mesh);
// 毎フレーム個別に座標を更新
});
この実装で衛星数が500機を超えると、最新のハイスペックPCであってもフレームレートが20fps以下に急落し、スマートフォンではブラウザがクラッシュするかフリーズします。その主な原因は以下の3点にあります:
- ドローコールの爆発(Draw Call Overhead): 1つのメッシュを描画するたびに、CPUからGPUへ「描画命令(Draw Call)」とコンテキスト切り替えが発行されます。数千回のドローコールはGPUのパイプラインを飽和させます。
- シーングラフ走査のCPU負荷: Three.jsは毎フレーム、シーン内の全オブジェクトのワールド行列(
updateMatrixWorld)を再帰的に走査・計算するため、CPUのメインスレッドが計算で圧迫されます。 - メモリの細分化: 数千個のJavaScriptオブジェクトがヒープ上に分散し、ガベージコレクション(GC)のスパイクが発生して定期的なカクつき(Stuttering)を引き起こします。
2. `THREE.InstancedMesh` による1ドローコール描画アーキテクチャ
この課題を解決する唯一無二の技術が、GPUのハードウェア・インスタンシング(Hardware Instancing)を活用したTHREE.InstancedMeshです。
衛星の基本メッシュ構造(ソーラーパネルとバス本体)の頂点データとテクスチャをGPUのVRAM(ビデオメモリ)に1度だけ転送しておき、各衛星の「4x4変換行列(位置・回転・スケール)」を1本の連続した型付き配列(Float32Array)としてGPUへ一括ストリーミングします。
// ⭕ 2,000機以上の衛星をわずか1回のドローコールで描画する設計
const count = 3000;
const geometry = new THREE.BoxGeometry(1, 0.4, 0.4);
const material = new THREE.MeshBasicMaterial();
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
const color = new THREE.Color();
// アニメーションループ内での座標一括更新
function updateSatellites(satellitePositions) {
for (let i = 0; i < satellitePositions.length; i++) {
const { x, y, z, status, isSelected } = satellitePositions[i];
dummy.position.set(x, y, z);
dummy.lookAt(0, 0, 0); // 常に地球中心を向く姿勢制御
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
// 稼働状況や選択状態に応じた動的カラーリング
if (isSelected) {
color.setHex(0xff0055); // ハイライト
} else {
color.setHex(status === 'active' ? 0x00ffcc : 0x888888);
}
instancedMesh.setColorAt(i, color);
}
// GPUバッファのフラグを立てて一括転送
instancedMesh.instanceMatrix.needsUpdate = true;
if (instancedMesh.instanceColor) instancedMesh.instanceColor.needsUpdate = true;
}
この設計により、描画にかかるドローコールは完全に「1回」に集約されます。CPUのオーバーヘッドは劇的に削減され、iPhoneや低価格帯のAndroid端末でも60fpsのヌルヌルとした滑らかな回転操作を実現しました。
3. Web WorkerによるSGP4軌道計算のマルチスレッド並列化
描画パイプラインのボトルネックが解消された後、次に直面したのが「軌道力学計算(SGP4)のCPU負荷」です。各Starlink衛星の最新二行軌道要素形式(TLE: Two-Line Element set)から現在の緯度・経度・高度を割り出すSGP4アルゴリズムは、三角関数や浮動小数点演算を大量に消費します。
メインスレッドで2,000機分のSGP4計算を毎フレーム実行すると、ユーザーのタッチ操作やUIのイベントループがブロックされてしまいます。そこでSatViewer3Dでは、バックグラウンドのWeb Workerに軌道伝播計算を完全にオフロードしました。
- Web Workerが最新エポック時刻に基づいて2,000機分の3D直交座標 $(X, Y, Z)$ を計算。
- 結果を1本の
Float32Array(3,000 × 3 = 9,000 floats、わずか36KB)にパッキング。 postMessageの第2引数に[buffer]を渡すTransferable Objects(ゼロコピー転送)を利用し、メインスレッドへのメモリコピー時間を0ミリ秒に抑制。
4. 新規打ち上げ「スターリンクトレイン」の連動追跡と光害シミュレーション
SpaceXがFalcon 9ロケットで1回に約20〜23機のStarlink衛星を打ち上げた直後、数十機の衛星が数キロメートル間隔で一列に並んで数珠つなぎのように夜空を周回する「スターリンクトレイン(Starlink Train)」が世界各地で目撃されます。
SatViewer3Dでは、最新打ち上げ群(Launch Group)をAPIから自動検出し、トレイン状態の衛星群だけをワンクリックでネオンカラーにハイライト表示するプリセットフィルターを実装しました。
また、衛星表面の反射太陽光が地上の光学天文台に与える影響(光害問題 / Satellite Mega-constellation Light Pollution)を客観的に観察できるよう、太陽光の入射角と衛星のソーラーアレイの向きから「地上での見かけの等級(視等級)」を概算する簡易アルゴリズムも組み込み、科学教育・天文啓発ツールとしての実用性を高めています。
5. まとめと宇宙状況把握(SSA)のオープン化
数千機の衛星がひしめく新宇宙時代において、軌道上の状況を誰もが手元のスマートフォンで直感的に把握できることは、宇宙工学の民主化において極めて重要な意義を持ちます。
WebGL、GPU Instancing、Web Workerというモダンブラウザ標準の技術を極限まで活用することで、専用の高価な宇宙管制ソフトに匹敵するビジュアライゼーションをWeb上に構築できました。ぜひSatViewer3Dを開き、地球を覆い尽くすスターリンクの壮大なフリートを体感してみてください。