p5.js のフィルター用シェーダー「createFilterShader()」で三角関数を使ったノイズ（WebGL 2.0／GLSL ES 3.0）：seed・スクロールアニメーションを追加

こちらの記事で書いていた内容の続きです。

●p5.js のフィルター用シェーダー「createFilterShader()」で三角関数を使ったノイズの WebGL 2.0／GLSL ES 3.0 バージョン（The Book of Shadersより） - Qiita
　https://qiita.com/youtoy/items/e11126452f8528813f3b

具体的には、上の記事で書いていた「見た目が 1種類限定の静止画的なノイズ画像」に関して、「見た目を変える」「アニメーションさせる」という 2つのことをやります。
（「見た目が異なる複数種類の、静止画的な出力のノイズ画像の出力」と「xy方向にスクロールするアニメーション」という内容をやります）

それらを試した内容は、以下のとおりです。

https://x.com/youtoy/status/1830086501017010566

## 実装について
ノイズ画像をシェーダーで出力する話は、[前の記事](https://qiita.com/youtoy/items/e11126452f8528813f3b)か、その元ネタになっている「[The Book of Shaders: Noise のページ](https://thebookofshaders.com/11/)」をご覧ください。　

その処理を実装すると、以下のようなノイズ画像が得られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/4ac15749-6d6f-5d9e-800f-bb041a3b1e5b.png)

それでは、今回の追加実装の話を書いていきます。

### seed を設定できるようにする
1つ目は、乱数生成でよくある seed のような設定をできるようにします。

前の記事に掲載していたプログラムで言うと、フラグメントシェーダーの以下の部分に手を加えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/b2add3b8-099f-1e72-a522-2f6ce2cb9459.png)

上記は sin() を使ってばらけた値を出力するということをやっていますが、その生成される値の系列が変化するようにします。

コード全体は以下のとおりです。

```javascript
let s;

function setup() {
  createCanvas(500, 400, WEBGL);
  noStroke();

  s = createFilterShader(fragSrc);
}

function draw() {
  background(0);

  const seed = map(mouseX, 0, width, 100.0, 300.0)
  s.setUniform("seed", seed);
  filter(s);
}

const fragSrc = `#version 300 es
precision mediump float;

in vec2 vTexCoord;
out vec4 outColor;

uniform float seed;

// 2D Random
float random(in vec2 st) {
    return fract(sin(dot(st.xy + seed, vec2(12.9898, 78.233))) * 43758.5453123);

}

// 2D Noise
float noise(in vec2 st) {
    vec2 i = floor(st);
    vec2 f = fract(st);
    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));
    vec2 u = f*f*(3.0-2.0*f);
    return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

void main() {
    vec2 st = vTexCoord;
    vec2 pos = st * 5.0;
    float n = noise(pos);
    outColor = vec4(vec3(n), 1.0);
}`;
```

dot() の中に seed の値を入れ、その値は draw() の中で mouseX をもとに用意する構成にしました。

### スクロールアニメーション
次にスクロールアニメーションです。

main() の中で、座標に関わる処理を行っている部分の値を時間変化させます。

処理全体は以下のとおりです。

```javascript
let s;

function setup() {
  createCanvas(500, 400, WEBGL);
  noStroke();

  s = createFilterShader(fragSrc);
}

function draw() {
  background(0);

  const u_time = millis() * 0.003;
  s.setUniform("u_time", u_time);
  filter(s);
}

const fragSrc = `#version 300 es
precision mediump float;

uniform float u_time;

in vec2 vTexCoord;
out vec4 outColor;

// 2D Random
float random(in vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);
}

// 2D Noise
float noise(in vec2 st) {
    vec2 i = floor(st);
    vec2 f = fract(st);
    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));
    vec2 u = f*f*(3.0-2.0*f);
    return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

void main() {
    vec2 st = vTexCoord + vec2(u_time * 0.1, u_time * 0.1);
    vec2 pos = st * 5.0;
    
    float n = noise(pos);    
    outColor = vec4(vec3(n), 1.0);
}`;
```

`vec2 st = vTexCoord + vec2(u_time * 0.1, u_time * 0.1)` という部分で、 `u_time` という時間変化する値を、x座標と y座標の両方に足しています。
（正規化された）座標 0 〜 1 からはみ出た部分は、座標 0 〜 1 をループしているような変化をするので、単純な加算のみ行っておけば OK です。

また、時間変化する値は draw() の以下の部分から受け渡している構成です。

```javascript
  const u_time = millis() * 0.003;
  s.setUniform("u_time", u_time);
```

## 余談
ここからは余談ですが、上記の 2つ目のほうを使った描画で、夜の空みたいな見え方をするものを作ってみました。

https://x.com/youtoy/status/1830188062338580877