Top / 4K Procedural Gfx Monitor / 4KBプロシージャルGFX入門講座 2時限目

4KBプロシージャルGFX入門講座 2時限目

1時限目では、とりあえずさわって動かしてみることを中心にやってきた。
ここからは仕組みと動作を理解するステップに進む。

4kGfxMonは何をやっているのか?

2つのソースファイルはの役割は?

4kGfxMonでは vs.glsl と fs.glsl のソースファイルを変更することによって表示の変更がおこなえる。
vs.glsl はVertexProgramのソースファイルで、fs.glsl はFragmentProgramのソースファイルである。
GLSLになじみがない人にはなんのことかさっぱりな名前であるがあまり気にしなくて良い。
以下からは4kGfxMonに限定しての話をする。一般的なGLSLのシェーダプログラムの役割とは
少し違うので注意してほしい。

vs.glsl は fs.glsl の初期化の処理を書くところだと思っておけばよいだろう。
特に初期化を必要としないときは以下のように書いておけばよい。

-- vs.glsl --
// VertexProgram

void main()
{
    gl_Position = gl_Vertex;
}

fs.glsl は実際にグラフィックスを表示させるための処理を書くためのファイルだ。
gl_FragColor という特殊な変数に色の値を代入させることで、その色を出力できるわけだ。
青色 [ RGBA(0,0,1,1) ]を表示してみよう。vec4はベクトル型の定義だ。
gl_FragColorvec4型なのでvec4型の値を代入する。

-- fs.glsl --
// FragmentProgram

void main()
{
    gl_FragColor = vec4(0,0,1.0,1.0);
}

それぞれのファイルを保存し終わったら、以下のように表示されただろうか。

4kGfxMonは2つのシェーダプログラムをどう使っているのか?

次に、4kGfxMonが vs.glsl と fs.glsl のシェーダプログラムをどのようにつかっているのか見ていく。
4kGfxMonはウインドウの画面いっぱいに2枚の三角ポリゴン(1枚の四角ポリゴン)を描画している。
ワイヤーフレームで表示すると以下の赤線ような感じになるはずだ。

4kGfxMonではこの2枚の三角ポリゴンに対してVertexProgram (vs.glsl)と FragmentProgram (fs.glsl)を
セットしてOpenGLで描画している。

VertexProgramは頂点単位に実行されるもので、VertexProgram中のgl_Position に頂点座標を
代入することで頂点の位置を変更できる。特殊な変形をせずに画面いっぱいに描画する場合は
4kGfxMonの設定した値であるgl_Vertex をそのまま代入しておけばよい。
4kGfxMonのXY頂点座標は以下のようになっている。(Z座標は常に0である)

FragmentProgramは三角形が描画される領域の画面のピクセル単位で実行される。
各ピクセルで表示される色の値はgl_FragColorに代入された値になる。
FragmentProgramは各ピクセル共通の処理を記述する必要がある。つまり特定の部分のピクセルの処理を
書くことはできない。(この部分は慣れが必要!)
つまり、gl_FragColorに定数を代入すると、指定した一色が表示される。(青色を表示したサンプル)

各ピクセルごとに別々の処理をするためには、VertexProgramから座標値を渡してもらい、その値を元に
どのような処理をするのかを決めればよい。
VertexProgramから頂点座標の値を渡してもらい、それをそのまま出力するプログラムを考える。

-- vs.glsl --
// VertexProgram

varying vec4 p;

void main()
{
    gl_Position = gl_Vertex;
    p = gl_Vertex;
}

-- fs.glsl --
// FragmentProgram

varying vec4 p;

void main()
{
    gl_FragColor = p;
}

varying変数はVertexProgramからFragmentProgramへ値を補間して渡す変数である。
ここで p にgl_Vertex の4kGfxMonによって設定された頂点座標を渡しているが、
これが頂点間で補間されて各ピクセルごとに渡されることになる。

以下のような感じに表示される。
三角形頂点の座標系と一致していることがわかる。

つまり、まとめると・・・?


おおざっぱだけど、こんなイメージでいいかな。


グラデーションのサンプルの解説


さて、ここまで読み進めてきたら、グラデーションのサンプルの解説はすぐだろう。
sampleフォルダのgradationフォルダの中のソースファイルを見てみよう。

-- vs.glsl --
// VertexProgram

varying vec4 p;

void main()
{
    gl_Position = gl_Vertex;
    p = gl_Vertex;
}
-- fs.glsl --
// FragmentProgram
varying vec4 p;

void main()
{
    float g = p.y * 0.5 + 0.5;
    gl_FragColor = vec4(g,g,g,0);
    return;
}

vs.glsl では頂点座標をそのまま出力し、座標値をFragmentProgramに渡している。
fs.glsl ではVertexProgramから渡された座標値vec4 p;のY座標の値を利用し、
float gの値を計算している。
VertexProgramから渡されるpの値をそのままFragmentProgramで出力した時の
結果を考えながら、g = p.y * 0.5 + 0.5 の式を考えてみよう。
   p.y = -1 〜1
だったわけだから、
   g = 0 〜1
となることがわかる。
あとは、RGBAの色情報として出力するためにベクトル型のvec4(g,g,g,0) として、
gl_FragColorに代入している。
アルファ値が0となっているが、現在の4kGfxMonではアルファブレンド処理をしていないので
gl_FragColorのアルファ値がいくらであっても表示結果はアルファ1のときと同じになる。
最後のreturn;はあっても無くても良い。まぁ気分の問題。
これで結果的に上のグラデーションの結果になることが納得いただけただろうか。