イメージシンセシス トップページ

GLSLの演習:基本的な処理

サンプルプログラム glsl1 を以下のように変更して実行してみる. 順次,プログラム中の赤字の箇所を変更する. 青字は,その時点で,すでに変更済みの箇所である.

(1) シェーダを使わない(OpenGLアプリケーションのみ)の場合の動作を確認する.

OpenGLアプリケーション(main.cpp)内で glUseProgram(0); としてシェーダプログラムの適用を無効化することにより,バーテックスシェーダ simple.vert とフラグメントシェーダ simple.frag が動作しなくなる.
OpenGLアプリケーション内で4角形ポリゴンの4つの頂点に与えた赤色,緑色,青色,黄色がポリゴン内部で補間される.

(2) バーテックスシェーダとフラグメントシェーダの動作を確認する.

バーテックスシェーダ simple.vert 内の【実験1】,【実験2】,【実験3】について,それぞれ,行頭のコメント記号 // を外して実行する. バーテックスシェーダ(simple.vert)では,頂点の色を vec4 型の変数 gl_FrontColor に与えることができる. ここで,vec4 型は4次元ベクトルをあらわす変数の型であり,色を扱う場合には R(Red),G(Green),B(Blue),A(Alpha) の4つの要素を与える. それぞれの色要素は 0.0 から 1.0 の範囲の値をとる.

フラグメントシェーダ(simple.frag)では,バーテックスシェーダから(ラスタライザを介して)渡された色を vec4 型の変数 gl_Color によって参照できる(gl_FrontColor ではない). 出力画像に表示する色を vec4 型の変数 gl_FragColor に代入する. ただし,前述したように,図形の重なりによって,1つのピクセルに対して複数のフラグメントが存在する場合には,最終的に最も視点に近い(つまり,最も奥行き値(デプス値,Z値)が小さな)フラグメントが表示される.

(3) バーテックスシェーダでユーザ定義変数(uniform変数)を使う.

バーテックスシェーダ simple.vert 内の【実験1】,【実験2】について,それぞれ,行頭のコメント記号 // を外して実行する. それぞれの場合で,マウスによって4角形ポリゴンを回転させ,ポリゴンの色を観察する. OpenGLアプリケーション(main.cpp)からバーテックスシェーダ(simple.vert)に頂点ごとに変化しない値を渡したい場合には uniform 変数を用いる. このとき,まず,バーテックスシェーダ内で uniform 変数を定義する. 上記のプログラムでは,simple.vert 内で
 uniform float valVert;
を定義している. この変数に main.cpp から値を渡したい場合,直接的に値を代入することはできない. 上記の main.cpp 内で行っているように,関数 glGetUniformLocation と glUniform1f を用いた手続きによって代入を行う. 上記の main.cpp 内では,まず,通常の変数に
 float valVertC = 0.0;
のように値 0.0 を代入しておき,その手続きに従って simple.vert 内の uniform 変数 valVert にその値を代入している.

上記の simple.vert 内では,【実験1】,【実験2】として,main.cpp から uniform 変数 valVert に渡された値 0.0 を用いた処理を行っている. 具体的には,4角形ポリゴンの各頂点の x 座標の値を valVert の値 0.0 と比較して,各頂点に異なる色を与えている. つまり,頂点の x 座標が負であれば赤色,非負(0,または,正)であれば緑色を与えている. ただし,実験1と実験2では,頂点の x 座標の種類が異なる. プログラムを実行し,マウスによって4角形ポリゴンを左回りに90度だけ回転した結果を下図に示す.

@
A
B
C
説明図
実験1
実験2

【実験1】では,頂点の座標値として vec4 型の変数であるモデリング座標値 gl_Vertex を用いている. これは main.cpp 内で4角形ポリゴンを定義する際に用いたモデリング座標系における座標値であり,4角形ポリゴンに貼りついた座標系であると考えてよい. 上の説明図では,灰色であらわした4角形ポリゴンに貼りついた [ xv, yv ] である. この実験では,モデリング座標値 gl_Vertex.x,つまり,4角形ポリゴンに貼りついた x 座標値 xv によって各頂点に色が与えられるので,常に,頂点 V00 と V01 に赤色,頂点 V10 と V11 に緑色が与えられる. よって,4角形ポリゴンを回転しても,4角形ポリゴン上の色が固定されている.

