0

私は通常、新しい粒子を作成し、それらを更新し、破壊する粒子システムを持っています...

エミッタ モジュールには、パーティクルをリセットする for ループがあります。

foreach p in particles
    p.position = rand()
    p.velocity = rand()

通常、C の rand() 関数を使用すると均一な分布が得られますが、他の分布 (ガウスなど) を使用したい場合はどうすればよいでしょうか?

そのコードを変更して、新しい粒子のパラメーターを生成するいくつかの (または少なくとも 2 つの) 異なる方法を処理する方法は?

もちろん、RandomGenerator などのオブジェクトを作成し、いくつかの仮想関数呼び出しを使用して、これらのさまざまな動作を処理できます。しかし、このコードは非常に高速である必要があるため (数千の粒子を更新する場合)、仮想関数を使用するのは良くないと思います。

または多分私は気にせず、単に書くべきです:

foreach p in particles
    p.position = useGaussian ? gausRand() : UniRand()
    p.velocity = useGaussian ? gausRand() : UniRand()

異なるディストリビューションの数を絞り込んで、そのうちの 2 つまたは 3 つだけを使用することができます...

私の例は非常に単純ですが、実際のコードではいくつかの粒子パラメータ構成があることに注意してください。

その件について一般的なアドバイスをいただきたいです。

4

2 に答える 2

3

通常、C の rand() 関数を使用すると均一な分布が得られますが、他の分布 (ガウスなど) を使用したい場合はどうすればよいでしょうか?

Box Muller Transformは、一様分布を入力として (つまり、 を使用して) ガウス分布から乱数を生成するために、三角関数を使用する非常に巧妙なアルゴリズムですrand()。平均と標準偏差を指定し、この関数を呼び出して新しい変量を生成します。唯一の欠点は、 andrandも呼び出すため、単純に を呼び出すよりもコストがかかることです(ただし、呼び出しは 2 回ごとに行われます)。sin()cos()

そのコードを変更して、新しい粒子のパラメーターを生成するいくつかの (または少なくとも 2 つの) 異なる方法を処理する方法は?

RandomGenerator仮想メソッドのアプローチから始めることをお勧めします。一番メンテナンスしやすいでしょう。物事を最適化しようとする前に、最も単純なアプローチとプロファイルから始めてください。

乱数を生成する計算の複雑さを考えると、変量を生成するコストは、仮想メソッド呼び出しと静的関数呼び出しのオーバーヘッドをはるかに上回ります。

これが実際には十分に高速でない場合は、常に乱数のプールを生成し、必要に応じてバックグラウンドでさらに生成することができます。

于 2012-06-02T11:06:02.023 に答える
3

@gavinbの答えは完全に有効な方法ですが、車輪の再発明を避け、標準機能を使用することをお勧めしstd::normal_distributionます. normal_distribution? を使用します)。boost::randomそれ以外の場合は、 libraryを使用します。

これらはヘッダーのみ (少なくともブースト バージョン) であるため、関連するポリモーフィック コールがないため、それらについて心配する必要はありません。もちろん、これは@Oli Charlesworthのアドバイスの最大の関連性を排除するものではありません.

編集: ポリモーフィック呼び出しによるオーバーヘッドが無視できない場合は、列挙型のディストリビューションで関数をいつでもテンプレート化し、必要に応じて特殊化することができます。

簡単に言えば、次のように簡単です。

#include<iostream>

// template on an int selector
template<int N> void foo(){ std::cout<<"42\n"; }
template<> void foo<1>() {std::cout<<"1\n";}

//now use an enum
enum  distr_types {UNIF, NORMAL, UNKNOWN}; 
template<distr_types T> void bar() {std::cout<<"fourty two\n";}
template<> void bar<UNIF>() {std::cout<<"UNIF\n";}
template<> void bar<NORMAL>(){std::cout<<"NORMAL\n";}

int main(){
  foo<3>();
  foo<1>();

  bar<UNIF>();
  bar<NORMAL>();
  bar<UNKNOWN>();
}

しかし、このようなことをしている場合は、優れた C++ の本を読む価値があります。

于 2012-06-02T11:12:00.243 に答える