Processing.pyでアート #11 VectorField
今回は、deconbatchさんのベクター・フィールドをpythonモードでやってみました。
作例はこんな感じ。
ベクトル場の生成には、以前のシェーダーを使った作品
で利用した、行列積&非線形変換による複雑な模様生成器を再利用。描画される線の流れが途中でカクっと変わる様になりました。
コードは以下です。
def setup():
size(400, 400, P2D)
pixelDensity(displayDensity()) # retinaディスプレイのための呪文
smooth()
colorMode(HSB, 360, 100, 100, 100)
blendMode(SCREEN)
def draw():
noiseSeed(long(random(1e6))) # noiseSeedの引数はlong型なので注意
step = 0.002
stepNum = 500
gridNum = 50
h = random(360)
noFill()
stroke(h, 50, 10, 50)
background(0)
for i in range(gridNum):
for j in range(gridNum):
x = map(i, 0, gridNum-1, 0, 1)
y = map(j, 0, gridNum-1, 0, 1)
for k in range(stepNum):
v, th = field(x, y) # 関数が多値を返せる
v *= step
v += step*0.1
th = atan2(y-0.5, x-0.5) + th*PI
x += v*cos(th)
y += v*sin(th)
strokeWeight(map(k, 0, stepNum, 1, 3))
point(map(x, 0, 1, 0, width), map(y, 0, 1, 0, height))
saveFrame("frames/####.png")
if frameCount == 200:
noLoop()
def field(x, y): # ベクターフィールド (x, y成分ではなく大きさと角度として使う)
r, th, _ = tr(*tr(*tr(abs(x-0.5), abs(y-0.5), 1))) # *でタプルのアンパック
return r, th
def mat(i, j): # 以下のtr()で使う乱数
return 2*noise(i, j)-1.
def act(x): # 以下のtr()で使う非線形関数
return (3*noise(frameCount*0.1)*x)%1
def tr(a, b, c): # なにかややこしい変換 (行列演算&非線形変換)
x = act(mat(0, 0) * a + mat(1, 0) * b + mat(2, 0) * c)
y = act(mat(0, 1) * a + mat(1, 1) * b + mat(2, 1) * c)
z = act(mat(0, 2) * a + mat(1, 2) * b + mat(2, 2) * c)
return x, y, z
3つの引数を取って3つの値を返す変換関数tr(a, b, c)を繰り返し使うことで、ベクトル場を用意。
pythonの関数は多値が返せるので便利... なのですが、関数の戻り値は実際にはタプルなので、「3つ値を返す関数」を「3つ変数を取る関数」の引数部分に書くには、* でタプルを展開(アンパック)する必要があります。コードの中では以下の部分。
r, th, _ = tr(*tr(*tr(abs(x-0.5), abs(y-0.5), 1))) # *でタプルのアンパック
ちなみに上の行は「なんかややこしいことにな〜れ」くらいの気持ちで書いてます。
ベクター・フィールドは、ベクトル場を作る数式(私のコードだとact()をいじると印象が大きく変化)を変えたり、線の密度や太さや色を変えたりでさらにいろいろ遊べます。...楽しい!
この記事が気に入ったらサポートをしてみませんか?