【実験2】では,頂点の座標値として vec4 型の変数であるクリッピング座標値 gl_Position を用いている. これはウィンドウに貼りついた座標系であり,上の説明図では [ xp, yp ] であらわされ,その範囲は -1 ≤ xp ≤ 1,-1 ≤ yp ≤ 1 である. この実験では,クリッピング座標値 gl_Position.x,つまり,ウィンドウに貼りついた x 座標値 xp によって各頂点に色が与えられるので,上図では,@とAでは頂点 V00 と V01 に赤色,頂点 V10 と V11 に緑色が与えられるが,A→Bの過程で頂点 V00 と V11 の x 座標値 xp の正負が変化するため,BとCでは頂点 V01 と V11 に赤色,頂点 V00 と V10 に緑色が与えられる. つまり,4角形ポリゴンの回転による頂点の位置の変化により,4角形ポリゴン上の色が変化する.

(4) フラグメントシェーダでユーザ定義変数(uniform変数)を使う.

以下のプログラムを実行し,マウスによって4角形ポリゴンを回転させ,ポリゴンの色を観察する. OpenGLアプリケーション(main.cpp)からフラグメントシェーダ(simple.frag)にフラグメント(ピクセル)ごとに変化しない値を渡したい場合には uniform 変数を用いる. その方法はバーテックスシェーダ(simple.vert)の場合と同様である. 上記のプログラムでは,simple.frag 内で
 uniform float valFrag;
を定義している. main.cpp 内では,通常の変数に
 float valFragC = 150.0;
のように値 150.0 を代入しておき,バーテックスシェーダの場合と同様の手続きに従って simple.frag 内の uniform 変数 valFrag にその値を代入している.

プログラムを実行し,マウスによって4角形ポリゴンを左回りに90度だけ回転した結果を下図に示す. 上記の simple.frag 内では,main.cpp から uniform 変数 valFrag に渡された値 150.0 を用いた処理を行っている. 具体的には,4角形ポリゴンの各フラグメントの x 座標の値を valFrag の値 150.0 と比較して,各フラグメントに異なる色を与えている. ここでは,フラグメントの座標値として vec4 型の変数であるフラグメント(ピクセル)座標値 gl_FragCoord を用いている. これはウィンドウ内のフラグメント(ピクセル)の位置をあらわす座標系であり,下の説明図では [ xf, yf ] であらわされる. ウィンドウ内のピクセル数が Nx × Ny の場合,その範囲は 0 ≤ xf ≤ Nx,0 ≤ yf ≤ Ny である. フラグメント(ピクセル)の位置が [ 0, 0 ] の場合に [ xf, yf ] = [ 0.5, 0.5 ],[ Nx-1, Ny-1 ] の場合に [ xf, yf ] = [ Nx-0.5, Ny-0.5 ] となる. このプログラムでは,フラグメント座標値 gl_FragCoord.x,つまり,ウィンドウ内のフラグメントの x 座標値 xf が valFrag = 150.0 より小さければ黄色,それ以上であれば紫色が与えられる. このプログラムでは,ウィンドウのサイズを指定していないため,ウィンドウ内のピクセル数はデフォルトの 300 × 300 である. よって,4角形ポリゴンの回転に関わらず,4角形ポリゴンの領域のうち,ウィンドウ内で左半分に含まれる領域は黄色,右半分に含まれる領域は紫色となる. なお,(3)の実験では,バーテックスシェーダ(simple.vert)内で4角形ポリゴンの各頂点に色を与えたため,ウィンドウに表示される4角形ポリゴン内の色は4つの頂点の色を(ラスタライザを介して)滑らかに補間した色となる. 一方,この(4)の実験では,フラグメントシェーダ(simple.frag)内で各フラグメント(ピクセル)に色を与えるため,上記のフラグメント座標値の条件により,ウィンドウに表示される4角形ポリゴン内の色がはっきりと分かれる.

@
A
B
C
説明図
実験

(5) バーテックスシェーダとフラグメントシェーダでユーザ定義変数(varying変数)を使う.

