まずは挑戦してみよう
シェーダを自分でコーディングするなんて……
きっとお難しいんでしょ……
と、お思いの奥様方。そんなことはないんです。コツをつかめば意外と楽しめます。当連載では、シェーダというものに対して抱かれてしまいがちな、漠然とした 難しそう感 を払拭すべく、簡単なシェーダの記述とその基本について解説したいと思います。
想定する読者
当連載では、シェーダってなんか難しそう……とか、シェーダプログラミング始めてみたいけど……とか、なんとなく興味を持ってるけどシェーダを記述したことがない方を読者に想定しています。
たとえば Unity などのツール、あるいはマインクラフトのようなゲーム、またはモデリングソフトなどでもシェーダを自分で記述することができるような世の中です。きっとシェーダに触れた経験は無駄にはならないでしょう。
すぐに業務で活かすとか、そういう壮大な話はさておいてまずは気軽にシェーダに触れてみましょう。
難しい 3D の数学的知識はとりあえず要りません。もちろん難しいことをやろうとする場合は話が変わってきますが、当連載ではそのあたりの知識は求めません。ちょっとくらい、三角関数とかは出てきますがそんなに難しくないですから安心してください。
対象のシェーダ記述言語は GLSL
「シェーダ」という言葉には非常に広い意味が含まれるので、世の中にはシェーダといってもいろいろなものが存在しています。また、それを記述するための専用の言語にも、いくつか種類があったりして非常に初心者には敷居が高いのかなと思います。
当連載では GLSL というシェーダ専用言語を用います。
GLSL は 昨今話題の WebGL でも採用されているので、特別な開発環境の準備などをしなくても、ブラウザとテキストエディタさえあれば簡単に始められます。
また、当連載では著者自作の GLSL editor というオンラインでシェーダが記述できるエディタを使いますので、もはやブラウザとネット環境さえあればシェーダが書けます。気軽ですね。
さっそく始めてみよう
それでは早速始めてみましょう。
ほんとに簡単ですよ。
まずは、先ほど紹介したオンラインシェーダエディタ、 GLSL editor のページを開いてみて下さい。以下のような画面が出てくると思います。
簡単に説明すると、右側のコードペインにモリモリ GLSL を書いて、Windows なら Ctrl+s、Mac なら Command+s を入力すると、シェーダが走るという仕組みです。
シェーダによって描き出された映像は、左側の白い矩形をスクリーンとして映し出されます。
- コードを書く
- 保存(Ctrl+s) → 即実行
という感じです。簡単ですね。
尚、レンダリングを止めたい場合は Esc キーを入力するとすぐに止まります。
最初の GLSL コード
先ほどのオンラインエディタ。ページを開いたときにデフォルトでシェーダのコードが書かれていると思います。
パッと見では、これが何をするものなのかわけわからんちんだと思いますが、試しに Ctrl+s (Mac なら Command+s)するとどうなるでしょうか。
ちょっとやってみてください。
どうですか?
なにやら怪しげな、しかし非常に美しい模様が描き出されたと思います。
このアニメーションする模様が、シェーダだけで描かれているんですね。なんとも不思議ですね。
しかし、この謎の模様(ジュリア集合と呼ばれるものですね)について解説するよりも、もっと簡素なコードで試してみましょう。
オンラインエディタにもともと書かれているコードを全削除してから、以下のコードを全文コピーペーストして再度実行してみてください。ただし、アニメーションしないのでわかりにくいですが、放置するとずっと実行されっぱなしになっちゃうので、ここに戻ってくる前に Esc キーを押してループを止めておいてくださいね。
precision mediump float;
uniform float t; // time
uniform vec2 r; // resolution
void main(void){
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
さて、結果はどうなりましたか?
うまくいっていれば、以下のようになったはずです。
スクリーンが綺麗に緑色になっちゃいましたね。
これはいったいどういうことなんでしょう。
GLSL editor お決まりの冒頭三行の意味
さて、コピーアンドペーストしたシェーダのコードには、いったいどんな意味があったのでしょうか。
まずは、先ほどのコードの上から三行分を見てみましょう。
precision mediump float;
uniform float t; // time
uniform vec2 r; // resolution
結論から言うと、この三行のコードのうち、一行目のコードの意味については 現時点では知る必要なし! です。
いずれ、連載を続けていくなかで説明するときは来ると思いますが、とりあえず気にしなくて大丈夫です。
では二行目以降にはどんな意味があるんでしょうか。
実は、二行目と三行目に注目してみると、いずれの行頭にも同じキーワードが使われているのがわかると思います。ここで使われている uniform
というキーワードは、シェーダに外部から送られてくるパラメータ を書くときに使われるものです。
コメントでも書かれているとおり、float
型の変数 t
には、時間の経過がリアルタイムに送られてくるようになっています。シェーダ内でアニメーションを行いたいときには、この変数を利用することで時間の経過と共に描画される内容を変更しながらレンダリングすることが可能になります。
三行目には vec2
という謎のキーワードが出てきます。
これは、浮動小数点数を扱うことができる float
型のデータを、二つまとめてパッキングした変数の型です。ほかにも vec3
、vec4
の合計三種類の vec 型があって、vec3
であれば float
が三つパッキングされています。同様に vec4
であれば四つですね。
各要素にアクセスするには、xyzw
や rgba
といった要素名を使うことになっています。
たとえば次のようにピリオドを使って記述してやればいいですね。
vec4 v;
float a = v.x;
float b = v.y;
float c = v.z;
float d = v.w;
uniform
としてシェーダに送られてくる vec2
型の変数 r
には、コメントにもある通り resolution という意味のデータが入ってきます。これはわかりやすく言うと スクリーンのサイズ です。
GLSL editor では、スクリーン部分のサイズが 512px 四方の正方形になっています。ですから、この vec2
型の変数 r
には、横 x 縦 のスクリーンサイズが入っており、javascript 風に書くと Array(512.0, 512.0)
のような感じでデータがあらかじめ格納されています。
float a = r.x;
というようなコードを書くと、変数 a
には 512.0 という浮動小数点数のデータが代入されるというわけです。
さて、ここまでを踏まえてみると、先ほどの冒頭の三行には次のような意味があったことがわかります。
precision mediump float; // ← とりあえず気にしない
uniform float t; // ← 経過時間(秒単位)
uniform vec2 r; // ← スクリーンサイズ(512.0, 512.0)
この三行分のコードは、GLSL editor では 基本的に手を入れることはない 決まり文句です。
各自が修正して創意工夫を凝らすのは、定型三行コードの下にある main 関数の中身ということになります。
main 関数の中で使われるもの
さて、それでは先ほどのコピーしたコードを再度掲載してみます。
precision mediump float;
uniform float t; // time
uniform vec2 r; // resolution
void main(void){
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
冒頭の、三行のお決まり定型コードの下には main という関数が定義されています。
この main 関数が、シェーダ内で実行される処理そのものです。ここに記述したコードが実行されると同時に動き出します。
関数の中では、gl_FragColor
という部分に、なにかを代入しているのがわかると思います。
gl_FragColor
は vec4
型の構造を持つデータで、最終的に画面に出力される色を決定する GLSL の組み込み変数です。この gl_FragColor
に指定した色が、スクリーン上にそのまま出るわけです。
それを踏まえつつ先ほどのコードを見てみると、vec4
という記述と共に、データを代入している様子がわかると思います。画面上の色は、いわゆる CSS などと同様に RGBA の四つの要素で表されます。
ですから、上記のような記述をすると vec4(0.0, 1.0, 0.0, 1.0)
はそのまま RGBA として解釈され、スクリーン上には不透明度 100 % の緑として出力されます。色の範囲を 0.0 ~ 1.0 の範囲で表現するということさえ理解できていれば、それほど難しくないと思います。
さて、ここまでわかったら、スクリーンに描かれる色を変えるのは簡単ですね。
たとえば次のように記述すると、スクリーン上は何色になるでしょうか。
gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
ちょっと考えればすぐわかりますね。
この場合は、画面の色は紫というかピンク色っぽくなります。
GLSL シェーダコーディングの基本は色を出すこと
ここまで見てきてわかったと思いますが、シェーダを記述することとは、言い換えれば 画面上に出る色を決定すること なんですね。
途中、どのような複雑な計算をしようとも、最終的にどんな色を出力するのかを決めることが最終的な目的なのです。そういう風に考えてみると、要は色を決めればいいだけなんだ! と気楽に考えることができるのではないでしょうか。
※もちろんシェーダには他の役割もありますが今はとりあえずそういう解釈でいいと思います
連載の第一回となる今回はここまで。
次回以降、より具体的にシェーダを記述するための基礎を解説していく予定ですのでお楽しみに!
次回:[連載]やってみれば超簡単! WebGL と GLSL で始める、はじめてのシェーダコーディング(2) - Qiita