現在、ゲームのパーティクルシステムに貢献し、エミッタシェイプを開発しています。
線または長方形の領域に沿った私の一様なランダム分布は問題なく動作します-問題ありません。
しかし今、私はこの分布に1次元の勾配のようなものを持ちたいです。これは、たとえば、低い値は高い値よりも一般的であることを意味します。
この問題に適切な数学用語が何であるかはわかりませんので、この検索スキルでは私の検索スキルはかなり役に立ちません。パーティクルシステムは効率的である必要があるため、計算が簡単なものが必要です。
現在、ゲームのパーティクルシステムに貢献し、エミッタシェイプを開発しています。
線または長方形の領域に沿った私の一様なランダム分布は問題なく動作します-問題ありません。
しかし今、私はこの分布に1次元の勾配のようなものを持ちたいです。これは、たとえば、低い値は高い値よりも一般的であることを意味します。
この問題に適切な数学用語が何であるかはわかりませんので、この検索スキルでは私の検索スキルはかなり役に立ちません。パーティクルシステムは効率的である必要があるため、計算が簡単なものが必要です。
回答:
この写真を見てください:

(ランダムな)値を曲線にマッピングするプロセスを示しています。0から1の範囲の一様に分布したランダムな値Xを生成するとします。この値を曲線にマッピングすることで、つまりXの代わりにf(X)を使用して、好きな方法で分布を歪めることができます。 。
この図では、最初の曲線がより高い値を示しています。2番目は、より低い値をより可能にします。3番目の値は、値を中央にクラスター化します。曲線の正確な公式は重要ではなく、好きなように選択できます。
たとえば、最初の曲線は平方根に少し似ており、2番目の曲線は正方形に似ています。3つ目はキューブに似ており、翻訳のみです。平方根が遅すぎると考えると、最初の曲線もf(X)= 1-(1-X)^ 2-平方の反転のように見えます。または、双曲線:f(X)= 2X /(1 + X)。
4番目の曲線が示すように、事前に計算されたルックアップテーブルを使用できます。曲線としてはいように見えますが、おそらくパーティクルシステムには十分でしょう。
この一般的な手法は非常にシンプルで強力です。必要な分布が何であれ、曲線マッピングを想像するだけで、すぐに数式を考案できます。または、エンジンにエディターがある場合は、曲線のビジュアルエディターを作成するだけです!
より長い説明:
要求される勾配@diditoなどの希望する確率分布がある場合、関数として記述することができます。0での確率が0.0である三角分布が必要で、0から1までの乱数を選択するとします。y= xと書くことができます。
次のステップは、この関数の積分を計算することです。この場合、それはです。0〜1で評価され、½です。それは理にかなっています—それは底辺1と高さ1の三角形なので、その面積は½です。
次に、0からエリア(この例では½)まで均一にランダムなポイントを選択します。これをzと呼びましょう。(累積分布から均一に選択しています。)
次のステップは、xのどの値(x̂と呼ぶ)がzの領域に対応するかを見つけるために、後方に移動することです。0からx̂まで評価され、zに等しいを探しています。を解くと、が得られます。
この例では、zを0から½の範囲で選択し、目的の乱数はです。簡略化すると、として記述できます。eBusinessが推奨するとおりです。
sqrt(random())生涯を過ごしましたが、経験的にやって来ました。乱数を曲線に結び付けようとしても、うまくいきました。数学がもう少し上手になったので、なぜそれが機能するかを知ることは非常に貴重です!
おそらく、指数システムを利用することで、必要なものに近い近似値を取得できます。
1-(rnd ^ value)のようなものに基づいてxを作成します(rndが0から1の間であると仮定します)。使用するものに基づいて、左から右へのスキューのいくつかの異なる動作が得られます。値を大きくすると、より偏った分布になります
オンライングラフ作成ツールを使用して、さまざまな方程式がそれらを配置する前に提供する動作に関するいくつかの大まかなアイデアを得ることができます。
編集
パーティクルあたりのCPU時間が非常に重要なパーティクルシステムのようなものでは、Math.Pow(または同等の言語)を直接使用すると、パフォーマンスが低下する可能性があります。より多くのパフォーマンスが必要で、実行時に値が変更されない場合は、x ^ 2ではなくx * xなどの同等の関数に切り替えることを検討してください。
(フラクショナル指数は問題になる可能性がありますが、私よりも数学の背景が強い人は、おそらく近似関数を作成する良い方法を思いつくことができます)
value場合、これはBeta(value、1)です。
あなたが探している用語はですWeighted Random Numbers、私が見たアルゴリズムのほとんどはtrig関数を使用していますが、効率的な方法を見つけたと思います:
ランダム関数の乗数値を保持するテーブル/配列/リスト(何でも)を作成します。手動またはプログラムで記入してください...
randMulti= {.1,.1,.1,.1,.1,.1,.2,.2,.3,.3,.9,1,1,1,}
...次にrandom、ランダムに選択されrandMulti、最後に分布の最大値を掛けます...
weightedRandom = math.random()*randMulti[Math.random(randMulti.length)]*maxValue
これはsqrt、またはその他の計算が複雑な関数を使用するよりもはるかに高速で、より多くのカスタムグループ化パターンが可能になると考えています。
あなたが求めるのは平方根関数を使用して達成される分布だと思います。
[position] = sqrt(rand(0, 1))
これにより[0, 1]、位置の確率がその位置に等しい単一次元フィールドの分布、つまり「三角分布」が得られます。
代替の平方根フリー生成:
[position] = 1-abs(rand(0, 1)-rand(0, 1))
最適な実装の平方根は、分岐のない少数の乗算および合計コマンドです。(参照:http : //en.wikipedia.org/wiki/Fast_inverse_square_root)。これらの2つの関数のどちらが速いかは、プラットフォームとランダムジェネレーターによって異なります。たとえば、x86プラットフォームでは、2番目の方法を遅くするために、ランダムジェネレーターで予測不可能な分岐を数個しか必要としません。
ベータ版を使用するだけです:
等
2つの形状パラメーターは整数である必要はありません。
uniform_generator()通話をに置き換えますgsl_ran_beta(rng, a, b)。ここを参照してください:gnu.org/software/gsl/manual/html_node/...
さらに簡単に、ランダムジェネレーターの速度に応じて、2つの値を生成して平均することができます。
あるいは、もっと単純で、Xは、RNGの結果であり、まずdouble y = double(1/x);、x = y*[maximum return value of rng];。これは、数値を低い数値に指数関数的に重み付けします。
より多くの値を生成して平均化し、値を中心に近づける可能性を高めます。
もちろん、これは標準のベル曲線分布またはその「折り畳まれた」バージョン*でのみ機能しますが、高速ジェネレーターを使用すると、sqrtなどのさまざまな数学関数を使用するよりも速く簡単になります。
サイコロのベルカーブについて、これに関するあらゆる種類の研究を見つけることができます。実際、Anydice.comは、サイコロを転がすさまざまな方法のグラフを生成する優れたサイトです。RNGを使用していますが、前提も結果も同じです。そのため、コーディングする前に配布を確認するのに適した場所です。
*また、軸を取得し、平均化された結果を減算してから軸を追加することにより、軸に沿って結果分布を「折り畳む」ことができます。たとえば、より低い値をより一般的にし、15を最小値、35を最大値、20の範囲にしたい場合、20の範囲の2つの値を生成して平均します(必要な範囲の2倍)、20を中心としたベルカーブが得られます(最後に5を引いて、範囲を20から40から15から35にシフトします)。生成された数値XとYを取得します。
最終番号
z =(x+y)/2;// average them
If (z<20){z = (20-z)+20;}// fold if below axis
return z-5;// return value adjusted to desired range
ゼロが最小値である場合、さらに良い場合は、代わりにこれを行い、
z= (x+y)/2;
If (z<20){z = 20-z;}
else {z = z - 20;}
return z;