はじめに
このページでは以下の作品について説明します。
#つぶやきProcessing ノイズ山脈
— Koji Saito (@KojiSaito) July 17, 2020
def setup():size(500,300);noStroke()
R=range
def draw():
filter(BLUR,1)
for y in R(300):
h=90
for x in R(-50,500):
t=noise(x*.05,y*.07)*90
if t>h:
fill(-1,50);h=t
else:
fill(50,50);h-=sin(frameCount*.02)**2*2
rect(x,y,1,1) pic.twitter.com/Meq8itrjei
この作品はノイズ曲面を山脈にみたて、 その曲面に左側から平行光源を当てた場合の影を計算しています。 光源の傾きは時間とともに変化し、 その様子が日の出と日没のように感じたため、 このようなタイトルにしました。
ソースコード
短縮化処理(code golf しない版)のソースコードを以下に示します:
def setup():
size(500,300)
def draw():
filter(BLUR,1)
for y in range(300):
h=90
for x in range(-50,500):
t=noise(x*.05,y*.07)*90
if t>h:
stroke(-1,50)
h=t
else:
stroke(50,50)
h-=sin(frameCount*.02)**2*2
point(x,y)
解説
このプログラムでは、500 x 300 の領域にある全ピクセルに対し、 色付けの処理を行っています。 なので、本作品は計算負荷の高い作品です。
全ピクセルの処理は以下の 2 重ループ内で行わrています:
for y in range(300):
# y=0,1, ... ,299 と変化させつつ
for x in range(-50,500):
# 各 y に対して、
# x=-50,-49, ... , -1,0,1,2, ... , 499 と変化させて
# 各 (x,y) に対して描画処理を行う
x 座標の変動範囲が -50 〜 499 となっているのは、 左側の画面外からの処理も必要になるためです。
各 y の値に対し、h=90 という処理を行っています。 この変数 h は、現在、光が到達していない影の部分の高さを表しています。
言い換えれば、この h よりも標高(=ノイズ曲面の高さ)が高ければ その部分は光が当たっていることとなりますし、 そうでなければ影になります。
このプログラムでは、 座標 (x,y) のノイズ曲面の高さは変数 t に格納されていますので、 プログラムでは
if t>h:
# 光が当たっているときの処理
else:
# 影領域での処理
と書き表されます。
光が当たっている場合は、座標 (x,y) のピクセルの色は明るい色とします。 そして、影領域の高さを示す変数 h も現在のノイズ曲面の高さである t の値に更新されます。
一方、影であった場合は、その座標のピクセルは暗い色に指定されます。 そして、変数 h の高さを光線の進路に応じて変化させます。 この作品の場合は、左側から太陽光線が当たっていると想定していますので、 x 座標が進むにつれ、その高さは減って行きます。
今回はアニメーションの進行と共にその高さを変化させるため、 h の変化量を \( -2\sin(0.2 \cdot \mbox{frameCount})^2 \) としました。
このような変化量にした理由は周期的な関数にしたかったことと、 負の値にならないように工夫しただけで、何か物理的な根拠があるわけではありません。
逆に言えば、ジェネラティブアート作品の作者が勝手に決める領域の作業に他なりません。
話を光線の処理に戻します。 この処理は何をやっているかというと、 x 座標を更新するにあたり、前回光が当たった部分の高さ (つまり、現在影を落としている遮蔽物の高さ)を \( h_0 \) とするならば、 座標 x における、この遮蔽物が落とす影の高さ h は
$$ h(x)= a (x-x_0) + h_0 $$
という処理に他なりません。 ただし、上の式における \( x_0 \) は現在影を落としている 遮蔽物が存在する x 座標の位置であり、 傾き a は上で示した定数 \( -2\sin(0.2 \cdot \mbox{frameCount})^2 \) です (あるフレームに着目して考えているので、 この場合 frameCount は定数として解釈します)。
この作品で用いている処理は、このように単純なものです。 強いていえば、レイマーチングやレイキャストの非常に単純化したものと言えるかもしれません。
原理的にはレイキャストによる影付け(= shadowing )に他ならないため、 ノイズ曲面が影付けされて画像化(= rendering )されています。
まとめ
このページでは、対象となる作品を紹介し、 その清書版のソースコードを掲載しました。 このソースコードを基として、アルゴリズムの解説を行いました。 このプログラムで行っている処理は、 非常に簡単なレイマーチングによるレイキャストであり、 それにより影付けが実施されていることを示しました。