シェーダの記述と基礎
GLSL について知る
その代わりに、いわゆるプログラマブルシェーダの一種であるシェーダ言語が実装されています。
それが GLSL ( OpenGL Shading Language )です。 GLSL は
OpenGL との親和性を持つシェーダ記述言語で、
C 言語ライクな独自の文法によって記述します。
シェーダの役割
まず、WebGL には
頂点シェーダ
フラグメントシェーダ
の二種類のシェーダがありました
いずれも、GLSL を使って記述することができます。
頂点シェーダとフラグメントシェーダは相互に関係性を持っていて、
どちらが欠けてもいけませんが
原則として先に呼ばれるのは頂点シェーダです。
頂点シェーダには、頂点に関する情報の全てを渡すことができます。
たとえば、
頂点の位置情報や、
頂点が持つ法線、
テクスチャ座標、
頂点の色など、
頂点に関する情報の全てをシェーダに渡すことが可能です。
ここで、どんな情報をシェーダに渡すのかは基本的に自由です。
ただし座標だけは必須
何も描画できなくなる
さて、頂点シェーダの次はフラグメントシェーダです。
頂点シェーダは文字通り頂点に関するあらゆる情報を受け取り、最終的に頂点をどのように処理するのかを決定します。
一方、フラグメントシェーダは画面にどんな色を出力すればいいのかを決めることができます。
そもそも、フラグメント( fragment )とは、直訳すると 断片 や 欠片 といった意味を持つ単語です。
要するに、画面上のピクセル(画面上の最も小さな断片ですね)それぞれに対して最終的に出力される色を操作してくれるわけです。
GLSL 記述の基礎
code:glsl
attribute vec3 position;
void main(void) {
gl_Position = position;
}
さて、ここで変な単語が出てきましたね。
実は、この attribute という修飾子を付けて宣言された変数(上記の場合なら position ですね)が、頂点の情報をシェーダ側で受け取る変数になります。
つまり、WebGL のプログラム側で position という名前を付け、あらかじめデータを仕込んでおきシェーダに渡すわけです。
たくさん存在する頂点は、それぞれ位置情報などが異なっていますよね。
そういった頂点ごとに異なるデータを受け取るための仕組みが attribute 修飾子付き変数なのです。
座標変換も GLSL で
頂点シェーダでは、頂点に関する処理を行なうと先ほどから書いていますが、頂点に関する処理と言えば忘れてはいけないのが座標変換ですね。
基本的にはどこまでを頂点シェーダに任せるのかは自由ですが、
WebGL のプログラム側でモデル・ビュー・プロジェクションのそれぞれの行列を生成して掛け合わせておき、
最終的に出来上がった座標変換行列を頂点シェーダに渡すのが(たぶん)一般的です。
さて、ここで考えてみてください。
この座標変換行列、どうやって頂点シェーダに渡せばいいのでしょうか。
この uniform 修飾子を使うと、全ての頂点に対して一律に処理される情報を渡すことが可能になります。
そのことを踏まえ、先ほどのシェーダの記述例を手直ししてみましょう。
code:glsl
attribute vec3 position;
uniform mat4 mvpMatrix;
void main(void) {
gl_Position = mvpMatrix * position;
}
一例
フラグメントシェーダとの連携
ちょっと長いテキストですが、まだもう少し続きます。
さて、 attribute と uniform の二つの修飾子については理解できたでしょうか。GLSL には、もう一つ、重要な修飾子があります。それが varying 修飾子付き変数です。
この varying 修飾子ですが、使い道は頂点シェーダとフラグメントシェーダの橋渡しです。たとえば、描画するモデルを半透明で表示したいと考えた場合、どういったプログラムを書くでしょうか。
いろいろな方法がありますが、一般的には、頂点に色情報を付加しておき、その透明度を変化させることでモデルを半透明にしたり、あるいは完全に透明にしたりします。このとき、頂点が持つ色の情報を、画面上の色を操作する役割を持つフラグメントシェーダに、どうにかして渡す必要が出てきますね。
そんなときにこそ、 varying が活躍します。それを踏まえて、再度シェーダの記述例を手直ししてみます。今度は、頂点シェーダだけではなくフラグメントシェーダの記述例も一緒に見てみます。
まずは頂点シェーダ。
code:glsl
attribute vec4 position;
attribute vec4 color;
uniform mat4 mvpMatrix;
varying vec4 vColor
void main(void) {
vColor = color;
gl_Position = mvpMatrix * position;
}
続いて、 varying 修飾子付きの変数 vColor を受け取るフラグメントシェーダ。
code:glsl
varying vec4 vColor;
void main(void)
{
gl_FragColor = vColor;
}
このように、頂点シェーダからフラグメントシェーダにデータを渡したい場合には varying 修飾子付きの変数を使います。そして、頂点シェーダでは必須だった gl_Position へのデータの代入と似たような形で、フラグメントシェーダにおいては gl_FragColor にデータを代入します。
頂点シェーダの場合とは違い、フラグメントシェーダでの gl_FragColor は絶対にデータを代入しなければならないもの(つまり必須)ではありません。ただ、普通は何かしらの色を出力することになるので、基本的には gl_FragColor が必要になります。
まとめ
かなり長いテキストになりました。内容もそれなりに濃かったと思うので、一度に理解するのは大変かもしれませんね。
ざっくりと、今回の内容をまとめてみます。
頂点シェーダとフラグメントシェーダは、いずれも GLSL を使って記述することができ、基本的には双方がセットになった形で使います。シェーダ内部には、必ず main 関数を用意し、そのなかにシェーダの行なう処理を記述します。さらに、WebGL 側からシェーダになにかしらのデータを渡したい場合には、特殊な修飾子付き変数を使うのでしたね。
頂点ごとに異なるデータを渡すために使うのが attribute 修飾子付き変数、頂点に対して一律で使われるデータを渡すために使うのが uniform 修飾子付き変数でした。
そして、頂点シェーダからフラグメントシェーダにデータを渡したい場合には varying 修飾子付きの変数を使います。
頂点シェーダでは、組み込みの変数である gl_Position へのデータの代入が必須であり、フラグメントシェーダにおいては、 gl_FragColor への代入が必須ではないものの、基本的には行うのが普通です。
GLSL に関しては、正直かなり内容が深くなるので、今回のテキストの内容ではまだまだ表層的な基本の部分しか解説していません。その辺に関してはテキストの進行状況に応じて、追々説明を加えていくことにしますので、まずは今回の内容をしっかり理解しておきましょう。
次回は、頂点バッファについて解説します。