GLSLシェーダによる簡単な描画プログラム
やっとホームページのタイトル通り、GLSLを使用したサンプルプログラムをアップすることができました。最初、何を紹介しようかと迷ったのですが、GLSLそのものよりも、GLSLを読み込みんでコンパイルする方法にしました。現在、OpenGL2.1以降でオフラインコンパイラも検討されていますが、通常、実行時にシェーダをコンパイルするからです。
GLSLのロードとコンパイル
シェーダプログラムにはバーテックスシェーダ(頂点シェーダともいいます)とフラグメントシェーダ(ピクセルシェーダともいいます)の2種類があり、二つセットで使用します。簡単な流れとしては、二つのシェーダプログラム(ソース)をそれぞれ読み込み、コンパイルし、それらをリンクして、プログラムオブジェクトを作成します。言葉で説明するよりも、プログラムを見た方が早いと思います。太字の部分がgl関数です。
int FUTL_LoadShader(
char *vtxShdName, /* バーテックスシェーダファイル */
char *frgShdName, /* フラグメントシェーダファイル */
GLuint *lpProg
)
{
GLuint vtxShader;
GLuint frgShader;
GLuint prog;
GLint linked;
/* シェーダオブジェクトの作成 */
vtxShader = glCreateShader(GL_VERTEX_SHADER);
frgShader = glCreateShader(GL_FRAGMENT_SHADER);
/* バーテックスシェーダのロードとコンパイル */
if (loadShader(vtxShader, vtxShdName) < 0)
return -1;
/* フラグメントシェーダのロードとコンパイル */
if (loadShader(frgShader, frgShdName) < 0)
return -1;
/* プログラムオブジェクトの作成 */
prog = glCreateProgram();
/* シェーダオブジェクトのシェーダプログラムへの登録 */
glAttachShader(prog, vtxShader);
glAttachShader(prog, frgShader);
/* シェーダオブジェクトの削除 */
glDeleteShader(vtxShader);
glDeleteShader(frgShader);
/* シェーダプログラムのリンク */
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &linked);
printProgramInfoLog(prog); /* リンクログの出力 */
if (linked == GL_FALSE)
return -1;
*lpProg = prog;
return 0;
}
/* シェーダープログラムをロードし、コンパイル */
static int loadShader(
GLuint shader,
char *name
)
{
: : 途中略 : :
/* シェーダオブジェクトにソースプログラムをセット */
glShaderSource(shader, 1, (GLchar **)&buf, &size);
/* シェーダのコンパイル */
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
printShaderInfoLog(shader); /* コンパイルログの出力 */
if (compiled == GL_FALSE)
return -1;
return 0;
}
英語になりますが、各関数の詳しい説明は、OpenGL2.1のマニュアルを見てください。上記のように、コンパイルやリンクをするので、エラーログを取得する関数もあります。例えば、コンパイルログは次のようにして取得します。
/* シェーダコンパイルエラーの出力 */
static void printShaderInfoLog(
GLuint shader
)
{
int logSize;
int length;
/* ログの長さは、最後のNULL文字も含む */
glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &logSize);
if (logSize > 1)
{
glGetShaderInfoLog(shader, MAX_SHADER_LOG_SIZE,
&length, s_logBuffer);
fprintf(stderr, "Shader Info Log\n%s\n", s_logBuffer);
}
}
GLSLシェーダプログラム
簡単なシェーダプログラムとして、正規化された法線(x, y, z)をRGBカラーに変換して描画するシェーダを作成しました。法線は-1.0~1.0の範囲であるため、(r, g, b) = 0.5 *(x, y, z) + 0.5として計算します。バーテックスシェーダは、次のようになります。
void main(void)
{
// 位置座標を座標変換
gl_Position = ftransform();
// 法線から色を決定
gl_FrontColor.rgb = 0.5 * gl_Normal.xyz + 0.5;
gl_FrontColor.a = 1.0;
}
GLSLでは、バーテックスシェーダの中のgl_FrontColorが、頂点色としてフラグメントシェーダのgl_Colorに渡される仕組みになっています。今回、フラグメントシェーダはその色をそのまま出力するようにしています。そのままと言っても、三角形内部のピクセルは渡された頂点色で補間されます。
void main (void)
{
gl_FragColor = gl_Color;
}
OpenGLを利用するプログラム側は、次のglUseProgramをコールした後、頂点配列や頂点バッファを用いて、gl描画関数(glDrawArrayやglDrawElements等)を呼び出せば、シェーダに頂点や法線が渡っていきます。
/* シェーダプログラムの適用 */
glUseProgram(shdProg);
/* トーラスの描画 */
if (drawVBO)
{
triangles = FUTL_DrawTorusVBO(count);
vtxStr = vtxBufStr;
}
シェーダを使わずに、これまでの通りの固定パイプライン描画を行う場合は、glUseProgram(0)としてコールすればOKです。
これで説明は終わりです。サンプルプログラムを動かせば、次のような絵が描画されると思います。ドーナツはシェーダで、文字はこれまで通りの描画です。

偶然ですが、個人的には割と綺麗な色になって気に入っています。食べたい色ではないですけどね。
最新の7件
OpenGL
電子工作
玄箱HG
- ClamAVのアップデート
- Smartyも入れてみる
- etchでPHP4->PHP5
- etchでのSamba設定
- etchでのメール設定
- 玄箱HGのetch化
- Webdruidでログ解析
- PEARも入れてみる
- 玄箱WEBのUTF-8化
- phpMyAdminでMySQL
- postmasterの変更
- ウィルスメール対策
- SPAMメール対策
- メールサーバ(IMAP)
- メールサーバ(Postfix)
- 猫にXOOPS
- PHPも入れてみる
- MySQLを入れてみる
- Subversion導入
- WebDav導入
- Apacheのrewrite機能
- Apacheディレクトリ設定
- Apache1.3->2.0
- ddclientの設定
- 静かな玄箱
- ユーザ追加