Smoke(2020.03.07)

作品解説

 自然現象を つぶやき Processing したくて、この日は「煙」をテーマに選びました。 煙は CG でもパーティクルという機能で表現されているものであり、 つぶやき Processing でも、まあ、なんとか表現できるだろう、という目論見はありました。

ソースコード(清書版)と解説

N=500
R=random
P=[[250,N,20,R(4)-2,-R(5)-2] for i in [0]*N]
I=[250,N,20] # パーティクルの初期値(煙の発生場所と半径)
def setup():size(N,N);noStroke()
def D(i,x,y,r,s,t):
    fill(255,y*.1);circle(x,y,r)
    e=P[i]
    e[0]+=s;e[1]+=t;e[2]*=1.02
    if y<0:P[i][:3]=I
def draw():
    clear()
    [D(i,*P[i]) for i in range(N)]

 グローバル変数として宣言されている配列 P に、 各パーティクルの位置(x,y) と半径が格納されています。

i 番目のパーティクルの x 座標は P[i][0] に、 y 座標および半径 r は P[i][1], P[i][2] に格納されています。

$$ \mbox{i 番目のパーティクルの}(x,y,r)=(P[i][0],P[i][1],P[i][2]) $$

配列 P の要素には、(x,y,r) だけではなく、 パーティクルの速度 (s,t) も格納されています。

$$ \mbox{i 番目のパーティクルの速度ベクトル}(s,t)=(P[i][3],P[i][4]) $$

 関数 D では、パーティクル番号 i と、位置 (x,y) と 半径 r 、および 速度 (s,t) を受け取り、i 番目のパーティクルを描画と位置の更新を行っています。

描画に際しては、y の値に応じて α 値を変化させています。 y の値が小さい=画面上方に描画されるもの程、薄く描画されるように設定しています (fill(255,y*.1) の部分)。

 パーティクルの位置の更新では、文字数を減らすため、 変数 e に一度 P[i] を格納しています。 その後、

e[0]+=s
e[1]+=t

として、パーティクルの位置を更新しています。

 関数 D では、パーティクルの半径も更新しています。 半径については、等比級数的に拡大した方が、煙のような表現になりますので、 1.02 を乗ずることで処理しています。

この辺りは、どの程度の拡散速度にするのかにより決まってくる定数だと思います。

関数 D の最後にある if 文にて、パーティクルの y 座標が 0 より小さくなったら、 位置と半径を初期値に戻すよう設定しなおしています (速度ベクトル P[i][3],P[i][4] は変化させていません)。

 描画のメインルーチンは関数 D なので、 draw 関数内でパーティクルの数だけ関数 D を呼び出しています。