お題:ミキサー(2020.05.02)

はじめに

 この作品は 2020 年 4 月 1 日から 5 月 14 日にかけて開催された、 #dailycodingchallenge の 5 月 2 日のお題「ミキサー」についての作品です。

ソースコードおよび解説

 この作品は見ての通り、赤と青の 2 つの色で色分けされた粒子が 動きつつ回転する、という作品です。

構成要素としては、

  • ノイズによる運動
  • 色付け
  • 回転
  • 残像効果
  • ぼかすための全画面ブラー

に分けられます。

色付け以外の部分については、こちらの作品で実現しているものです。

 今回の作品のソースコードは以下のようになります:

M=500

def setup():
    size(M,M)
    noStroke()
    background(-1)

G=lambda p,q,t:cos(t)*p+sin(t)*q+M/2

N=noise
C=[255,50,20] # 色指定のための配列

def draw():
    t=frameCount*.03
    fill(-1,5);
    rect(0,0,M,M);
    for i in range(98):
         C[0],C[2]=C[2],C[0] # 色の入替え処理
         fill(*C)
         x=(N(i,t/2)-.5)*M;
         y=(N(t/2,i)-.5)*M;
         circle(G(x,y,t),G(y,-x,t),20)
    filter(BLUR,3)

色の入替え処理

 現在処理中の粒子(パーティクル)の色は帯域変数 C に格納されています。 初期値は C=[255,50,20] であり、つまり (R,G,B)=(255,50,20) の赤色です。

C[0],C[2]=C[2],C[0]

で R チャネルの値と B チャネルの値を入替えています。 つまり、この処理を一度行うと、C の値は C=[20,50,255] となります。

当然、再度この入替え処理を行うと、C=[255,50,20] と初期値に戻り、 結果として

fill(255,50, 20)
fill( 20,50,255)
fill(255,50, 20)
fill( 20,50,255)
      :

と赤色と青色が繰り返し指定されることとなります。

ひとつの関数で行う回転処理

 各パーティクルを角度 t にて回転させることで、全体的に回転させています。

点 (x,y) を点 (a,b) を中心に t だけ回転させた座標 (x’,y’) は

$$ \left( \begin{array}{c} x’ \newline y’ \end{array} \right) = \left( \begin{array}{cc} \cos t & -\sin t \newline \sin t & \cos t \end{array} \right) \left( \begin{array}{c} x \newline y \end{array} \right) + \left( \begin{array}{c} a \newline b \end{array} \right) $$

で表されます。

これを行列を使わずに書き下すと次のようになります:

$$ \left\{ \begin{array}{l} x'=\cos(t) x - \sin(t) y +a \newline y'=\sin(t) x + \cos(t) y +b \end{array} \right. $$

code golfing のため、この式を変形すると次のようにも書き表せます:

$$ \left\{ \begin{array}{l} x'=\cos(t) x + \sin(t) \cdot (-y) +a \newline y'=\cos(t) y + \sin(t) x +b \end{array} \right. $$

これはつまり、関数 G を次のように定義すると、

$$ G(p,q,t,c) = \cos(t) p + \sin(t) q + c $$

(x’,y’) は次のように書けます:

$$ \left\{ \begin{array}{l} x'=G(x,-y,t,a) \newline y'=G(y,x,t,b) \end{array} \right. $$

Processing で反時計回りにする場合

 実際のソースコードでの使用法をみてみると、 関数 G の実装は同じ(a=b=M/2)であるにも関わらず、 circle 関数の引数として使用されているのは、

circle(G(x,y,t),G(y,-x,t),20)

であり、いわば

$$ \left\{ \begin{array}{l} x'=G(x,y,t,M/2) \newline y'=G(y,-x,t,M/2) \end{array} \right. $$

となっており、上で示した方法とは異なっています。

 これは Processing の座標系が数学でよく使う座標系と異なり、 下の方に y 軸のプラス方向が向いているからです。

まず話を簡単にするために、回転の中心を原点とします (説明をした後に、+b だけ並行移動させます)。

これまでの議論の結果を利用するためには、 まず回転処理を行う入力としての (x,y) を、 y 軸方向だけ反転させる必要があります。

つまり、回転処理を行うための座標を (x,y) ではなく (x,-y) とする必要があります。

で、計算の結果得られる (x’,y’) ですが、 これも数学での座標系においての位置ですので、 得られた (x’,y’) も y 軸方向に反転して (x’,-y’) としなければ Processing において意図した位置にはなりません。

 原点を中心とする(つまり b=0 とした場合の) y’ の計算式は、

$$ y'=\cos(t) y + \sin(t) x $$

でしたので、Processing の座標系に合わせるためには、 y と y’ をそれぞれ -1 倍したものとします。 すると、

$$ -y'=\cos(t) (-y) + \sin(t) x $$

という式が得られます。

この式の両辺に -1 を掛けて、整理すると

$$ y'=-\cos(t) (-y) - \sin(t) x = \cos(t)y+\sin(t)(-x) = G(y,-x,t,0) $$

を得ます。

 この作品では、最終的に点 (M/2,M/2) を中心に回転させていますので、 結局

$$ y'=G(y,-x,t,M/2) $$

となります。

 x’ の計算では、G の引数として -y を利用するだけで良いので、 結果として、ソースコードの形となります。