← 作品一覧

CELL CITY

ブラウザの中で動く、渋谷のシミュレーション。

コード公開街全体を動かす ↓
  • JavaScript
  • Three.js
  • Web Workers
仕組みと技術
Three.js / WebGL
建物や道路を3Dで描画。
Web Workers
街を分割し、描画とは別のスレッドで組み立てる。
TypedArray / cache
設定したメモリ予算の中で、形状データを保持する。
この作品の目次

動き出す前に、都市を分ける

街を区画に分け、別々に計算する6つのWorkerで分担します。

01 · 1つの都市、6つの担当。
仕組みと検証条件を読む

形状の出発点は、実在する都市です。配信している加工済みデータには7,770棟のレコードがあり、233の空間チャンクに分かれています。その合計は、バイナリとメタデータで照合しています。一方、窓の在室状態は創作です。階の明かりは手続き的に作った値であり、人や部屋の利用状況を観測したものではありません。

担当の決め方は単純です。チャンクIDを6で割った余りをワーカーIDにします。カメラが動いても担当は変わりません。5つのワーカーは39チャンクずつ、最後の1つは38チャンクを担当します。ただし、チャンクごとに建物の数も大きさも違います。チャンク数が揃っていても、保持するデータ量は揃いません。

図で担当ワーカーを選び、そのチャンクを調べてください。格子は個々の建物の輪郭ではなく、チャンクの中心を表しています。Workerの実験では、実際の頂点から求めた境界ボックスを可視判定に使います。担当と窓処理を調べるには建物の位置・寸法テーブルで足りるため、この計器で描画用の全形状を読み込む必要はありません。

メモリの上限には、内訳がいる

Workerが保持するデータを足し合わせます。この予算には、描画用のGPUメモリやブラウザ全体の使用量は含みません。

02 · 保持している配列を数える。
仕組みと検証条件を読む

建物テーブルのpayloadは1棟あたり20バイトです。位置と寸法を表す4つのFloat32値に、用途やシードを表す4バイトが加わります。詳細な窓状態には、モデル上の窓1枚につき1バイト、さらに1棟あたり寸法用の8バイトと縦方向の明かりの帯域キャッシュ用の4バイトが必要です。メッセージ処理後もワーカー内に残る配列を、この内訳で追います。

ワーカー自身が持つメタデータも数えます。チャンク中心、正確な境界、識別子、受信を見送った状態のフラグは、現行実装では担当チャンク1つにつき45バイトです。この費用は、最初の窓詳細を確保する前から存在します。図のメタデータ欄は選択したワーカー全体、それ以外の欄は選択したチャンクの内訳です。他のチャンクを保持すれば、その配列も加わります。

担当する全チャンクを展開すると、ワーカー4の計算上の上限は、メタデータを含めて250,060バイトです。配信テーブルから再計算した値です。カメラのツアーでこの値まで到達するという意味ではありません。このモデルでは全データが256 KiB以内に収まりますが、実際に保持する集合は視点の履歴と選んだ予算によって変わります。

これは保持しているTypedArrayのモデルであり、ブラウザ全体のメモリ使用量ではありません。JavaScriptオブジェクト、実行環境とコード、GPU資源、転送中のメッセージは会計の対象外です。範囲を明示することで上限を検証でき、計器の小さな数値を都市全体の費用と取り違えることも避けられます。

使用中のデータを残したまま、場所を確保する

使用中のデータを残し、古いデータを外して空きを作ります。それでも収まらないときは、窓の明かりを近似で計算します。

03 · 使用中のデータも内訳に含める。
仕組みと検証条件を読む

近くのチャンクが窓詳細を求めるとき、その建物テーブルは既に処理に使われています。ワーカーはまず、使用中のエントリを残したまま新しいpayload全体が収まるか確認します。その後、固定されていない古いエントリを選び、必要な空きができるまで追い出します。使用中のテーブル、メタデータ、要求した詳細が一緒に収まらなければ、詳細を見送って近似の明かりを返します。

窓状態、窓寸法、帯域キャッシュは、まとめて1回の確保判断にかけます。大きな配列だけ先に許可して、小さな付随配列を後から足す方法にはしていません。厳しい上限の近くでは、見た目には小さい配列でも、保持する全バイトを同じ判断に含める必要があります。

下の手順は、都市から切り出した処理列ではなく、作成した試験入力です。各6棟の高い建物を含む2チャンクが、64 KiBのワーカーを共有します。まず両テーブルを受け取り、Aが窓詳細を確保し、次にBが要求します。結果にはWorkerが返した実際のキャッシュエントリとeviction回数を表示します。読み取り専用の検査では、保持エントリのサイズを別に合計し、メタデータを加えた値が報告値と一致することも確認します。

距離の判定にも、履歴がある

区画に近づき、離れて、戻る。記憶に残るデータは、そこまでの移動にも左右されます。

04 · 戻るときと、初めて来るときの違い。
仕組みと検証条件を読む

