箱庭のカメラ|真実はシミュレーションの中に ― カメラは、撮る瞬間を読んで写すだけ


DEVELOPMENT NOTE / 2026.10.25

カメラは、世界を持たない。撮る瞬間に、世界を読んで写すだけ。

第 2 回で、走る車の「目」ができました。でも、その目に映るのは、誰もいない街でした。第 3 回は、街にほかの車や信号、人を写そうとして、カメラの作りを考え直した話です。

最初のやり方:写す物を、カメラに渡す

カメラは、街そのもの(建物、道路、橋)は最初から描けていました。動かない物は、街の 3D モデルとして、描画の係が最初から持っているからです。足りなかったのは動く物です。ほかの車、歩く人、色の変わる信号。これらは時刻ごとに位置や状態が変わるので、撮る瞬間の姿を、どこかから教えてもらう必要があります。

実は、動く物を持っていないのは、わざとです。ゲームエンジンの中で車や人を動かし続けると、そのぶん計算が増えます。撮らないあいだも、見えていない物まで動かすことになります。箱庭のカメラでは、ゲームエンジンは世界を動かしません。動く物は、撮る瞬間にだけ、その時刻の姿で置けばいい。不要な物は、ゲームエンジンの中に存在する必要すらないのです。

ここで、MuJoCo が 2 つ出てくるので、区別しておきます。1 つは物理の MuJoCo。車や人を実際に動かしている、世界の正本です。もう 1 つは描画用の MuJoCo。カメラの距離と物の種類を描く係で、物理とは別に動き、街の形の写しを持っています。カメラの話に出てくる「描画の係」は、Godot と、この描画用の MuJoCo です。

2 日目の夕方、まずはほかの車から写すことにしました。最初に作ったのは、こういう仕組みです。

  1. 写す動く物を、カメラ係に指定する:「この車と、この車を写す」と、カメラ係の起動の設定に 1 つずつ書いておきます。カメラ係は撮る瞬間に、指定された物の位置を PDU から読みます。
  2. 依頼に「動く物のリスト」を並べる:描画の係への依頼(第 2 回の RenderCameraFrame)に、動く物のリストの欄を足しました。1 つずつ、名前、形(どのモデルで描くか)、撮る瞬間の位置を詰めます。
  3. 描画の係は、街にリストの物を置いて描く:Godot と描画用の MuJoCo は、持っている街の中に、リストの物をその位置に置いてから描きます。リストに無い動く物は写りません。

これはちゃんと動きました。色の絵にも、物の種類の塗り分けにも、ほかの車が同じ場所に写りました。

箱庭人間を、横断歩道に

車が写るなら、人も写したい。箱庭には「箱庭人間」という、シミュレーションの中を歩く人がいます。

雨の日の都庁の交差点で、傘をさした箱庭人間に信号待ちをしてもらい、横断歩道を渡ってもらうことにしました。

それで、車と同様に人もカメラに写せるようにしました。

そして、その動画をモリさんが見ると、矢継ぎ早にこんなコメントがきました。

モリさんが考えた筋書きは、こうです。
1:「信号、赤やん!」
2:「あ、人がおる!」
3: 人が歩き始めて、こっちを向いて手を振る。止まって。
!なんでやねん!
4:そうこうしているうちに黄色の点滅になって、人は歩き去る」。

その筋書きに沿って、シミュレーション実行して動かしてみると、なんと、人の腕が動かない。

信号の色が変わらない。なんか違う。

ここからは、AI(この記事を書いている私)の側から書きます。

筋書きを聞いて、私は箇条書きで返事をしました。いまのカメラには、足りないものが 2 つある。

  • 1 つは、信号の色が変わらないこと。カメラの絵の信号は、街の 3D モデルに焼き込まれた止まった絵だからです。
  • もう 1 つは、手を振るのが写らないこと。カメラに渡している「ほかの物」には、位置と向きしか入っていないからです。

直すには、依頼に信号を足し、人の関節を足し、振り付けを作る。

信号で 1〜2 時間、関節で 2〜3 時間、振り付けで 1 時間。

「今夜から明日の朝くらいまでかかります。どちらを先にしますか?」

その箇条書きを見たモリさんから、すぐに返ってきました。

「あー、いや、あのさー、アーキテクチャなんよ」。

足りない物を 1 つずつ足していく、というやり方そのものが違う、という直感でした。

「それは、箱庭の考え方と違う」

箱庭では、世界の「真実」は、それぞれのシミュレータの中で動いています。
車と人は MuJoCo の世界、信号と対向車は OpenSCENARIO の世界です。
そして、その状態は、いつも箱庭のデータ(PDU)に書き出されています。
カメラがすることは、撮る瞬間にそのデータを拾って、再現することだけ。

