18
16

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 5 years have passed since last update.

WebGLAdvent Calendar 2014

Day 21

Filtersを使ってGLSLを楽しく学んじゃおう!

Last updated at Posted at 2014-12-21

Advent Calendar 21日目の記事です。

すでに散々書いていて今さら感もありますが、今回はいくつかの記事で紹介してきたFiltersについてさらに詳しく紹介したいと思います。

Filters

この記事の対象はWebGLに興味があってGLSLをこれから学習したい人

すでにがっつりGLSLを書いている人はFiltersで遊んでみてくださいw
ここでは主に、どういう点が学習に向いているか、どう使うのかについて書いています。

Filtersとは

Filtersは、PCブラウザからGLSLを記述し、それをリアルタイムに同期を取ってiPhone側のフィルターとしてプレビューできるまったく新しいタイプのフィルターアプリです。

なにがいいのか

ずばり、GLSLを楽しく学べる点です。
GLSLは(個人的には)学習するのが大変な言語のひとつだと思っています。
理由としては3Dの基本的な知識はもちろん、OpenGL(WebGL)を理解していないとなりません。

OpenGL(WebGL)に関しては色々な言語で記述することができるので、言語的な学習コストはあまりないかもしれませんが、素で書こうと思うと手順がとても冗長で、単純なポリゴンを描くまでもだいぶ時間がかかってしまいます。

そしてOpenGL(WebGL)のプログラムが書けたとして、GLSLはそこからやっとスタート、となります。
さらにはGLSLの場合、頂点シェーダとフラグメントシェーダと言われるふたつのシェーダを書かないとなりません。

つまり、セットアップだけでお腹いっぱいになること必至です。
こうしたことからも、GLSLは「Hallo world」がとてもしづらいものだと思います。

FiltersではすぐにGLSLを書き始められる

以上のように、GLSLを書こうと思ってもそれをセットアップするまでの手順が多いだけでなく、OpenGL(WebGL)も同時に学習しないとなりません。

しかし、Filtersはカメラのフィルターアプリなのでなにもしなくてもカメラの映像が、リアルタイムに変化するテクスチャとして表示されるよう準備されています。つまりOpenGL(WebGL)の知識は必要ないわけです。
(もちろん、GLSLを学ぼうという人がOpenGLをやらないわけにはいかないでしょうが)

加えて、他にたくさん投稿されているフィルターをForkしたり(あるいはGLSL Sandboxから引用したり!)して、徐々に変化をつけながらGLSLを学んでいくことが出来ます。

これが、自分が思うFiltersでのGLSL学習のメリットです。

GLSLが書けるサービスは他にないの?

もちろんFiltersでなくても、前述したGLSL SandboxのようにGLSLを気軽に書けるサービスはあります。
ですが、どんな模様を描くかはプログラム次第です。(要はがんばらないと画面になにも出てこない)

でもFiltersは前述した通り、カメラのフィルターアプリなのでデフォルトでカメラの映像が表示されます。
さらに静止画ではなく今撮っている映像がリアルタイムに表示されるので、画面の変化も感じやすいのがいいところです。

[本題] 使ってみる

だいぶ前置きが長くなりましたが、Filtersの機能を見て行きましょう。
Filtersアプリをインストールして起動すると以下のような画面になります。

[[画像入れる]]

  • PICK UP は投稿されたものが一覧で並んでいます。
  • RANKING には人気のフィルターが並びます。
  • FAVORITE は自分がお気に入りに入れたフィルターリストです。

Forkしてみる

ざっとフィルターを眺めているとたまに気になるフィルターが見つかると思います。
どうやって作っているのか気になるフィルターや、普通に使ってみたいフィルター、あるいは見ていたフィルター同士を組み合わせて面白いのが作れそうだ、と思わせてくれるフィルターなどなど。