現行ワーカーは、可視のチャンク中心までの距離が560 m未満になると、窓詳細の確保を求めます。窓のpayloadを解放するのは、カメラが1,150 mを超えて離れた後です。この間では、現在の出力が軽い近似帯域になったり、明かりの更新を返さなくなったりしても、以前に確保した窓配列がメモリに残る場合があります。

そのため、現在の距離だけを見ても、保持集合は説明できません。空のキャッシュで600 mまで近づいた場合と、いったん接近してから600 mへ戻った場合は異なります。建物テーブルの寿命はさらに別で、距離ではなく予算不足による追い出しでキャッシュから外れます。保持バイトの内訳と、その瞬間の明かりの計算方式は、別の問いへの答えです。

この計器は実データの1チャンクのpayloadを使い、シミュレーション時刻を固定し、全可視となる試験用の平面入力を与えます。そのうえで、作成した往復の距離列を処理します。可視範囲の変化から確保・解放の規則を切り分けるための単純化であり、描画を含むツアー全体の再生ではありません。600 mへの2回の訪問で、残る配列を比べてください。

処理列を揃えて、予算を変える

保持できる量を変え、同じ処理を繰り返します。記憶から外れたデータを比べる実験で、描画速度の測定ではありません。

05 · 処理列を揃えて、予算を変える。
仕組みと検証条件を読む

記録済み曲線では、どの予算にも同じ疎な処理列を与えます。正確に固定した54視点、各視点2バッチ、固定時刻、実頂点から求めた境界です。毎回、対象予算でワーカーを初期化し、担当する建物テーブルを全て送ります。この記録はNode 22.11.0で作成しました。入力列を定めたソース再生であり、連続したブラウザのツアーや描画速度の評価ではありません。

記事と完全なデモは、同じWorkerソースを実行します。記事では追加の予算プリセットも選べます。ワーカーを1つ選び、そのブラウザで1つの予算を実行するか、8〜192 KiBの13予算を順に処理してください。256 KiBは別の基準値です。丸は記録済みNode結果、四角はこのブラウザで実際に返ったカウンターです。異なる結果も消さずに残します。計算や待機にかかった時間を、作り物のフレームレートに置き換えることはしません。

メモリを減らした結果が、滑らかな単調曲線になるとは限りません。とても小さい予算では高価な窓状態を見送り、近似帯域を使えます。少し大きくすると、その状態を確保できる代わりに、後で必要になるテーブルを追い出すことがあります。eviction、近似への切り替え、明かりの更新を合わせて読んでください。明かりの更新がないことは、建物がないことではありません。完全なデモでは形状はGPUに残り、その上に更新前の帯域が残る場合があります。

記録した処理列では、128 KiB以上のevictionは0でした。この観測は、この負荷に対する結果です。経路、ウォームアップ、メッセージ列を変えれば実験も変わります。任意の音は既定でOFFです。ONにすると、実際のWorkerバッチがeviction回数の増加を返したときだけ、頻度を制限した小さな合成音の候補になります。これは計器の信号音です。

必要なデータが、メモリに収まらないとき

建物が高くなると、必要な窓データも増えます。高さを変え、Workerの予算に収まるか試せます。

06 · 詳細の要求が、大きすぎるとき。
仕組みと検証条件を読む

窓モデルは建物寸法から階数と列数を求め、それぞれに上限を設けます。確認したソースでは、1棟が要求できるのは最大80階、72列です。これらは手続き的な処理量を制限する規則です。元の建物形状を変えるものでも、高さ属性が現地で測定されたことを証明するものでもありません。

この計器では、明示した合成入力を作ります。選択した高さ、半径33 mの建物46棟です。内訳にはテーブル、詳細状態、寸法、帯域キャッシュ、担当メタデータを含みます。高さを変えて要求量を調整し、256 KiBの予算でWorkerを実行してください。この寸法は実験のために作成したもので、渋谷の実在建物に対応づけていません。

ここで確かめたいのは、確保するかどうかの判断です。詳細全体が収まれば保持します。収まらなければ、詳細配列を作らず近似の明かりを返します。見送った要求は保持メモリではないため、実測した保持バイトは計算上の要求量を大きく下回ることがあります。図では、この要求量と保持量を分けて表示します。

Workerの仕様を読む ↗

根拠と確認方法

確認方法と範囲

配信データは7,770棟、233チャンク。バイト数はワーカーのメタデータと保持配列から計算し、GPU形状やJavaScript実行環境の管理領域は含めません。

記録した実行は、Node 22.11.0で54視点・6ワーカー・14段階の保持量を比較したものです。処理列ごとに初期化しています。ブラウザでの計測は、上の操作画面に別途表示します。

データとソース識別情報を保存 ↓

街全体を動かす

このページ内で、ブラウザが世界を動かします。

映像 · 4:30

YouTubeで見る ↗

建物:PLATEAU / 国土交通省 · 道路:© OpenStreetMap contributors