3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

完走賞を目指す @xrxoxcxoxAdvent Calendar 2023

Day 19

WebGL で色々な表現に挑戦する - 時間経過による変化

Last updated at Posted at 2023-12-16

この記事の概要

前回の記事で時間経過にあわせてグラフィックを変更するための下準備をしました。

もう少し色々な表現を探ります。

グラデーションの変化

sin(vTextureCoord.x) だと左から右に行くにつれて黒から赤に変わるグラデーションでした。
このグラデーションの位置を変えます。

plane.frag
  void main() {
    float pi = acos(-1.0);

-   float r = sin(vTextureCoord.x);
+   float r = sin(vTextureCoord.x + uTime);

    outColor = vec4(r, 0.0, 0.0, 1.0);
  }

sin へ渡す値に uTime を足しています。
これで時間経過にあわせて sin の中身が変わるので、グラデーションが水平方向に動いているような見た目になります。

今度はグラデーションの明度は変えず、色相だけが変わるようにしてみます。

plane.frag
  void main() {
    float pi = acos(-1.0);

+   float value = sin(vTextureCoord.x);
-   float r = sin(vTextureCoord.x + uTime);
+   float r = value * sin(uTime * 1.2);
+   float g = value;

-   outColor = vec4(r, 0.0, 0.0, 1.0);
+   outColor = vec4(r, g, 0.0, 1.0);
  }

sin の中身自体が変わるとグラデーションの位置が変わりますが、sin(vTextureCoord.x) を変えずに係数として uTime を使うと色相が変わります。

ノイズの変化

単なる白黒のノイズを動かします。

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

  void main() {
+   float noise = createNoise(uTime);

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

先ほどとコードの作りはほとんど同じです。

少しだけ色ズレしたノイズを作る際も、シードとして渡す値を少しだけいじれば大丈夫です。

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

  void main() {
-   float noise = createNoise(uTime);
+   float r = createNoise(uTime);
+   float g = createNoise(uTime + 1.0);
+   float b = createNoise(uTime + 2.0);

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

ノイズが素早く動くという性質上、添付の gif がかなり粗く、重くなってしまっていますが、雰囲気は理解いただけると思います。

色々なものを組み合わせる

ここまでもノイズは多用していましたが、簡単なものだけでした。
GLSL noise などと調べると先人の作ったノイズがたくさん見つかります。1

こういったものを使って実装してみます。

#version 300 es

precision mediump float;

in vec2 vTextureCoord;

uniform float uTime;

out vec4 outColor;

float pi = acos(-1.0);

vec3 permute(vec3 x) {
  return mod(((x * 34.0) + 1.0) * x, 289.0);
}

float sNoise(vec2 v) {
  const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);
  vec2 i = floor(v + dot(v, C.yy));
  vec2 x0 = v - i + dot(i, C.xx);
  vec2 i1;
  i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
  vec4 x12 = x0.xyxy + C.xxzz;
  x12.xy -= i1;
  i = mod(i, 289.0);
  vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 )) + i.x + vec3(0.0, i1.x, 1.0 ));
  vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);
  m = m * m;
  m = m * m;
  vec3 x = 2.0 * fract(p * C.www) - 1.0;
  vec3 h = abs(x) - 0.5;
  vec3 ox = floor(x + 0.5);
  vec3 a0 = x - ox;
  m *= 1.79284291400159 - 0.85373472095314 * ( a0 * a0 + h * h );
  vec3 g;
  g.x = a0.x  * x0.x  + h.x  * x0.y;
  g.yz = a0.yz * x12.xz + h.yz * x12.yw;
  return 130.0 * dot(m, g);
}

void main() {
  float offset = sNoise(vec2(cos(vTextureCoord.x * pi) + uTime * 0.1, vTextureCoord.y * sin(uTime) * 0.2) - uTime * 0.1);
  float colorValue = mix(1.0, offset, 0.25);
  float r = clamp(colorValue, 0.2, 0.75);
  float g = clamp(colorValue + 0.1, 0.2, 0.85);
  float b = clamp(colorValue * 1.2, 0.2, 0.9);

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

急にエモい感じになりました。
ブランドサイトの背景とかに使えそうな感じがあります。

最後に

ノイズの実装され方をすべて理解するのは難しすぎて諦めました。
普段何気なくライブラリを使っているときも、背景にはこれぐらい難しいコードがあるってことだよな、と謎の自戒が生まれています。

次は操作に合わせて変化するようにしたいです。

  1. 例: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83 本文内にURL を貼ると展開されてとんでもない長さになるので脚注へ載せるに留めています。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?