このアプリは、ブラックホールのまわりで光がどう曲がるかを本物の物理で計算して、 「もしそばまで行って写真をとったらこう見える」という画像をつくるシミュレーターです。 ここでは数式を使わず、図でやさしく説明します。
アインシュタインは「重力とは、重いものが“時空”をへこませること」だと考えました。 時空とは、空間(たて・よこ・高さ)と時間をひとまとめにした“宇宙の床”のようなものです。 重い天体ほど、この床を大きくへこませます。
光はいつでも「まっすぐ」進もうとします。でも、時空そのものがへこんでいると、 その“まっすぐ”が曲がって見えるのです。坂道でまっすぐ転がしたボールが、坂に沿って曲がるのと同じ。 この「曲がった時空での光のまっすぐな道」を、むずかしい言葉でヌル測地線と呼びます。
時空のへこみがあまりにも深く、光さえも出てこられなくなった場所、それがブラックホールです。 大事な3つの場所を見てみましょう。
ある距離より内側に入ると、どんなに速くても二度と出てこられません。その境界が事象の地平面です。 滝のふちのようなもので、超えたら最後、落ちるしかありません。光も出られないので、外からは“まっ黒な穴(影)”に見えます。
地平面の少し外側には、光がブラックホールのまわりを円をえがいて回れる特別な場所があります。 これが光子球。ここをかすめた光が回り込むため、写真では穴のふちに細く明るいリング(光子リング)が見えます。
ブラックホールに落ちていくガスは、すぐには落ちず、まわりをぐるぐる回りながら円ばんをつくります。 これが降着円盤。猛スピードでこすれ合ってとても熱くなり、強く光ります。 さらに、こちらに近づいてくる側は青く明るく、遠ざかる側は赤く暗く見えます(ドップラー効果)。
ブラックホールは大きく「回転していないもの(シュバルツシルト)」と 「回転しているもの(カー)」に分けられます。回転していると、まわりの時空ごと 引きずられて、影の形が少しゆがみます。じっさいの宇宙のブラックホールはほとんど回転しています。
大きさで分けることもあります。星が一生の最後につぶれてできる恒星質量ブラックホール(太陽の数倍〜数十倍)と、 銀河の中心にある超大質量ブラックホール(太陽の数百万〜数十億倍!)です。2019年に世界ではじめて “写真”がとられたのは、この超大質量タイプでした。
ブラックホールは光の道を曲げるので、本来なら隠れて見えないはずの真後ろの星の光まで回り込んで こちらに届きます。そのため星がリング状になったり、いくつにも見えたりします。これを重力レンズと呼びます。 まるで宇宙が巨大な“レンズ”になっているのです。
もっとくわしく(計量の式や積分のしくみまで)知りたい人は、上の「📐 くわしい版」を開いてみてください。
このアプリは、回転するブラックホール(カー時空)のまわりのヌル測地線を後退レイトレーシングする シミュレーターです。本ドキュメントはプロジェクトのコードを読み解けるレベルを目標に、物理と実装を 対応づけて解説します。以下、幾何単位系 G = c = 1、距離はすべて M を単位(1 M = GM/c²)。 スピン軸 = +y = 円盤軸、赤道面 = xz 平面。
処理は「① 設定 → ② 積分 → ③ 描画」の3段に分かれ、ファイルもこの流れに沿っています。
| 段 | ファイル | 役割 |
|---|---|---|
| ① | config/types.ts / presets.ts | 全段で共有する契約 SimulationConfig・プリセット |
| ② | physics/geodesic.ts | 積分の心臓部。traceGeodesic(運命) / traceGeodesicPath(軌跡) |
physics/camera.ts / constants.ts / vec3.ts | ピクセル→光線、r₊・光子球・ISCO、three非依存ベクトル | |
| ② | integrate/tracer.ts / worker.ts / pool.ts | タイル分割・Web Worker 並列・進捗・転送 |
| ③ | render/viewer.ts | G-buffer→線形HDRシェーダ→Bloom→ACES |
| ③ | render/disk.ts / starfield.ts / compass.ts | 円盤テクスチャ・背景天球・方位テクスチャ(GLSL/Canvas) |
| — | main.ts / ui/* | 3段の配線・UI・断面図・光線アニメ |
カー時空は Boyer-Lindquist 座標 (t, r, θ, φ) で記述します。本実装では極軸(θ=0)を +y にとり、 θ は +y 軸から測る角、φ は赤道面(xz)内の方位角です。a→0 で通常の球座標に一致します。
BL 座標とワールド直交座標の換算(blToWorld / カメラ位置→r):
主な特徴的半径(constants.ts):事象の地平面 r₊、エルゴ面、順行光子軌道。
a=0 では r₊=2M(シュヴァルツシルト半径)、光子球=3M、ISCO=6M に一致します。
計量(Σ, Δ, A は以後くり返し使う補助量):
計量が t と φ に依存しない(時間並進・軸対称のキリングベクトル)ので、共変運動量の保存量が2つ得られます — エネルギー E と軸方向角運動量 L:
さらにカー時空には Hamilton-Jacobi 方程式が変数分離することで現れる第3の保存量=カーター定数 Q があります。
本実装は E=1 に規格化し、Q を次の形で持ちます(geodesic.ts の q):
この Q のおかげで、本来カーでは平面に乗らない光子の r 方向と θ 方向の運動が分離して解けます。
変数分離の結果、アフィンパラメータ λ に対する1階の運動方程式が得られます(E=1、ドット = d/dλ)。 r と θ は符号 ± を持つ「平方根型」で、転回点で符号が反転します:
動径ポテンシャル R(r) と角ポテンシャル Θ(θ):
R(r) は実質的な有効ポテンシャルです。 なので、 R(r)=0 となる半径が転回点(そこで dr の符号が反転=戻る)。逆に地平面まで R>0 のままなら光子は 吸い込まれます(捕獲)。光子球付近はこの境目で、わずかな衝突径数 b=L/E の差が運命を分けます。
上式は r と θ が共通因子 Σ で結ばれていて厄介です。そこでミノ時間 τ を導入すると、Σ が消えて r 方程式は r だけ、θ 方程式は θ だけの式になり完全に分離します:
実装では平方根の符号管理を避けるため、両辺を τ で微分した2階形式を 4次ルンゲ=クッタ法(RK4)で積分します
(geodesic.ts のメインループ)。転回点を符号の場合分けなしに滑らかに通過できます:
カメラ位置での視線方向から (E, L, Q) を作る必要があります。回転時空では「静止した観測者」が定義できないため、 ZAMO(zero-angular-momentum observer, 局所非回転観測者)の正規直交テトラッドを基準にします。 ラプス α と引きずり角速度 ω を使い、視線の局所成分 (n_r, n_θ, n_φ) から反変運動量を組み、共変化して保存量を得ます:
最後に E=1 へ規格化(L, p_r, p_θ を E で割る)し、 を初速として積分を開始します。視線の局所成分は、カメラ位置での BL 基底ベクトル ê_r, ê_θ, ê_φ に視線を射影して求めます。
ピンホールカメラ(camera.ts)。常に原点(BH)を注視し、前方 f̂・右 r̂・上 û の正規直交基底をつくります。
ピクセル (pₓ, p_y) の視線方向は(縦画角 fov、横はアスペクト倍):
この d(正規化)を §5 の局所成分に分解して各光子の初期条件にします。後退レイトレーシングの全体像:
ステップ幅 dτ は固定ではなく適応的に決めます(geodesic.ts)。動径方向の特徴長
charR、θ 方程式の角加速度 thAcc、軸付近で急増する dφ/dτ などの上限から
最小値を採用し、光子球付近の鋭い曲がりや極(θ→0)付近を十分細かく刻みます。これを怠ると、L≈0 で
BH の真上・真下を回り込む光に「縦の継ぎ目」が出ます。safeSin は 1/sinθ の発散を抑えます。
② は各タイル(横ストリップ)を Web Worker で並列処理し、結果を Transferable な ArrayBuffer で 親に返します。出力は2枚の Float32 RGBA テクスチャ(G-buffer):
| テクスチャ | R | G | B | A |
|---|---|---|---|---|
gbuf0 | status (0/1/2) | dir.x | dir.y | dir.z(脱出方向) |
gbuf1 | diskR | diskφ | g(赤方偏移) | — |
③ は全画面 quad のフラグメントシェーダ(viewer.ts)。status で分岐します:
starfield.ts:宇宙/地上/方位)。disk.ts)に、
相対論的ドップラー/重力赤方偏移 g を適用。g は順行ケプラー円運動するガスの放射に対する係数で、② の時点で gbuf1 に格納済み(b=L/E):
色温度を g 倍にシフトし、相対論的ビーミングで強度 ∝ g⁴。よって近づく側は青く明るく、遠ざかる側は赤く暗くなります。
g は積分済みなので ON/OFF はシェーダ切替だけ(再積分不要)。最後に線形 HDR を出力し、
UnrealBloomPass でにじませ、ACES トーンマップ+sRGB で合成します。
geodesic.test.ts が正しさの基準です。弱い重力場(大きな b)で曲がり角が次の解析式に一致することを確認しています
(2次の GR 補正込み):
ほか、M=0 で直進・無捕獲、臨界以下(b<√27 M)の捕獲、カーの順行/逆行で運命が変わるフレームドラッギングの非対称も検証。
プリセットの dPhi(ミノ時間のステップ係数 ~0.045)と escapeRadius(~200)が精度と速度を、
解像度(256〜1536)が画素数を決めます。カー積分は重く、512² で約 6 秒、1024 で約 1 分が目安です。
より厳密な式の導出は Bardeen (1973)、Carter (1968) などの原典を参照してください。
実装の細部は physics/geodesic.ts のコメントが本ドキュメントと対応しています。
ソース:github.com/sunege/black-hole-picture ↗