WebGL で色々な表現に挑戦する - ノイズを作成する

## この記事の概要

[前回の記事](https://qiita.com/xrxoxcxox/items/146d744bf7f124924eff)ではグラデーションを扱いました。
今回はノイズを作ってみようと思います。

## 単純な白黒のノイズ

組み込みのノイズ生成関数などは無いので、自作します。[^1]

[^1]: このノイズ関数、調べているといたるところで目にするのですが、出典が分かりません。[Stack Overflow でも質問している人がいましたが、明確な答えは出ていなさそうでした](https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner)。

```diff_glsl:plane.frag
  void main() {
    float noise = fract(sin(dot(vTextureCoord.xy, vec2(12.9898,78.233))) * 43758.5453);

    outColor = vec4(noise, noise, noise, 1.0);
  }
```

このように、白黒のノイズが得られました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/b59be33a-460e-6f8c-418a-66ba5ba765da.jpeg)

## 上記のノイズの色ズレ

`vTextureCoord.xy` の値を操作すると、生成されるノイズが変わります。
r, g, b それぞれを少しずつ変えるため、関数に切り出して操作できるようにします。

```diff_glsl:plane.frag
+ float createNoise(float seed) {
+   return fract(sin(dot(vTextureCoord.xy * seed, vec2(12.9898,78.233))) * 43758.5453);
+ }

  void main() {
-   float noise = fract(sin(dot(vTextureCoord.xy, vec2(12.9898,78.233))) * 43758.5453)
+   float r = createNoise(2.0);
+   float g = createNoise(5.0);
+   float b = createNoise(10.0);

-   outColor = vec4(noise, noise, noise, 1.0);
+   outColor = vec4(r, g, b, 1.0);   
  }
```

r, g, b を分解したため、白黒ではなくカラフルな感じのノイズになりました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/e1ed5370-2b6e-d884-9a9b-a5e3bf5f9cea.jpeg)

この状態だと、どの色もおよそ平等に出現しています。
これを例えば赤ベースにしたければ次のようにします。

```diff_glsl:plane.frag
  float createNoise(float seed) {
    return fract(sin(dot(vTextureCoord.xy * seed, vec2(12.9898,78.233))) * 43758.5453);
  }

  void main() {
-   float r = createNoise(2.0);
+   float r = createNoise(2.0) * 2.0;
    float g = createNoise(5.0);
    float b = createNoise(10.0);

    outColor = vec4(r, g, b, 1.0);   
  }
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/007d6950-8e85-1eb6-fdef-27c9d5c37915.jpeg)


## グラデーション + ノイズ

前回、前々回の記事で作ったようなグラデーションは、ノイズと組み合わせることもできます。

```diff_glsl:plane.frag
  void main() {
+   float gradient = sin(vTextureCoord.y);
+   float noiseIntensity = mix(1.0, 0.5, gradient);
    float r = createNoise(2.0) * 2.0; // 一旦使わない
    float g = createNoise(5.0); // 一旦使わない
    float b = createNoise(10.0); // 一旦使わない
+   vec3 color = vec3(gradient) + createNoise(1.0) * noiseIntensity;

-   outColor = vec4(r, g, b, 1.0);
+   outColor = vec4(color, 1.0);
  }
```

このように、上行くにつれてノイズが弱くなるようなグラデーションを作れました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/62ac1df7-b73e-50a8-581b-06ac4f5bb504.jpeg)

これを r, g, b それぞれに適用すれば、

```diff_glsl:plane.frag
  void main() {
    float gradient = sin(vTextureCoord.y);
    float noiseIntensity = mix(1.0, 0.5, gradient);
+   float r = createNoise(2.0) * 2.0 + gradient;
+   float g = createNoise(5.0) + gradient;
+   float b = createNoise(10.0) + gradient;
-   float r = createNoise(2.0) * 2.0;
-   float g = createNoise(5.0);
-   float b = createNoise(10.0);
-   vec3 color = vec3(gradient) + createNoise(1.0) * noiseIntensity;
+   vec3 color = vec3(r, g, b) * noiseIntensity;   

    outColor = vec4(color, 1.0);
  }
```

先ほど作った赤ベースのノイズ + グラデーション、という表現になりました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/01f90e17-dd3b-8b32-f1aa-5e4d15bd7875.jpeg)

ここまで来れば数値を適当に足したり掛けたりするだけで楽しくなってきます。

```diff_glsl::plane.frag
  void main() {
    float gradient = sin(vTextureCoord.y);
    float noiseIntensity = mix(1.0, 0.5, gradient);
    float r = createNoise(2.0) * 2.0 + gradient;
    float g = createNoise(5.0) + gradient;
-   float b = createNoise(10.0) + gradient;
+   float b = createNoise(10.0) + gradient * noiseIntensity;
    vec3 color = vec3(r, g, b) * noiseIntensity;

    outColor = vec4(color, 1.0);
}
```

今回はこのように色相を変えてみました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214677/43bbfdff-2533-e98d-dbfe-b018048c333d.jpeg)

## 最後に

かなり複雑な表現ができるようになってきたと思います。
ノイズ関数は調べると色々なものがあり、深い理解はできませんでしたが、単に「ザラっとした質感を表現をしたい」くらいであれば実際にも使えると思います。

次は時間による変化をつけていきます。

https://qiita.com/xrxoxcxox/items/dedd6c8c2874b642bbd6