はじめに
今回の内容は、p5.js の createFilterShader() のお試しです。
createFilterShader() とは?
createFilterShader() がどういうものかという話は、以下の公式リファレンスで説明されています。
●reference | createFilterShader()
https://p5js.org/reference/#/p5/createFilterShader
冒頭の説明を見てみると、「using only a fragment shader, as a convenience method for creating image effects.」と書いてあります。
その説明内容は、「フラグメントシェーダーを利用するだけで、シェーダーの処理が行えて、画像エフェクトを使うのに便利」というものです。
p5.js でのシェーダーを使う場合の準備
「フラグメントシェーダーを利用するだけで...」という部分は、少し補足すると「バーテックスシェーダーの準備が不要」ということになります。
p5.js でシェーダーを利用する場合、createShader() を使う方法があり、そしてこの createShader() を使う場合は、バーテックスシェーダーとフラグメントシェーダーを準備する必要がありました。
●reference | createShader()
https://p5js.org/reference/#/p5/createShader
createFilterShader() を使う場合は、バーテックスシェーダーが準備済みの状態となるようで、そのため自前で用意するのはフラグメントシェーダーだけとなるようです。
試してみた内容
createFilterShader() を使った描画
ここで createFilterShader() を使った描画を先に掲載してみます。
以下の動画では、4つの図形が動いており、その中の図形 2つの色が途中で変化しています。
これは、画面の中のピクセルに対する処理をシェーダーを用いて行っているためです。
処理内容は、画面内のピクセルで RGB の G(緑)の値が一定以上の大きさの場合、色の変更を行っています。この変更処理の ON/OFF は、ユーザーの操作で実行するようにしています。そして、以下の動画では、その ON/OFF の切り替えを何度か行っています。
実装内容
実際に実装した内容は以下のとおりです。
const colorList = ["#3f616c", "#6baec5", "#9dcebc", "#e0e8a4"];
let isF = true;
function setup() {
createCanvas(500, 400);
noStroke();
// ------------------------
let fragSrc = `precision highp float;
varying vec2 vTexCoord;
uniform sampler2D tex0;
void main() {
vec4 color = texture2D(tex0, vTexCoord);
if (color.g > 0.8) {
gl_FragColor = vec4(color.r = 0.85, color.g= 0.9, color.b = 0.95, 1.0);
} else {
gl_FragColor = vec4(color);
}
}`;
s = createFilterShader(fragSrc);
// ------------------------
}
function draw() {
background(0);
// 円1つ目
const x = width * 0.5 + width * 0.22 * cos(frameCount / 25),
y = height * 0.5 + height * 0.25 * sin(frameCount / 36);
fill(colorList[0]);
circle(x, y, height * 0.22);
// 矩形
const x2 = width * 0.6,
y2 = height * 0.3 + height * 0.2 * sin(frameCount / 27);
fill(colorList[1]);
rect(x2, y2, height * 0.22);
// 円2つ目(大きい方)
push();
translate(width / 2, height / 2);
rotate(frameCount / 30);
fill(colorList[2]);
circle(50, 50, height * 0.33);
pop();
// 三角形
push();
translate(width / 2, height / 2);
rotate(frameCount / 40);
translate(width * 0.1, 0);
fill(colorList[3]);
triangle(0, 0, height * 0.35, 0, 0, height * 0.35);
pop();
if (isF) filter(s);
}
function mouseClicked() {
isF = !isF;
}
上記の中で、createFilterShader() に関わる部分は、主に // ------------------------
で囲まれたところです。
その中でも、処理のメインの内容は以下です。
この処理では、キャンバス上の色を、デフォルトで準備された「vTexCoord と tex0」を用いて取得しています。
その取得した色を元に、 if (color.g > 0.8)
の条件にマッチしたピクセルの色を gl_FragColor = vec4(color.r = 0.85, color.g= 0.9, color.b = 0.95, 1.0);
という特定の色にしています。
void main() {
vec4 color = texture2D(tex0, vTexCoord);
if (color.g > 0.8) {
gl_FragColor = vec4(color.r = 0.85, color.g= 0.9, color.b = 0.95, 1.0);
} else {
gl_FragColor = vec4(color);
}
}`;
なお、シェーダーを適用する部分は、 draw() の中の filter(s)
の部分です。
このようにして、createFilterShader() を使ったシェーダーの適用を行いました。
補足
デフォルトで用意されるバーテックスシェーダーについて
バーテックスシェーダーはデフォルトで用意されると書きました。
それに関連して利用できる変数は、公式リファレンスに書かれた以下となります。