WebGLで画像を描画する(いろんなエフェクトをかけてみる

0 件のコメント
前回の続きですが、
gl.drawElementsとgl.drawArraysを使って画像を描画してエフェクトをかけちゃいます。
今回のサンプル画像も東京ドロンパです。

gl.drawElementsで色んなエフェクトをかける

下記サイトを参考にさせていただきました。
GLSLはこちらに記載しあるもので、時間経過と共にパラメータを更新し再描画している感じです。
http://ics-web.jp/lab/archives/5535

※ サンプルのために描画した下記サイトは、Google Chromeで閲覧下さい。
(Web Componentsやら使ってしまったので閲覧できる環境に制限が。。

・うずを巻く
http://experiment.itinao.net/webgl/blog/01_uzu_texture.html

・モザイク状態から徐々に鮮明になっていく
http://experiment.itinao.net/webgl/blog/02_mosaic_texture.html

・クレヨンで描いたようにボヤケている
http://experiment.itinao.net/webgl/blog/03_crayon_texture.html

・画像の色味が反転する
http://experiment.itinao.net/webgl/blog/04_reverse-color_texture.html

・画像の色が白黒になる
http://experiment.itinao.net/webgl/blog/05_sepia_texture.html

gl.drawArraysでエフェクトをつけてみる

下記を参考にさせていただきました。
こちらはスライドショーになってますが、下記のサンプルでは演出部分だけ抽出してみました。
肝は、canvasのcontext.getImageDataで色の情報を取得するとこです。

・画像がバラバラになったり、くっついたりする

以上です。
画像1つで、色んな見せ方ができるので面白い。。

0 件のコメント :

コメントを投稿

WebGLで画像を描画する

1 件のコメント
表題の通り、WebGLで画像を描画します。

描画するにはいくつか方法があると思いますが、
今回は
・gl.drawElementsを使った手法
・gl.drawArraysを使った手法
の2通りを試しました。

描画した結果はこちらです。
なるべくシンプルに書いています。
http://experiment.itinao.net/webgl/texture_draw_sample.html
(サンプル画像は、東京ドロンパです!

ハマりどころになるかと思うので先に書いておきますが、
画像のサイズ(縦と横)は2の乗数にしてください。
そうしないとエラーになって描画できません。
canvasでdrawImage(2の乗数で)して、canvas.toDataURLでリサイズしたデータを取るなどしても大丈夫です。

理由は、古いGPUが2の乗数のテクスチャしかサポートしていないから、などがあるみたいです。

gl.drawElementsを使った手法

おそらく一般的なもの。
コードを一部抜粋すると、このような感じ。
全文を見たい場合は、上記のサンプルコードを見てください!
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImg);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.bindTexture(gl.TEXTURE_2D, null);
textureImgは、HTMLのIMG要素です。
ここをVIDEO要素に変えると動画の一コマを描画することができます。

画像の描画に関する詳細は、こちらが参考になります。

動画の描画に関する詳細は、こちらが参考になります。

gl.drawArraysを使った手法

gl.POINTSを使って1つずつパーティクルを描画しています。

canvasのctx.getImageDataで画像データを取得し、その取得した画像データを使い、
ループの中で画像色・その位置を格納していってる感じです。
for (var i = 0; i < this.numParticles; i++) {
    var p = i;
    var cIndex = p * 3;
    var imageindexX = (rate * i % this.width) >> 0;
    var imageindexY = this.height - rate * (rate * i / this.width >> 0) >> 0;
    var pixIndex = (imageindexX + this.width * imageindexY) >> 0;
    vColor[cIndex] = this.imageArr[pixIndex * 4] / 255;
    vColor[cIndex + 1] = this.imageArr[pixIndex * 4 + 1] / 255;
    vColor[cIndex + 2] = this.imageArr[pixIndex * 4 + 2] / 255;
    var pIndex = p * 3;
    vPosition[pIndex] = ((rate * i % this.width) - this.width / 2) / posScale;
    vPosition[pIndex + 1] = (rate * (rate * i / this.width >> 0) - this.height / 2) / posScale;
    vPosition[pIndex + 2] = 0;
}

終わりに。

この他にも画像を描画する手法はあるかもしれませんが、
描画の方法によってできる演出が違うと思うので色々覚えておくと良いかもしれません!

1 件のコメント :

コメントを投稿

WebGLの描画メソッド・プリミティブについて。

0 件のコメント

WebGLって何だっけ?

ここ読んで下さい。

筆者もすごく参考になってますありがとうございます。

初めての方は、読んでって言われても..って感じだと思うので、
概要だけ掴んだ後は下記のサンプルを実際にコードを書きながら試してみるといいと思います。
「ポリゴンのレンダリング」http://wgld.org/d/webgl/w014.html
(WebGLで三角形を描画するだけでも数十行コードを書く必要があります。

今回の記事は、上記のポリゴンレンダリングでも使われている、描画メソッド[gl.drawArrays]などについて記載しています。
そして、その描画メソッドで指定されているプリミティブについて解説していきます。
(プリミティブとは、描画メソッドで使用する描画モードみたいなもの。詳細は下記で。

WebGLの描画メソッド

下記の種類があります。これらを実行することで、canvas上に描画されます。
大雑把に書いているので、「gl.drawArrays」と「gl.drawElements」は下記で補足します。

gl.drawArrays
⇒ 頂点情報を配列で正しい順番に格納し、その内容で描画するやつ。

gl.drawElements
⇒ 頂点情報と、頂点情報の何番目を使って描画するのかの情報を格納し、その内容で描画するやつ。
drawArraysとの違いは、頂点情報の順番を気にしないでいいこと。
頂点情報の何番目を使うかを指定するので、頂点情報が重複する場合はデータを省略できる。

gl.clear
⇒ gl.clearColorで指定した色で描画する。初期化用みたいな感じ。

gl.drawArrays

頂点情報を配列で正しい順番で格納し、その内容で描画するやつ。

使い方
gl.drawArraysメソッドを使用する前に、下記の手順を踏まないといけない。
1. gl.createBuffer()でVBO(頂点バッファ)を作成する
2. VBOをgl.bindBuffer()で、ターゲットのgl.ARRAY_BUFFERにバインドする
3. gl.bufferData()で、バッファに頂点データをセットする
4. gl.enableVertexAttribArray()で、汎用頂点属性配列を有効にする
5. gl.vertexAttribPointer()で、頂点シェーダに記述しているattributeをVBOのデータに接続する

引数について
gl.drawArrays(
    enum [レンダリングしたいプリミティブ], 
    int [頂点データの配列で最初に使用する要素のインデックス], 
    int [頂点の数])

enum [レンダリングしたいプリミティブ]
下記のどれかを指定します。(頂点をそれぞれ、右記で表現します。v0, v1, v2, v3...)

gl.LINES 
⇒ 線です。例えば、v0とv1, v2とv3, v4とv5を線で結んで描画されます。
(この場合は線3つできます。

gl.LINE_STRIP 
⇒ 線です。例えば、v0とv1とv2とv3とv4とv5を線で結んで描画されます。
(この場合は各頂点を結んで一筆書き。

gl.LINE_LOOP 
⇒ 線です。例えば、v0とv1とv2とv3とv4とv5を線で結んで描画されます。
(この場合は各頂点を結んで一筆書きですが、終点v5と始点v0も線で結びます。

gl.TRIANGLES 
⇒ 三角形です。例えば、v0とv1とv2, v3とv4とv5を線で結んで描画されます。
(この場合は頂点6つで三角形2つ描画されます。

gl.TRIANGLE_STRIP 
⇒ 三角形です。例えば、v0とv1とv2, v1とv2とv3, v2とv3とv4を線で結んで描画されます。
(この場合は頂点5つで三角形3つ描画されます。じぐざぐ。

gl.TRIANGLE_FAN 
⇒ 三角形です。例えば、v0とv1とv2, v0とv2とv3, v0とv3とv4を線で結んで描画されます。
(この場合は頂点5つで三角形3つ描画されます。扇型。

gl.POINTS 
⇒ 点です。指定した頂点を点で描画します。点の大きさは[gl_PointSize]で指定できます。

合わせて読みたい資料はこちらです。
とっても参考になります。図付きですし。

※ このように、描画する手段が色々あるので、最適な描画手段を選ぶ必要があります。
正方形を描画するにしても下記パターンがあり、
使用する頂点数が少なければ処理すべきデータ数が減り、メモリからGPUに転送するデータ量も減ります。
・gl.TRIANGLESで頂点を6つ指定するパターン
・gl.TRIANGLE_STRIPやgl.TRIANGLE_FANで頂点を4つ指定するパターンなど

・int [頂点データの配列で最初に使用する要素のインデックス]
頂点データの配列で最初に使用する要素のインデックスを指定する。

・int [頂点の数]
頂点の数を指定する。

gl.drawElements

頂点情報と、頂点情報の何番目を使って描画するのかの情報を格納し、その内容で描画するやつ。
drawArraysとの違いは、頂点情報の順番を気にしないでいいこと。
頂点情報の何番目を使うかを指定するので、頂点情報が重複する場合はデータを省略できる。

使い方
gl.drawElementsメソッドを使用する前に、
gl.drawArraysの手順に加えて、下記の手順を踏まないといけない。
1. gl.createBuffer()でIBO(インデックスバッファ)を作成する
2. IBOをgl.bindBuffer()で、ターゲットのgl.ELEMENT_ARRAY_BUFFERにバインドする
3. gl.bufferData()で、VBOを使用する順序を決定するインデックス配列をセットする

引数について
gl.drawElements(
    enum [レンダリングしたいプリミティブ], 
    int [インデックスバッファのインデックス数], 
    enum [インデックスバッファに格納されている要素の型], 
    int [頂点データの配列で最初に使用する要素のインデックス])

enum [レンダリングしたいプリミティブ]
gl.drawArraysと同様。

int [インデックスバッファのインデックス数]
インデックスバッファに何個のインデックスがあるかを指定する。

enum [インデックスバッファに格納されている要素の型]
gl.UNSIGNED_BYTE
gl.UNSIGNED_SHORT
このどちらかの型を指定する。

int [頂点データの配列で最初に使用する要素のインデックス]
インデックスバッファのインデックスの開始位置を指定する。

まとめ。

描画メソッド・プリミティブよって、描画する手段が異なります。
正方形を5個くらい描画する場合は
gl.drawElementsとgl.TRIANGLE_STRIPを使うと頂点データの数や使用するデータ用量も一番小さくなります。

ただ、データ容量を小さくするのも大事ですが、
描画するものによって、最適なデータの持ち方を選ぶことも大事らしいです。

今後も何かWebGL関連の記事を書きたいです。

以上。


0 件のコメント :

コメントを投稿