1
1

p5.js のフィルター用シェーダー「createFilterShader()」で三角関数を使ったノイズの WebGL 2.0/GLSL ES 3.0 バージョン(The Book of Shadersより)

Last updated at Posted at 2024-09-01

この記事では、以下の「The Book of Shaders」の Noise のページに掲載されている、三角関数を使ったノイズ画像に関連した内容です。

●The Book of Shaders: Noise
 https://thebookofshaders.com/11/

その内容を、WebGL 2.0/GLSL ES 3.0 の書き方にした上で、さらに p5.js のフィルター用シェーダー「createFilterShader()」で扱える形にします。

元の内容

元の内容は以下の通りです。

image.png

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

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

// 2D Noise based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
float noise (in vec2 st) {
    vec2 i = floor(st);
    vec2 f = fract(st);

    // Four corners in 2D of a tile
    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));

    // Smooth Interpolation

    // Cubic Hermine Curve.  Same as SmoothStep()
    vec2 u = f*f*(3.0-2.0*f);
    // u = smoothstep(0.,1.,f);

    // Mix 4 coorners percentages
    return mix(a, b, u.x) +
            (c - a)* u.y * (1.0 - u.x) +
            (d - b) * u.x * u.y;
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;

    // Scale the coordinate system to see
    // some noise in action
    vec2 pos = vec2(st*5.0);

    // Use the noise function
    float n = noise(pos);

    gl_FragColor = vec4(vec3(n), 1.0);
}

これを、まずは WebGL 2.0/GLSL ES 3.0 に対応した内容にします。

●WebGL1からWebGL2への移行
 https://webgl2fundamentals.org/webgl/lessons/ja/webgl1-to-webgl2.html

書きかえていく

WebGL 2.0/GLSL ES 3.0 対応

WebGL 2.0/GLSL ES 3.0 対応は、例えば冒頭の部分を以下のようにします。

image.png

また、フラグメントシェーダーの入出力の部分を、以下の書き方にする必要があります。

image.png

p5.js の「createFilterShader()」に関連した対応

次に p5.js の「createFilterShader()」に関連した対応です。

元のシェーダーのコードでの以下の部分は、少し違う書き方になります。

    vec2 st = gl_FragCoord.xy/u_resolution.xy;

以下の公式の「createFilterShader()」に関する説明で、上記に該当するのが vTexCoord です。

●createFilterShader
 https://p5js.org/reference/p5/createFilterShader/

image.png

vTexCoord は 0 から 1 の値になるよう正規化されたものであるため、 vec2 st = vTexCoord; とするだけで、書きかえは OK です。

書きかえ後のコード

書きかえ後のコードは以下のとおりです。

以下では、p5.js の createFilterShader() を呼び出す処理も含めています。

let s;

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

  s = createFilterShader(fragSrc);
}

function draw() {
  background(0);

  filter(s);
}

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

in vec2 vTexCoord;
out vec4 outColor;

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

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);
}`;

上記を実行した結果は、以下のとおりです。

シェーダーを使ったノイズ画像生成ができていることが確認できました。

余談

上記のシェーダーを使ったノイズ画像の生成について、さらに少し手を加えると、seed を設定できるようにできたりアニメーションさせられたりということもできます。

例えば、以下のような見た目のものを作ることが可能です。

1
1
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
1
1