点の分布・サンプリング

球面一様サンプリング

Uniform Sphere Sampling

球面の面積に対して均等な方向を選ぶ。

5 / 10

インタラクティブデモ

デモを準備しています…

球面一様サンプリング

ドラッグで視点を回転、Ctrl(⌘)+ スクロールでズーム。タッチ操作は 2 本指です。

ひとことで

球の表面の上に、面積に対して均等に方向(点)を選ぶ方法です。爆発の破片を四方八方に飛ばすときなど、「どの方向も同じ確率」で選びたい場面はゲームにたくさんあります。ところが、緯度と経度をそれぞれ乱数で選ぶという素直な方法では、北極と南極に点が集まってしまいます。正しくは、高さを一様に選び、経度を一様に選ぶだけで済みます。

ゲームでの使いどころ

  • 爆発・破片・火花:パーティクルの初速の向きを全方向から均等に選ぶ。偏ると、上下にばかり破片が飛ぶ不自然な爆発になる。
  • ランダムな向き:落ちている武器や岩の向き、宇宙空間の小惑星の回転軸など。
  • 全方向の探索:周りの障害物を調べるために全方向へ光線を飛ばす、音の反響や AI の視界の見積もり。
  • 球面上の配置:惑星の上の都市や木、星空の星。均等に並べたいときはフィボナッチ格子(黄金角のらせん)が便利。

しくみ

緯度と経度を一様に選ぶと偏る理由:緯度 θ\theta の所の緯線の長さは cos⁡θ\cos\theta に比例し、極では 0 になります。どの緯度にも同じ数の点が行くと、短い緯線の上(極の近く)ほど点が密集します。

高さを一様に選ぶ:球を同じ厚さの帯に切ると、どの帯も面積が等しい(アルキメデスの定理、帽子箱の定理)ことが知られています。そこで、一様乱数 u,v∈[0,1)u, v \in [0, 1) から

y=1−2u,φ=2πv,(x,z)=1−y2 (cos⁡φ, sin⁡φ)y = 1 - 2u, \qquad \varphi = 2\pi v, \qquad (x, z) = \sqrt{1 - y^2}\,(\cos\varphi,\ \sin\varphi)

とすれば、面積に対して一様になります。確率密度は 1/(4π)1 / (4\pi) です。

棄却法と正規分布:立方体の中に点を打ち、球の中に入ったものだけを正規化する方法も正しい結果になります(外れた点を捨てずに正規化すると、立方体の角の方向に偏ります)。また、3 つの正規分布の値を並べて正規化しても、どの方向も等しくなります。

フィボナッチ格子:NN 点を均等に並べたいときは、ii 番目の点の高さを yi=1−(2i+1)/Ny_i = 1 - (2i + 1)/N、経度を φi=i⋅137.5∘\varphi_i = i \cdot 137.5^\circ(黄金角)とします。乱数を使わず、固まりもすき間もない配置になります。

実装のポイント

  • 円錐の中だけ:銃口から一定の角度の範囲に散らす場合は、高さを [cos⁡α,1][\cos\alpha, 1] の範囲で一様に選びます(α\alpha は円錐の半角)。球の一部(球冠)の上で一様になります。
  • 半球だけ:法線の側だけに向けたいなら、yy を [0,1][0, 1] で選びます。ただし光の計算には、余弦重みの方が向いています。
  • three.js:new Vector3().randomDirection() がこの方法で実装されています。

つまずきやすい点

  • 立方体の点を正規化しただけ:手軽なのでよく書かれますが、角の方向(体積が多い方向)に偏ります。棄却するか、上の方法を使います。
  • ゼロ除算:立方体の点がちょうど原点に来ると正規化できません。棄却法では、長さが小さすぎる点も捨てます。
  • 見た目の確認は極で:偏りは極や立方体の角の方向で目立ちます。上から見たり、破片として飛ばしたりして確かめます。

デモで試すこと

  1. 「緯度と経度を一様に」では、北極と南極に点が密集します。球は面積の等しい 12 本の帯に色分けしてあり、右下のグラフの両端(極の帯)が高く盛り上がります。
  2. 「立方体の点を正規化」は、グラフの偏りは小さめですが、視点を回すと 8 つの角の方向がやや濃く見えます。
  3. 「高さを一様に」では、どの帯にもほぼ同じ数の点が入り、グラフが 1 の付近で平らになります。「フィボナッチ格子」は乱数を使わない、むらのない配置です。
  4. 「爆発の破片として飛ばす」を入れて、偏った方法では破片が固まって飛ぶ様子を見てください。

参考資料

Fast Poisson Disk Sampling in Arbitrary Dimensions ↗

分野全体の資料で、この項目を直接扱っているとは限りません。