見出し画像

Processing.pyでアート #4 Shader

PCD2019FMS_Catさんワークショップで教わったシェーダーが面白かったので、pythonモードでもやってみました!

まず以下のコードをProcessingで書いて、

def setup():
    size(400, 400, P2D)
    
    global sh
    sh = loadShader("shader.frag")

def draw():
    background(0);

    noFill()
    stroke(255)
    strokeWeight(100)
    rectMode(CENTER)
    rect(width/2, height/2, 140, 140)

    sh.set("time", frameCount*0.005)
    filter(sh)

このProcessingのコードがおいてあるフォルダにdataフォルダを作って、その中に以下のshader.fragファイルを置きます。
(ということになってるけど、dataフォルダを作らず、.pydeファイルと.fragファイルを同じ場所に置いても動くっぽい)

uniform vec2 resolution;
uniform sampler2D texture;
uniform float time;
const float PI = 3.141592653589793;

void main(){
  vec2 uv = gl_FragCoord.xy/resolution;
  vec2 xy = uv-0.5;

  float t = 10.*cos(PI*time);
  float a = 0.8;
  xy.x = xy.x+a*sin(xy.x*t)*sin(xy.y*t);
  xy.y = xy.y+a*sin(xy.y*t)*sin(xy.x*t);

  gl_FragColor = texture2D(texture, xy+0.5);
}

そうすると、Processingで描いた四角形をシェーダーでグネグネ曲げることができます!楽しい!

Pythonモードでの注意

これをpythonで書くときにハマったことはいくつかあって、ひとつは

sh = loadShader("shader.frag")

def setup():
    size(400, 400, P2D)

def draw():
    ...

みたいに、setup()の外でグローバル変数を作ると同時にシェーダーを読み込むのはダメ、ということ。pythonは型宣言がないので、変数を作ったら同時に初期化しがち。setup()を呼ぶ前だと解像度が定まってないからシェーダー読めないのかな?

あとはシェーダーに時間を渡す際に、

sh.set("time", frameCount)

とするのもダメでした(常にtime=0になってしまう)。これ一見問題なさそうなんですが、シェーダー側でfloatで受け取るものは、こちらもfloatで渡す必要があるみたい(pythonって型を書かないのでこれもしばらく謎でした...)。frameCountに適当な計算をして小数にすればOKでした。



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