ランダムベクトル

ランダムに偏りのない3次元の単位ベクトルを取得する方法を調べてみたのですが、あまり情報が見つからなかったので自分なりに考えてみました。なぜランダムにベクトルが必要かというと、例えば夜空の天球に星を並べたり、パーティクルの爆発なんかに利用できますよね。いろんな求め方があると思いますが、シンプルに経度と緯度の角度で求める方向で考えてみます。

 

spheremodel

経度は0~2π(0~360度)をランダムに選べば大丈夫ですが、緯度のほうはランダムに選ぶと問題があって、北極と南極の部分の表面積が赤道の部分に比べて小さくなるので、一様分布で乱数を振ると極に密集してしまうことになります。なので、乱数に対して面積に比例した重みをつける必要があります。

表面積の比は微分するイメージで、輪切りで細かく分割すると円周の長さの比になると考えます。円周の長さの公式が2*πrなので、赤道から極までの円周の比はつまり半径の比になります。半径は三角比で求めるとcosΘになるので、つまり側面から見た輪切りの円周の長さはコサイングラフになります。

 

random_unit_vector

コサイングラフが面積比となりますが、面積比=確率とみなすので、グラフは確率密度と捉えます。たとえば60°の角度のところはcos(60°)=0.5なので赤道に比べて面積が半分ということになります(赤道の半分ぐらいしか確率が発生しない)。

これらの確率の累積密度はコサイングラフを積分したサイングラフとなります。なので、乱数にアークサイン(サインの逆関数)を通せば重みのついた乱数が得られるはずです。(図の右下の累積グラフの縦軸を確率、横軸を角度と見てください)

緯度と経度が得られたので三角関数を使ってベクトルの計算(少し前に書いた三角関数の記事を参考にどうぞ)。

angleY = rand(0, PI*2)
angleX = asin(rand(-1, 1))
vector.Y = sin(angleX)
vector.X = cos(angleX) * cos(angleY)
vector.Z = cos(angleX) * sin(angleY)

で、これを使ってモデルを同じ距離で飛ばしてみました。

 

spherical_placement

いい感じにバラついているかな?

p.s.
ランダムに単位ベクトルを求める方法はもしかして定石があったりするんでしょうか?間違いがあればご指摘をお願いします。

広告

ランダムベクトル」への1件のフィードバック

  1. 昔,球の点群を生成したことがありますが,その時はある単位ベクトル(例えば(1,0,0))を原点まわりで3自由度でランダムにヨーピッチロール回転させるのを繰り返しました.比とか考えなくていいので楽です.

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中