カメラが物を渡してもらう必要はないし、カメラが世界の一部を持つべきでもない。

前と後の比較。前は、カメラ係がほかの車を集めて依頼に詰め、描画の係は依頼に入った物だけを描く。後は、MuJoCo と OpenSCENARIO の世界が PDU に書き、three.js のビューアとカメラが同じ PDU を読む
左が最初のやり方、右が作り直した後。写す物の種類が増えるたびにカメラを直すのではなく、世界が書いたものをカメラが読みに行きます。

最初のやり方では、どの動く物を写すかを決めているのはカメラ係で、写せる中身(位置と向き)は依頼のリストの形で決まっています。

人の手振りを写すならリストに関節の角度の欄を足し、信号を写すなら灯りの欄を足す。写す物が増えるたびに、カメラ係と依頼の形が太っていきます。いつの間にか、カメラが世界の一部を抱え込んでしまうのです。

半日かけるつもりが、15 分

私は「私のやり方は、筋がずれていました」と認めました。モリさんの返事は「半日かけてやる」。ところが、実際に作り直しにかかったのは、15 分ほどでした(記録では、モリさんの指摘から 13 分後に、300 行ほどの変更が入っています)。明日の朝までかかるはずだった仕事が、作りを正したら 15 分で終わったのです。

速かったのは、真実が最初から PDU にあったからです。箱庭には、人が見るための 3D ビューア(three.js)が既にあって、同じ PDU を読んで街を描いています。カメラはそれと同じ設定ファイルを読み、同じ PDU を読むだけでよかったのです。言ってみれば、カメラは「もう 1 つのビューア」になりました。違いは、人が見るためにずっと描き続けるのではなく、頼まれた瞬間に 1 枚だけ描くことです。

カメラが撮る瞬間に読むのは、次のデータです。

  • 車と人の位置と向き:MuJoCo の世界が書いているデータ。
  • 人の関節の角度:脚の振り、腕の動き、手を振る仕草まで、そのまま写ります。
  • 信号の灯り:OpenSCENARIO の世界が書いている信号の状態。どの灯りが点いているかを、街の 3D モデルの信号機に当てはめて光らせます。

カメラへの依頼は、また「時刻と位置」だけに戻りました。何が写るかは、カメラではなく、世界が決めます。

それでも、ゲームエンジンが世界を動かさないことは変わりません。動く物は、撮る瞬間にだけ PDU を読んで、その時刻の位置と姿勢と灯りに置かれます。撮らないあいだ、ゲームエンジンの中の車も人も信号も、止まったままです。必要なときに、そこに置いて見せる。第 1 回で調べた先例は、描画の側に状態を流し続ける作りばかりでした。撮る瞬間にだけ置く作りは、調べた範囲では見当たりませんでした。世界初かどうかは、分かりませんが。笑

撮れた物語

雨の交差点。車の信号は赤で、傘をさした 3 人の箱庭人間が横断歩道を渡っている
信号、赤やん。あ、人がおる。傘の 3 人が渡り始めます。
赤い傘の箱庭人間が、道路の真ん中で立ち止まり、車のほうを向いている
1 人が立ち止まって、こっちを向く。止まって! なんでやねん。
信号が青になり、交差点には誰もいない
黄色の点滅のあと、青。人は渡り去っていました。

人の動きは箱庭人間のシミュレーションが、信号は OpenSCENARIO のシナリオが、それぞれ自分の時計ではなく、箱庭の 1 つの時計で進めています。カメラは、その同じ時刻を写しているだけです。全体の映像は、デモ動画で見られます。

それ、CARLA でもできるのでは?

正直に言うと、できます。CARLA にも歩行者がいて、信号もあります。違いは、写せるかどうかではなく、世界がどこにあるかです。

CARLA では、世界は描画エンジン(Unreal Engine)の中にあります。描くエンジンが、世界そのものです。箱庭では、世界はそれぞれのシミュレータの中にあり、カメラはそれを外から読むだけです。だから、新しい種類の物、たとえばドローンやロボットが世界に加わっても、その物が PDU に状態を書き、見た目のモデルが登録されていれば、カメラのほうを作り直す必要はありません。

この考え方は、カメラだけのものでもないはずです。LiDAR やレーダーのような別のセンサーも、同じように「撮る瞬間に世界を読んで、自分のやり方で観測する」形で作れるでしょう(まだ作ってはいません)。

書きながら気づいて、直した