気になったフィルターがあったら Fork してみましょう。
Forkするには、気になるフィルターを開き、タブの中の「Fork」ボタンを押下してForkします。
Forkすると以下のようにQRコードを撮影する画面になるので、PCブラウザで編集ページ (http://filters.kayac.com/edit) を開きます。

[[QRコード撮影画面キャプチャ]]

編集ページを開くとQRコードが表示されるので、先ほどアプリ側で表示されたQRコード撮影カメラでQRコードを撮影します。

すると以下のような編集画面が開かれ、アプリ側の画面も編集中を示す画面に切り替わります。
これでアプリとPCブラウザが同期されました。

Editor

左側のエディタでGLSLを編集してみましょう。
リアルタイムに同期が取られているので、エディタ側でコードを編集するとまもなくアプリ側の画面も変わるはずです。
さらに画面右側もプレビューになっていて、エディタで編集した内容が反映されるようになっています。
ここはWebGLが使われていて、記述したGLSLがそのまま適用されています。

ピンチイン・ピンチアウト、タッチ位置などに対応

Filtersの面白いもうひとつの点として、 ピンチイン・ピンチアウト、タッチ位置の捕捉 があります。
使いたいフィルターを起動して画面をピンチインさせたりすると、それがデータとしてGLSLに送られてきます。
それをなにかしらの係数として扱ってやれば、画面を触ると変化が起こるフィルターが作れる、というわけです。

ちなみにシステムから送られてくるパラメータはエディタの下に記載があります。
具体的には以下です。

param

それぞれ以下の意味になります。

変数名 意味
vec2 iScreen いわゆるUV座標
vec2 iResolution 画面サイズ。iPhoneのカメラの画角がそのままピクセルとして渡される
float iTime フィルターを開始してからの経過時間。sinなどで使うと変化を出せる
vec2 iPosition タッチ位置。(0, 0)〜(1, 1)で値が渡ってくる
float iSize ピンチイン・ピンチアウトの現在のスケール値。デフォルトは1。
sampler2D iCamera カメラ映像のテクスチャ

実際に作ってみる

今回の記事のために、簡単なフィルター(と呼べるか怪しいw)を作ってみました。
画面をタッチしてドラッグするとカメラの映像が繰り返しになって移動する、というものです。

↓こんな感じ(動画
moving-filter

まずは新規作成

フィルターを新規作成すると以下のコードが記述されています。

void main() {
	vec2 uv = iScreen;
	
	vec4 color = texture2D(iCamera, uv);
	
	gl_FragColor = vec4(color.rgb, 1.0);
}

とてもシンプルですね。これだけで、カメラからの映像をそのまま表示するものになっています。

いちおうGLSLにあまり馴染みがない人に簡単に説明しておくと、GLSLはC言語由来の言語になっており、基本的な構文などはC言語と非常に似ています。
また、今回いじっているGLSLのコードは フラグメントシェーダ と呼ばれ、主に画面にピクセルをレンダリングする計算をするシェーダになっています。

画面を真っ青にしてみる

試しに以下のようにコードを書き換えてみると画面が真っ青になります。

vec4 blue = vec4(0.0, 0.0, 1.0, 1.0);

gl_FragColor = blue;

gl_FragColorというのはフラグメントシェーダで計算された色を最終的な画面の色として決定する、特殊な組み込み変数です。(なのでGLSLはreturn文ではなくgl_FragColor変数に色を設定します)

そしてその上の行で定義しているのが「青色」の意味になります。
GLSLでは基本的に、値を0.0〜±1.0の範囲で扱います。
vec4は4要素のベクトルで、つまりはRGBAを意味しています。

上記コードは0, 0, 1, 1となり、つまり不透明な青になる、というわけですね。
だから画面が真っ青になったわけです。

カメラからの映像を取得する

さて、それでは最初のコードに戻って見てみましょう。

void main() {
	vec2 uv = iScreen;
	
	vec4 color = texture2D(iCamera, uv);
	
	gl_FragColor = vec4(color.rgb, 1.0);
}

なにかをcolorという変数に取り出してから、gl_FragColorに設定しています。

texture2Dはビルトイン関数でGLSLで定義されている関数です。
なんとなくなにをしているか分かると思いますが、要はカメラテクスチャ(画像)から、該当箇所(uv)のピクセルの色(通称テクセル)を抜き出してくれる関数です。

そして最後に、その抜き出した色のrgb成分、つまり4要素のうち最初の3つを取り出し、アルファを1.0に設定した色をgl_FragColorに設定しているわけです。
まぁたんにカメラの映像を出力しているだけですねw

余談

余談ですが、GLSLのフラグメントシェーダの役割は、画面内の 全ピクセル に対してどんな色が画面に出力されるべきか、を計算することです。
例えば、1920 x 1080のディスプレイであれば 2,073,600ピクセル もの計算を行う必要があるわけです。
だからグラフィック処理は重いんですね。

そしてこの1ピクセル1ピクセルにどんな色を出力すべきかを決定しているのがgl_FragColorで指定された色、というわけです。(実際にはアルファテストやブレンドなどさらに複雑な処理がありますが)

閑話休題

さて、ではどうしたらフィルター効果をつけれるでしょうか。
例えばtexture2Dの取得位置を変えてやれば上下左右反転、なんかはできそうですよね。
あるいは適当に生成した色とテクセルの色を合成してgl_FragColorに設定してやれば色味を変えるフィルターの出来上がりです。

実際のところ、よく目にするフィルターの中身はとてもシンプルなことが結構あったりします。

さっきの真っ青にしたコードと、デフォルトのを組み合わせたらどうなるでしょうか。

void main() {
	vec2 uv = iScreen;
	
	vec4 blue  = vec4(0.0, 0.0, 1.0, 1.0);	
	vec4 color = texture2D(iCamera, uv);
	vec4 dstColor = vec4(color.rgb, 1.0) + blue;
	
	gl_FragColor = dstColor;
}

最初のコードにblueを足しただけのものです。
これを実行すると以下のような、微妙に青みがかった映像になりました。

blue-filter

作ったフィルター

今回作ったフィルターも全然大したことはやっていません。
コードを見てもらうと、デフォルトのものと行数は一緒です。
というか十数文字くらいしか違いがありませんw

void main()
{
	vec2 uv = mod(iScreen - iPosition, 1.0);
  
	vec4 texColor = texture2D(iCamera, uv);
	
	gl_FragColor = texColor;
}

変更点は以下の部分のみ。

diff
vec2 uv = mod(iScreen - iPosition, 1.0)

iPositionはシステムから送られてくるタッチ位置ですね。
それをiScreenから引いています。つまりテクセルを取り出す位置をその分ずらしている、というわけです。

そしてそれをmod関数で計算した結果をuv変数に入れています。
mod関数は「モジュロ」と呼ばれ、要は余りを計算する関数です。
(GLSLは0.0〜±1.0で計算されるため、1.0の余りを求め、0.0〜±1.0の間になるようにしています)

このテクニックはタイル上にするフィルターなどにも使われ、比較的よく使われているものだと思います。

あとは、その求めたuvを使って、カメラテクスチャからテクセルを取り出してやれば今回のように移動するフィルターの完成となります。

Filters紹介ムービー

最後に。
Filtersの紹介ムービーを見ると実際に動かしているところが見られるので、興味がある人は見てみてください。

Filters PV

18
16
2

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
18
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?