1. はじめに
ブラウザ上で数万〜数十万規模のパーティクルやエンティティを扱うシミュレーションや、WebGPUを用いた描画処理では、「計算コストの爆発」が避けて通れない課題になります。
すべてのオブジェクトに対して毎フレーム座標更新や衝突判定を行っていては、CPU・GPUともにすぐ限界に達してしまいます。
本記事では、この問題に対する実用的なアプローチとして、画面外のオブジェクト計算を大胆に省略する「確率雲(Probability Cloud)」という設計手法を紹介します。
2. 確率雲アプローチの基本概念
この手法の本質は非常にシンプルです。
「画面に見えていないものは、個体として存在させない」
オブジェクトの状態を次の2つに分けて管理します。
■ 画面外(確率雲状態)
-
個別の座標や速度は持たない
-
群れ全体を以下のような統計データで表現
- 平均位置(center)
- 平均速度(velocity)
- 密度・分布(spread)
- 個体数(count)
■ 画面内(実体状態)
- 実際のエンティティとして生成
- 各オブジェクトを個別にシミュレーション
この切り替えにより、計算量は次のように変化します:
- 画面内:O(N)(通常の個別計算)
- 画面外:O(1)(統計データ更新のみ)
たとえば10万個のオブジェクトが存在する場合でも、画面に映る1,000個だけを計算し、残りは「1つのデータ」として扱えます。
3. 実装イメージ(JavaScript)
以下はシンプルな実装例です。
/**
* 確率雲マネージャー
* 画面外では統計データのみ保持し、必要時に実体化する
*/
class ProbabilityCloudManager {
constructor(totalCount) {
this.cloudData = {
count: totalCount,
averageVelocity: { x: 0.5, y: 0.2 },
centerPosition: { x: 5000, y: 5000 },
spreadRadius: 500
};
this.activeEntities = [];
this.isVisible = false;
}
update(cameraRect) {
const distanceToCamera = Math.hypot(
this.cloudData.centerPosition.x - cameraRect.x,
this.cloudData.centerPosition.y - cameraRect.y
);
const threshold = 1000;
if (distanceToCamera < threshold && !this.isVisible) {
this.spawnEntities();
} else if (distanceToCamera >= threshold && this.isVisible) {
this.compressToCloud();
}
if (this.isVisible) {
// O(N)
for (let ent of this.activeEntities) {
ent.x += ent.vx;
ent.y += ent.vy;
}
} else {
// O(1)
this.cloudData.centerPosition.x += this.cloudData.averageVelocity.x;
this.cloudData.centerPosition.y += this.cloudData.averageVelocity.y;
}
}
spawnEntities() {
this.isVisible = true;
this.activeEntities = [];
for (let i = 0; i < this.cloudData.count; i++) {
this.activeEntities.push({
x: this.cloudData.centerPosition.x + (Math.random() - 0.5) * this.cloudData.spreadRadius,
y: this.cloudData.centerPosition.y + (Math.random() - 0.5) * this.cloudData.spreadRadius,
vx: this.cloudData.averageVelocity.x + (Math.random() - 0.5),
vy: this.cloudData.averageVelocity.y + (Math.random() - 0.5)
});
}
}
compressToCloud() {
this.isVisible = false;
// 実運用ではここで統計量を再計算する
// (平均位置・速度など)
this.activeEntities = [];
}
}
4. 実践的な最適化テクニック
このアプローチは単体でも有効ですが、他の最適化と組み合わせることでさらに効果を発揮します。
■ ゼロアロケーション設計
-
Uint32Array/Float32ArrayなどのTypedArrayで管理 - オブジェクト生成を避け、GCを最小化
■ GPUフレンドリー設計
- 可視オブジェクトのみをGPUバッファへ転送
- Compute Shaderの負荷を大幅削減
■ 疑似無限空間
- 未観測領域をノイズ関数や数式で定義
- メモリを使わずに広大な空間を表現可能
■ LOD(Level of Detail)との併用
-
距離に応じて
- 粒子数
- 挙動の精度
を段階的に変化させる
5. このアプローチが効くケース
特に以下のような場面で効果を発揮します:
- パーティクルシステム(煙、群れ、流体)
- 大規模シミュレーション
- RTS・MMOのような多数ユニット管理
- WebGL / WebGPU 描画最適化
- 群集・生物系シミュレーション
6. まとめ
「すべてを正確に計算する」という前提を捨て、「観測される部分だけ整合性を保つ」という発想に切り替えることで、パフォーマンスは飛躍的に向上します。
確率雲アプローチは、
- 計算量削減(O(N) → O(1))
- メモリ削減
- GPU負荷軽減
を同時に実現できる、非常に強力な設計パターンです。
大規模データやリアルタイムシミュレーションを扱う際の選択肢として、ぜひ取り入れてみてください。