バーテックスシェーダ simple.vert 内の【実験1】,【実験2】について,それぞれ,行頭のコメント記号 // を外して実行する. それぞれの場合で,マウスによって4角形ポリゴンを回転させ,ポリゴンの色を観察する. 頂点ごとに異なる値について,バーテックスシェーダ(simple.vert)からフラグメントシェーダ(simple.frag)に値を渡したい場合には varying 変数を用いる. バーテックスシェーダが持つ頂点ごとの値がスクリーン上でラスタライズ(補間)されてフラグメント(ピクセル)ごとの値に変換され,フラグメントシェーダに渡される. この場合,バーテックスシェーダとフラグメントシェーダで同じ型と名前の varying 変数を定義する. 上記のプログラムでは,simple.vert と simple.frag で
 varying float addxy;
を定義している. simple.vert 内で各頂点に与える値を変数 addxy に代入し,その値がラスタライズされてフラグメントごとの値に変換され,simple.frag 内の変数 addxy に渡される.

上記の simple.vert 内では,【実験1】,【実験2】として,頂点の x, y 座標値から
 addxy = ( ( x + y ) + 2.0 ) / 4.0;
のように値を求めて変数 addxy に代入している. それぞれの座標値の範囲を -1 ≤ x ≤ 1,-1 ≤ y ≤ 1 とすると,この範囲の四隅における変数 addxy の値は以下のようになる.

y
1
0.5
1.0
-1
0.0
0.5
-1
1
x

このプログラムの基本的な処理は(4)の実験と全く同じである. すなわち,OpenGLアプリケーション(main.cpp)からフラグメントシェーダ(simple.frag)にフラグメント(ピクセル)ごとに変化しない値を uniform 変数を用いて渡し,その値を利用してウィンドウ内のフラグメント(ピクセル)の位置に応じて4角形ポリゴンに色を与えている. 具体的には,simple.frag 内の処理として,フラグメント座標値 gl_FragCoord.x と uniform 変数 valFrag = 150.0 の値を比較することで,4角形ポリゴンの回転に関わらず,4角形ポリゴンの領域のうち,ウィンドウ内で左半分に含まれる領域には黄色,右半分に含まれる領域には紫色が与えられる. (5)の実験では,この黄色と紫色に対して,変数 addxy の値を乗算した色を表示する. 変数 addxy の値は,色の明暗を決める役割を果たす. 上の表からわかるように,頂点の x, y 座標値に応じて,[ x, y ] = [ -1, -1 ] に近い位置では暗くなり,[ x, y ] = [ 1, 1 ] に近い位置では明るくなる. ただし,実験1と実験2では,(3)の実験と同様に,頂点の x, y 座標の種類が異なる. プログラムを実行し,マウスによって4角形ポリゴンを左回りに90度だけ回転した結果を下図に示す.

@
A
B
C
説明図
実験1
実験2

【実験1】では,頂点の座標値 [ x, y ] としてモデリング座標値 gl_Vertex を用いている. これは4角形ポリゴンに貼りついた座標系であり,上の説明図中の [ xv, yv ] である. また,main.cpp 内で4角形ポリゴンを定義する際に各頂点に与えているモデリング座標値から,その範囲は -1 ≤ xv ≤ 1,-1 ≤ yv ≤ 1 である. この実験では,モデリング座標値 gl_Vertex.x,gl_Vertex.y,つまり,4角形ポリゴンに貼りついた座標値 [ xv, yv ] によって各頂点に変数 addxy による明暗が与えられるので,常に,頂点 V00 に近い位置では暗くなり,V11 に近い位置では明るくなる. よって,4角形ポリゴンを回転しても,4角形ポリゴン上の明暗が固定されている.

【実験2】では,頂点の座標値 [ x, y ] としてクリッピング座標値 gl_Position を用いている. これはウィンドウに貼りついた座標系であり,上の説明図中の [ xp, yp ] であり,その範囲は -1 ≤ xp ≤ 1,-1 ≤ yp ≤ 1 である. この実験では,クリッピング座標値 gl_Position.x,gl_Position.y,つまり,ウィンドウに貼りついた座標値 [ xp, yp ] によって各頂点に変数 addxy による明暗が与えられるので,ウィンドウの左下に近い頂点には暗い値,右上に近い頂点には明るい値が与えられる. つまり,4角形ポリゴンの回転による頂点の位置の変化により,4角形ポリゴン上の明暗が変化する.