はじめに
以下の「p5.js の createFilterShader()」を扱った 3つの記事に引き続き、また 「createFilterShader() を扱います(この createFilterShader() を使ったシェーダーをあれこれ試すことに、個人的にハマり中ですw)。
- p5.js の createFilterShader() を使ったフィルター用シェーダーのお試し - Qiita
- p5.js のフィルター用シェーダー「createFilterShader()」で座標情報を使った着色のお試し - Qiita
- p5.js のフィルター用シェーダー「createFilterShader()」で座標情報を使った着色のお試し 〜その2〜 - Qiita
今回は、以下の内容をやろうとした過程で、試した内容の 1つです。
(以下は、今回のオフスクリーンキャンバスの描画をシェーダーで使うという内容に加えて、カメラ画像を使った処理なども組み合わせています)
試す内容
今回試すのは、フィルター用シェーダー「createFilterShader()」を使った処理で、「メインキャンバスの描画内容をシェーダーに渡して処理するだけでなく、とオフスクリーンキャンバスの描画をまぜる」というものです。
「createFilterShader()」を使う場合、メインキャンバスの内容はデフォルトで利用できる形(シェーダーの中で tex0
という記載で取得できる形)ですが、オフスクリーンキャンバスもシェーダー内で利用できる形にします。
そして、そのようにしてシェーダーに渡した 2つのキャンバスの内容を、シェーダーの中で扱う処理を試していきます。
書いたプログラム
今回書いたプログラム全体は、以下の通りです。
let pg;
let s;
function setup() {
let fragSrc = `precision highp float;
varying vec2 vTexCoord;
uniform sampler2D tex0;
uniform sampler2D tex1;
void main() {
vec4 color = texture2D(tex0, vTexCoord);
vec4 color2 = texture2D(tex1, vTexCoord);
gl_FragColor = vec4(color.rgba + color2.rgba);
}`;
createCanvas(400, 300, WEBGL);
background(0);
noStroke();
fill(100, 50, 50);
rect(-50, -50, 200, 150);
pg = createGraphics(width, height);
pg.noStroke();
pg.fill(100, 150, 200);
pg.circle(120, 120, 190);
s = createFilterShader(fragSrc);
s.setUniform("tex1", pg);
filter(s);
}
ポイントになる部分
今回のポイントになる部分は、以下です。
s.setUniform("tex1", pg);
pg = createGraphics(width, height)
として作成したオフスクリーンキャンバスを、シェーダーに渡します。
シェーダーでそれを受けとる側は、以下とすれば OK です。
uniform sampler2D tex1;
あとは、何らかのシェーダー内での処理を実装して、メインキャンバスの内容とオフスクリーンキャンバスの内容を両方使えているかを確認します。
今回は以下のように、2つのキャンバスのピクセルの値を単純に加算する、というシンプルな内容で試しています。
void main() {
vec4 color = texture2D(tex0, vTexCoord);
vec4 color2 = texture2D(tex1, vTexCoord);
gl_FragColor = vec4(color.rgba + color2.rgba);
}
実行結果
上記を実行した結果は以下になりました。
2つのキャンバスで行った描画に関しては、以下のように、メインキャンバスとオフスクリーンキャンバスのそれぞれで、特定の色で図形を描画しています。
そして、それをシェーダーで処理した結果が上に示したとおりなのですが、 blendMode(ADD)
を使ったのと同じように加算合成を行った見た目になりました。
createCanvas(400, 300, WEBGL);
。。。
fill(100, 50, 50);
rect(-50, -50, 200, 150);
pg = createGraphics(width, height);
。。。
pg.fill(100, 150, 200);
pg.circle(120, 120, 190);