GLSLの基礎的な書き方を確認する
- 頂点シェーダー
- フラグメントシェーダー
ここまで適当にGLSLを記述してきたが、ここで記述のルールを見直してみる。
void main () {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}
void main () {
gl_FragColor = vec4(1.0, 0.0, 0.0, 0.0);
}
「Shaderを描くための準備」でハローワールドとして上記のGLSLを書いた。この記述をもとに話を進める。
まず、最初のルールとして頂点シェーダー・フラグメントシェーダーともにmain
関数の中に処理を記述する必要がある。
void main {
//この中に処理を記述
//...
}
その次に頂点シェーダーではGLSLの組み込み変数であるgl_Position
に値を渡す。というより頂点シェーダーの役割が、このgl_Position
に値を渡すことと認識していてもとりあえずは問題なさそう。
void main {
// ...いろいろな処理
gl_Position = position;
}
一方、フラグメントシェーダーの役割はGLSLの組み込み変数であるgl_FragColor
に値を渡すことである(と認識していてとりあえずは問題なさそう)。
void main {
// ...いろいろな処理
gl_Position = color;
}
gl_Position
もgl_FragColor
もvec4型
、つまり4次元の浮動小数点ベクトルである。JavaScriptとは異なりGLSLは静的型付け言語なので、今扱っているデータの型が何なのかは常に意識する必要がある(JavaScriptでも型付けしないだけで意識しなくていいわけではない)。
ここで「WebGLProgram – three.js docs」を確認する。「前回の記事」でも軽く触れたが、Three.jsではビルドインでいくつかの変数が用意されている。ここまでShaderMaterialを使用してきたので、あまり意識してこなかったが、ビルドインで用意されている変数の前にuniform
やattribute
といった修飾子がついているのがわかる(RawShaderMaterialではこの辺りの変数を自分で宣言する必要がある)。
attribute
は頂点情報を受け取る変数を定義する修飾子であり、たとえばposition
はそれにあたる。頂点ごとに頂点情報を渡すので、attribute
で宣言された変数は頂点ごとに異なる値を受け取ることができる。対して、uniform
で宣言された変数はすべての頂点(フラグメントシェーダーならすべてのピクセル)で共通の値を受け取ることができる。modelMatrix
やviewMatrix
、projectionMatrix
などの変換行列はすべての頂点で同様の行列なので、uniform
で宣言されている。
頂点シェーダーからフラグメントシェーダーに値を渡す
さて、ここでvarying
修飾子についても触れておく。varying
修飾子は頂点シェーダーからフラグメントシェーダーに値を渡す際に使用できる修飾子である。百聞は一見にしかずということで、一旦実装してみる。
上記で何をやっているかというと、まず頂点シェーダーにおいて、varying
修飾子を使ってvColor
変数を宣言する。その後vColor
にvec4型の値を格納する(今回は青色)。ちなみにvColor
の先頭のvはvarying
のvであり、uniform
で宣言した時は先頭にuをつけることが慣習としてあるらしい。
// varyingで宣言
varying vec4 vColor;
void main () {
// 青色を設定
vColor = vec4(0.0, 0.0, 1.0, 1.0);
//...
}
次に、フラグメントシェーダーでも同様にvColor
の変数をvarying
で定義する。こうすることで頂点シェーダーからフラグメントシェーダーに値を渡すことができる。
// varyingで宣言、頂点シェーダーから値が渡ってくる
varying vec4 vColor;
void main () {
// vColor = vec4(0.0, 0.0, 1.0, 1.0) のはず
gl_FragColor = vec4(vColor);
}
試しに頂点シェーダーでvColor
の値をいろいろ変えてみると、オブジェクトの色が変わることが確認できる。
以上でここまでに記述してきたGLSLの基本的なルールの確認ができた。