見出し画像

つぶやきProcessing四大元素

今年作ったつぶやきProcessingを振り返っていたところ、何らかの自然物(?)のように見える作品が結構ありました。

そこでこの記事では、私が今年作ったつぶやきProcessingを四大元素(火、水、空気、土)になぞらえて紹介します。つぶやきProcessing用に圧縮する前のコードもコメント付きで記載したので、何かの参考になれば幸いです。

ちなみに、Processingではpythonモードを使用しています。

文字通り炎のような効果を狙った作品。確かDark Soulsのリマスター版をプレイして感動して、"BON FIRE LIT"の例のメッセージをイメージしたファンアートを作った際の副産物になります。

Processingの標準ライブラリ界に燦然と輝くヤバイやつ(褒め言葉)こと、PixelFlowを使用して上昇気流を計算。そこに炎っぽい彩色を施したものです。

つぶやきにするために圧縮する前のコードはこんな感じ。

add_library("PixelFlow") # pyhtonモードでJavaライブラリを使うにはadd_libraryを使用

def setup():
    size(720, 720, P2D) # PixelFlowはGPU利用なのでP2Dが必須
    frameRate(50) # Macだと何故かこれがないと表示されない

    global F
    F = DwFluid2D(DwPixelFlow(this), width, height, 1)
    F.param.dissipation_density = 0.8 # 徐々に色が消えるようにすることで炎っぽく

def draw():
    s = frameCount**4/5e10-1 # 色の微調整
    F.addTemperature(random(width), 0, 20, 3) # 熱源の設置
    F.addDensity(random(width), 0, 50, s, s/2, s/5, 1) # インクを撒く
    F.update() # 流体計算の更新
    F.renderFluidTextures(g,0) # 計算結果の描画

これはスプラトゥーン3が面白くて、そのファンアートとして作ったものです。なんだか今年はこんなノリが多い気がします。水というかインク。

コードの特徴としてはrandom()では文字数が厳しかったのでsin()を代わりに使って疑似乱数にしています。sin()は実際には周期関数ですが、適当な変数を引数にしておけば予測不可能な結果になるだろうという発想。

このコードの圧縮前はこんな感じです。

size(720, 720)
clear()
noStroke()
colorMode(3, 9)
for k in range(80):
    with push():
        fill([3,5,8][k%3], 4 ,9) # 色を緑、青、赤で振る
        scale(sin(k)) # サイズを擬似ランダムに
        translate(1e3*sin(k**3), 1e3*sin(k**7)) # 位置を擬似ランダムに(3と7はいい感じの結果が得るための調整パラメータ)
        for j in range(12): # 飛沫の「足」の部分は12本
            rotate(0.52) # 本来は2*PI/12(=0.5236)、だけれど精度2桁でもそれっぽくなる
            for i in range(205 + int(25*sin(j*k))): # 飛沫の「足」のサイズを擬似ランダムに
                circle(i, 0, min(sq(i-160)/99+9, 99)) # 飛沫の「足」の部分がなめらかにつながるよう調整

空気

四大元素の空気… というか、雲のような印象。

これは今年の2月に開催されていたコードチャレンジのイベント、#AltEdu2022をきっかけに生まれた作品です。Twitterで#AltEdu2022で検索すると色々な作品が見れるのでおすすめ。

これは2月5日のお題、「線を使わないで線を書いてみてください」から派生したもの。線を避けるように円を並べたら、「線が存在しない場所」として線が浮かび上がるのでは… と考えて作ったコードを、「円を避けるように円を並べる」とアレンジしたものです。

圧縮前のコードはこちら。

size(720, 720)
noStroke()
background(1, 90, 170)
for i in range(5000):
    x, y = random(720), random(720) # 描画する円の中心をランダムに選択
    r = 360 - max(abs(x-360), abs(y-360)) # 画面の端からの距離関数
    for i in range(12):
        r = min(r, dist(x, y, 360+245*cos(-i*.52), 360+245*sin(-i*.52))-i*5-2) # 距離関数に円の距離関数を合成
    fill(255, 8*exp(-r/70.)) # 接触する何かとの距離に応じて色の透明度を調整
    circle(x, y, 2*r) # 距離関数を参照して、ちょうど何か(画面の端か円)に接触するように円の直径を調整

コメントに出てくる「距離関数」は、特定の図形からの距離を表す関数で、GLSLを使ってレイマーチングをする際によく使います。二次元の距離関数についてはiq氏による記事がとても参考になります。

これは土、というか金属の光沢を表現しようとした作品。

非線形変換を繰り返すことで複雑な模様を作り、模様の「斜め下」の値を参照して色を決めることで金属光沢っぽい輝きを表現したものです。

圧縮前のコードはこちら。

def F(x, y): # 非線形変換
    return abs(sin(y)+log(x))

def G(x, y): # 引数を入れ替えながら非線形変換を適用
    return F(x,y),F(y,x)

def H(i, j): # 各点の座標をもとに上記の非線形変換を繰り返し適用
    r = dist(i, j, 360, 360)/65 # 1つ目の引数。画面中心からの距離
    q = abs((atan2(j-360, i-360)*12/PI)%4-2) # 2つ目の引数中心からの角度、をもとに6回回転対称のパターンを生成。
    return G(*G(*G(r, q+r)))[0] # pythonのunpack記法。G(*[x, y])はG(x, y)のように展開される。

size(720,720)
for i in range(width):
    for j in range(height):
        c = 360*(H(i+2, j+3) - H(i, j)) # 現在の点(i, j)と、その斜め下(i+2, j+3)の差を取り、斜め方向の「傾き」として扱う
        stroke(3*c, 2*c, c) # 傾きに応じて色付け。RGB値を3:2:1の比にすると黄金っぽい色味に
        point(i, j)


以上、今年のつぶやきProcessingでした!

この記事が気に入ったらサポートをしてみませんか?