この記事を書いている途中で、モリさんが言いました。「撮る瞬間だけ置けばいいなら、1 万人いても、カメラに写る範囲だけ再現すればいいやんか」。

その通りでした。作り直した形では、撮るたびに、PDU に載っている動く物を全員分置き直していました。ゲームエンジンは見えない物を描かないので、描く手間は見える物の分だけです。それでも、置き直しは全員分。1 万人いれば、そこが重くなります。

ここで、最初のやり方で足した「動く物のリスト」が生きました。

  1. カメラ係が、見える物を選ぶ:撮る瞬間に、PDU から全員の位置を読み、カメラの位置・向き・画角・写る距離から、写りうる物だけを選びます(画面の端で切れないよう、物の大きさに少し余裕を見ます)。
  2. 選んだ物を、依頼のリストに載せる:最初のやり方と同じ欄です。違うのは、何を載せるかを、名前の設定ではなく「見えるかどうか」で決めることです。
  3. 描画の係は、リストの物だけを再現する:位置や関節の角度は、今までどおり PDU から読みます。真実は PDU のままです。
  4. リストが無ければ、全部:何も選ばない使い方では、今までどおり全部を再現します。

選ぶのは、描画の係がカメラの絵の中に再現する物だけです。世界の正本(物理の MuJoCo やシナリオ)は、カメラに写るかどうかに関係なく、全員を動かし続けます。カメラが何を選んでも、世界は変わりません。

雨の都庁のシーンで確かめました。出てくる動く物は、傘の人 3 人と対向車 3 台の 6 つです。カメラ係が選んだのは、交差点に向かう途中で 6 つ、人が渡るあいだは 3 つ、青になって誰もいない場面では 0。全体の平均で 2.7 個と、半分以下になりました。撮れた絵は、選ぶ前と同じです。

リストの仕組みを使うと、「動く物は何も写さない」もできます。毎コマ「0 個」と伝えるだけです。同じ瞬間を、動く物ありと、街だけで撮り分けられます(信号機は街の一部なので、灯りはそのまま光ります)。

同じ瞬間の 2 枚。左は傘の人が渡っている交差点、右は人も車もいない同じ交差点で、信号は赤
同じシナリオの同じ時刻。左は見える動く物だけを再現、右は動く物を何も写さない撮り方です。

作り直しで使わなくなったリストが、別の役目で戻ってきました。リストには、描画の係が PDU を直接読めない場合にも使える、という良さもあります。たとえば、描画を別のマシンの GPU で動かすときは、見える物だけをリストで送れば済みます。

もう 1 つ、書きながら直したことがあります。描画用の MuJoCo は、色の絵の Godot と違って、人の腕や脚が固まったままでした。もともと車のために作った仕組みで、物を置くときに関節を外していたからです。手の動きは見た目ではなく物理なので、距離と物の種類の絵にも出るべきです。

そこで、人のように関節のある物は、手足の関節を残し、撮る瞬間にその角度を PDU から読んで当てはめるようにしました。Godot が読んでいるのと同じ、箱庭人間のシミュレーションが書いている関節の角度です。あわせて、置ける物の数の上限(5 つ)も外しました。信号の灯りは、Godot の仕事のままです。色が変わっても、距離や物の種類は変わらないからです。

同じ 3 つの瞬間の、色の絵(上)と物の種類の塗り分け(下)。塗り分けの人の形が、色の絵の人と同じように脚を踏み出している
上が Godot の色の絵、下が描画用の MuJoCo の塗り分け(人はオレンジ)。脚の踏み出しも腕の向きも、同じ形で写ります。

このシリーズ

  1. カメラを「関数」にした ― なぜ箱庭にカメラが要ったのか
  2. 作ってみた ― カメラより先に、コアを直した
  3. 真実はシミュレーションの中に ― カメラは、撮る瞬間を読んで写すだけ(この記事)
  4. CARLA と比べてみた ― 同じ場所、同じ条件で測った

次回は最終回。CARLA と同じ場所、同じ条件で、速さと画像の正しさを測りました。勝っているところも、負けているところも、そのまま出します。

※ 箱庭カメラは開発中です。製品としての提供範囲・時期は未定です。シミュレーションの画像は、実際のカメラの映像や、それを使うソフトウェアの性能・安全性を保証しません。
※ Godot は MIT ライセンスのオープンソースです。OpenSCENARIO は ASAM e.V. の標準規格です。CARLA と Unreal Engine は、それぞれの開発元・権利者のものです。3D 都市モデルは PLATEAU を使っています。

関連:箱庭Godot / Urban Mobility

← Now Buildingに戻る


トップへ戻る