Open8

glsl表現備忘録(p5.js)

からくれ178からくれ178

p5.jsでGLSL(フラグメントシェーダー)を書いていて高確率でどうやったっけ?となるのでどの表現がどのコードだったのかをメモ書きしていく。

からくれ178からくれ178

使用するテクスチャイメージはこちら。

基本コードは以下である。基本的にテクスチャであるpgに対してシェーダーをかけていく。
https://editor.p5js.org/Karakure178/sketches/cxM8USsOI

let pg;
let theShader1;

function setup() {
  createCanvas(800, 800,WEBGL);
  pg = createGraphics(width, height);
  pg.noStroke();
  pg.fill('#776B5D');
  background('#F3EEEA');
  noStroke();
}

function draw() {
  translate(-width / 2,-height / 2);//WEBGLは真ん中基準だがcreageGraphicsは左上基準なので合わせるために設定している
  pg.push();
  grid(10,pg);
  pg.pop();
  
  // シェーダーの設定
  theShader1 = createShader(shader1.vs, shader1.fs);
  shader(theShader1);
  theShader1.setUniform(`u_tex`, pg);
  theShader1.setUniform(`u_time`, frameCount / 35);
  theShader1.setUniform('u_resolution', [pg.width, pg.height]);
  
  // シェーダー適用したイメージを描画
  image(pg,0,0);
}

/** num個で分割したグリッドを画面いっぱいに生成する
* @method grid
* @param  {Number}        num           画面の分割数
*/
const grid = (num,pg) => {
    const n1 = num + 1;
  
    const margin_left = width / n1 / n1;
    const margin_bottom = height / n1 / n1;

    const nw = width / n1;
    const nh = height / n1;

    for (let i = 0; i < num; i++) {
      for (let j = 0; j < num; j++) {
        const x = nw * i + margin_left * (i + 1);
        const y = nh * j + margin_bottom * (j + 1);
        pg.circle(x + nw / 2, y + nw / 2, nw);
      }
    }
};

keyPressed = () => {
  if (key === 's') {
    saveCanvas(canvas, 'canvas', 'png');
    //saveGif('canvas', 4);
  }
};

const shader1 = {
  vs: `
  precision highp float;
  precision highp int;

  attribute vec3 aPosition;
  attribute vec2 aTexCoord;

  varying vec2 vTexCoord;

  uniform mat4 uProjectionMatrix;
  uniform mat4 uModelViewMatrix;

  void main() {
    vec4 positionVec4 = vec4(aPosition, 1.0);
    gl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;
    vTexCoord = aTexCoord;
  }
`,
  fs: `
  precision highp float;
  precision highp int;

  varying vec2 vTexCoord;

  uniform sampler2D u_tex;
  uniform float u_time;
  uniform vec2 u_resolution;

  float PI = 3.14159265358979;

  void main() {
    vec2 uv = vTexCoord;
    vec4 tex = texture2D(u_tex, uv);

    gl_FragColor = tex;
  }
`,
};
からくれ178からくれ178

ホワイトノイズを描く。

https://editor.p5js.org/Karakure178/sketches/DrM_C6qiR
主要コードは以下。

  float random(vec2 c){
    return fract(sin(dot(c.xy ,vec2(12.9898,78.233))) * 43758.5453);
  }

  void main() {
    vec2 uv = vTexCoord;
    // white noise用
    float interval = 3.0;
    float strength = smoothstep(interval * 0.5, interval, interval - mod(u_time, interval));
    float whiteNoise = (random(uv + mod(u_time, 10.0)) * 2.0 - 1.0) * (0.15 + strength * 0.15);

    vec4 tex = texture2D(u_tex, uv);
    gl_FragColor = tex + whiteNoise;
  }

新たにrandom関数を定義しているがこの形ではiosでは動かないとの話もあったので要注意。
記事がそこそこ前なので今は改善されているかもしれない(未検証)。
浮動小数点の精度のバラつき

参考資料:
https://codepen.io/ykob/pen/GmEzoQ?editors=1010
https://nogson2.hatenablog.com/entry/2017/11/18/150645
http://www.science-and-fiction.org/rendering/noise.html

からくれ178からくれ178

魚眼レンズを描く。

https://editor.p5js.org/Karakure178/sketches/YjP0PLmvU
主要コードは以下である。

    float apertureHalf = 0.5 * u_aperture * (PI / 180.0);
    float maxFactor = sin(apertureHalf);

    vec2 xy = 2.0 * uv.xy - 1.0;
    float d = length(xy);

    if (d < (2.0-maxFactor)){
      d = length(xy * maxFactor);
      float z = sqrt(1.0 - d * d);
      float r = atan(d, z) / PI;
      float phi = atan(xy.y, xy.x);
      
      uv.x = r * cos(phi) + 0.5;
      uv.y = r * sin(phi) + 0.5;
    }

参考資料:
https://www.geeks3d.com/20140213/glsl-shader-library-fish-eye-and-dome-and-barrel-distortion-post-processing-filters/

からくれ178からくれ178

ハッチングを描く。

https://editor.p5js.org/Karakure178/sketches/NGeMf9Bxv
主要コードは以下である。

    float hatch = 10.0;// ハッチングのサイズを変えられる
    float lum = length(texture2D(u_tex, uv.xy).rgb);

    vec4 tex = texture2D(u_tex, uv);
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    bool isHatch = false;

    if (lum < 1.00){
      if (mod(gl_FragCoord.x + gl_FragCoord.y, hatch) == 0.0){
        gl_FragColor = tex;
        isHatch = true;
      }
    }

    if (lum < 0.75){
      if (mod(gl_FragCoord.x - gl_FragCoord.y, hatch) == 0.0){
          gl_FragColor = tex;
          isHatch = true;
      }
    }

    if (lum < 0.50){
      if (mod(gl_FragCoord.x + gl_FragCoord.y - 5.0, hatch) == 0.0){
          gl_FragColor = tex;
          isHatch = true;
      }
    }

    if (lum < 0.3){
      if (mod(gl_FragCoord.x - gl_FragCoord.y - 5.0, hatch) == 0.0){
          gl_FragColor = tex;
          isHatch = true;
      }
    }

    if(isHatch == false){
      gl_FragColor = vec4(u_color, 1.0);
    }

backgroundとハッチングする箇所のだし分け方法が思い浮かばなかったためbackgroundのカラーを別途p5jsからglslへ渡している。(u_color)
参考資料:
https://github.com/pixijs/filters/blob/main/filters/cross-hatch/src/crosshatch.frag

からくれ178からくれ178

ぼかしたい。

https://editor.p5js.org/Karakure178/sketches/OJStMs0oI

主要コードは以下である。

const float Directions=100.;// BLUR DIRECTIONS
const float Quality=10.;// BLUR QUALITY
const float Size=5.;// BLUR SIZE

// 省略

for(float d=0.;d<Pi;d+=Pi/Directions){
  for(float i=1./Quality;i<=1.;i+=1./Quality){
    Color+=texture2D(u_tex,uv+vec2(cos(d),sin(d))*Radius*i);
  }
}

ガウス分布を使用したぼかしフィルタ。上3つパラメータでぼかし感を変え、下のfor文で畳み込みを計算しピクセルの色を決定している。

参考資料:

https://www.shadertoy.com/view/Xltfzj
https://xorshaders.weebly.com/tutorials/blur-shaders-5-part-2
https://www.youtube.com/watch?v=CHx6uHnWErY