GLSL ES 2.0 で用いられる型修飾子(Type Qualifiers)、attribute、varying、uniform について
GLSL ES 2.0 シェーダ記述言語を読み始めると、最初に宣言されている変数にはデータ型以外のストレージ修飾子が付いているはずです。
attribute vec3 in_Position;
変数ストレージ修飾子
vec3 はデータ型、attribute は GLSL ES 2.0 の変数ストレージ修飾子です。※
※ attribute 及び varing は GLSL ES 3.0 以降から削除され、代替実装は in out となる。GM:S は GLSL ES 2.0 を扱っているため in out は利用しません。
参考(opengl.org):Type Qualifier
GLSL ES の変数スコープは「グローバル」と「ローカル」のみ。
attribute/varying/uniform は変数にグローバルスコープが必要な修飾子で、これらはメイン関数が実行される前に宣言が必要です。※
※ 厳密には「グローバルスコープが必要」というより、GPU メモリのグローバルプール(事前割り当て領域)へ配置する変数であることをコンパイラへ知らせる役割を持つ。データ型とは別に、メモリ(ストレージ)上のどこからデータが来ているのかを示す
ストレージ修飾子が付いた変数の値はシェーダ内で「定数=読み取り専用」として扱われます。
attribute 修飾子
attribute は頂点シェーダ(Vertex Shader)でのみ利用される修飾子です。
attribute vec3 in_Position; // (x,y,z) attribute vec3 in_Normal; // (x,y,z) attribute vec4 in_Colour; // (r,g,b,a) attribute vec2 in_TextureCoord; // (u,v)
attribute には組み込み変数は無いので、本来自由に変数名を指定できますが、GM:S では事前に定義済みなので、変数名を変えずにこのまま利用してください。※
※ GM:S がバインド処理を自動で行っている部分。本来 CPU / GPU 間で共通した名前を扱うための関連付けが手続きとして必要になるのだが、GM:S ではシェーダを簡単に利用させるためなのか、この手続きを隠蔽してある。その代わり手続き無しでいきなり attribute を利用できるという恩恵もある。
attribute 修飾子が付いた変数は値が定数となります。
頂点ごとに主アプリケーションから OpenGL ES API 経由で Vertex Shader へ情報が送信されます。つまり頂点情報を Vertex Shader で受け取るための型修飾子(Type Qualifier)として attribute は用いられます。
uniform 修飾子
uniform は主アプリケーション(GM:S で作成されたアプリケーション)から GPU シェーダへパラメータ送信が必要な際に利用される修飾子です。
uniform 修飾子が付いた変数は値が定数となります。
GM:S ユーザは uniform を利用する場合、CPU 側と GPU 側で変数名に関連付けを行うバインド処理を GML を使ったコードで記述する必要があります。※
※ GM:S ユーザは attribute の時には自由度を失う代わりに手続き無しで attribute を利用出来ましたが、uniform はカスタムシェーダの作成者が変数名を自由定義できる代わりにバインド処理が必須と成っています……が、本来この手続きが OpenGL API を利用するためには必須なのです。
Vertex および Fragment の両シェーダで uniform は利用できます。
varying 修飾子
Vertex Shader から Fragment Shader へパラメータを送信したい場合に利用される修飾子。
uniform は CPU から GPU 上のプログラムへ値を渡すため利用され、varying は GPU から GPU 上のプログラムへ値を渡す目的で利用されます。
修飾子 | データ送信元 | データ受信側 |
---|---|---|
uniform | CPU | GPU |
varying | GPU | GPU |
varying 修飾子が付いた変数は、値を受け取る Fragment 側で定数となります。
Vertex と Fragment は実行順に決まりがあって、Vertex が必ず先に実行されます。二つのシェーダは GPU 上で動くプログラムとして完全に独立しているため、名前空間などもそれぞれ別々になっています。異なったプログラム同士で値を送信するための手段として varying 修飾子付き変数を利用しますが、変数の名前を相互で関連付けする処理が必要と成ります。この処理のために varying 修飾子はまず Vertex から利用され、Fragment 側でも同じ名前/同じ型で varying 修飾子付きの変数として宣言された場合は、自動的に Vertex から送信された値が Fragment 側の varying 変数へ格納されます。そしてこの値は定数となります。
[divpage]