dA-tools.com

乱数:Random

AfterFxには乱数を発生させるメソッドが複数用意されています。

    • JavaScriptの乱数より実用的です。

メソッド 引数 返値
random( ) なし 0~1の乱数を返します。
random(max) 数値 0とmaxの間の数値を返します。
random(min, max) 数値 minとmaxの間の数値を返します。
random(maxArr) 配列 max_arrと同じ次元で、0~max_arrの範囲にある配列を返します。
random(minArr, maxArr) 配列 minArrおよびmaxArrと同じ次元で、minArr~maxArrの範囲にある配列を返します。
gaussRandom( ) なし 0~1の乱数を返します。結果はベル分布です。
gaussRandom(max) 数値 0~maxの乱数を返します。
gaussRandom(min, max) 数値 min~maxの乱数を返します。
gaussRandom(maxArr) 配列 max_arrと同じ次元の配列を返します。
gaussRandom(minArr, maxArr) 数値 max_arrと同じ次元の配列で、各コンポーネントがminArr~maxArrの範囲にある配列を返します。
seedRandom(seed,timeless=false) 数値 既存の乱数シードを引数で増分します。
シードで乱数のパターンを変える。
noise(val) 数値or配列[2or3] 0~1の間の数値を返します。noiseは乱数ではありませんが、多少ばらつきが必要な時に使います。noiseはPerlin Noise。

  • random は小数点を含んだ値を返します。整数にするにはMath.round/floor/ceilなどを使います。下に関連項目。
  • レイヤーIDを引数に取る乱数の場合、同じエクスプレッションでもレイヤーが違えば異なる値を返します。それを揃える方法はこちらLinkIconエクスプレッション制御

乱数分布の違い


random([100,100])
0~100の範囲の分布



seedRandom(2);
random([100,100])
 
seedRandom(n)は既存のシードを引数nで増分します。random()またはgaussRandom()とは別パターンの乱数を発生します。



gaussRandom([100,100])
 
値はベル形分布になります。
結果の90%は0~100の範囲にあり、残りの約10%はその範囲外に分布します。



円形に分布させるにはベクトルの角度と長さにランダムを適用します

rad=random(Math.PI*2);
dist=random(50);
x=Math.cos(rad)*dist;
y=Math.sin(rad)*dist;
[x,y]




上の分布は中央に集まってしまうので長さにバイアスをかけると、均等分布になります。

rad=random(Math.PI*2);
dist=Math.sqrt(random())*50;
x=Math.cos(rad)*dist;
y=Math.sin(rad)*dist;
[x,y]



例:不規則に0~20のランダム値を出現させる。

  • 平面の回転プロパティに以下の式を記述しました。
  • 1行目で-100から0の乱数をaaに代入しています。
  • 2行目で乱数aaが-20より小さければ無視されます。
  • randomの引数100とMath.maxの第二引数は任意です。

aa=random(100)*-1;
Math.max(aa, -20)+20

 

seedRandom

seedRandom(seed,timeless)はrandom( )によって生成される乱数をコントロールすることができます。

  • 第1引数 seed は任意の数です。
  • 第2引数 timeless はランダム( )によって生成される乱数が時間要素を考慮するかしないかのフラッグで、デフォルトはfalseです。
  • seed値の違うrandom( )は異なる乱数を生成します。
  • 下のムービーでは緑とオレンジはseed値だけが違います。

のポイント

seedRandom(3);
random([thisComp.width, thisComp.height])

オレンジのポイント

seedRandom(99);
random([thisComp.width, thisComp.height]


  • timelessをtrueにするとすべてのフレームで同じ値になり、白のポイントのように静止します。

白のポイント

seedRandom(3,true);
random([thisComp.width, thisComp.height])

  • つまり第2引数 timeless がfalseならはフレーム毎に数値が変化して、trueならすべてのフレームで値が一定になります。
  • Seedを時間ステップで更新すると乱数の発現をコントロールすることが出来ます。

 

例:乱数が12コマ毎に発現 (24fps)

compSize=[thisComp.width, thisComp.height] ;
hold = 12/24 ;
seed = Math.floor(time/hold);
seedRandom(seed,true);
random(compSize)

 

以下のExpでも同様の結果を得ることが出来ます。

posterizeTime(2);
random(compSize)

 

乱数を補間

  • 上の動きをスムースな移動にするには2つのポイントを補間します。

compSize=[thisComp.width, thisComp.height];
hold = 12/24;
seed = Math.floor(time/hold);
A = seed*hold;
seedRandom(seed,true);
valA = random(compSize);
seedRandom(seed+1,true);
valB = random(compSize);
linear(time,A,A + hold, valA, valB)

※補間はeaseでもOKです。

ランダムに関するメソッドは浮動小数を返します。その値を整数にするには、小数点以下を[四捨五入] [切り上げ] [切り捨て]のいずれかの処理が必要になります。
その際に気をつけるポイントがあります。
 
例として整数1~6をランダムに取得する方法を考えます。

四捨五入

  • まずrandom(5)で0から5未満の値(例:2.921...)が得られます。
  • Math.round ( )で小数点以下を四捨五入して整数にします。(例:3)
  • 結果は0から5の整数なので、最後に1を加算します。まとめると

Math.round (random(5)) +1

  • これで目標とした"整数1~6をランダムに取得"することが出来ました。

 
しかしこの式には問題があります。

  • 下のグラフを見てください。横軸が乱数で縦軸が四捨五入の結果です。
  • 四捨五入して[1]になるのは[0.5 から 1.5未満](オレンジ部分)ですから幅は[1]です。
  • しかし[0]になるのは[0 から 0.5未満](グリーン部分)ですから幅は[0.5]です。
  • 同様に[5]になるのは [4.5 から 5未満]だけです。
  • つまり最大値と最小値の出る確率が他の数字の半分しかありません。
  • これを修正するには0.5だけシフトして四捨五入します。

Math.round (random(6) + 0.5)

 

  • これで全ての値が同じ確率で出現します。

 切り上げ:Math.ceil()と切り捨て:Math.floor ()

  • 上の場合、切り上げを使うと四捨五入の問題点を簡単に避けられます。

Math.ceil(random (6))

  • 切捨てを使うと

Math.floor (random (6)) + 1

 一般的に整数の乱数に"0"を含めたい場合は[random()+切捨て]、含めない場合は[random()+切り上げ]を使うと式が簡潔になります。

 

  • ちなみに次のように[ 10 ]を加えると10~15の整数をランダムに返します。

Math.floor(random (6)) + 10