XNA を使ってシェーダを書いている昨今。OpenGL でも同じことをしようとしたのだけど、それ以前の段階のカメラの設定で詰まってしまって、昨日はふてくされて寝てしまいました。
寝て起きたら、昨日の OpenGL のプログラムで何が悪かったのか分かってすっきり。double を渡すべき所で、「45」と int 表記にしていたのが問題だった。OpenGL でこれに引っかかるのは2度目。OpenGL で定数をいじるときには、一箇所いじるごとに動作を確認しなきゃだね。
んで、GLSL でシェーダプログラミングのお勉強。当然かもだけど、シェーダは1回のレンダリングで1種類しか使えないのね。ちょっと残念。
ちなみに Mac OS X の Cocoa では、
NSString *filepath = [[NSBundle mainBundle] pathForResource:@"シェーダのソースファイル名" ofType:@"拡張子"];
NSData *sourceData = [NSData dataWithContentsOfFile:filepath];
としてソース文字列を読み込み、
GLsizei sourceLength = [sourceData length];
GLchar *source = malloc(sourceLength);
[sourceData getBytes:source];
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); // ピクセルシェーダなら GL_FRAGMENT_SHADER
glShaderSource(shaderID, 1, (const GLchar **)&source, &sourceLength);
glCompileShader(shaderID);
という感じでコンパイル済みのソースを作成して(ここの手順は、頂点シェーダでもピクセルシェーダ(=フラグメントシェーダ)でも同じ。基本的には両方とも用意するものだろうけど、↓の glAttachShader() で片方だけ指定しないでおくと、そちらには固定シェーダが使われる)、
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
としてそれを GPU にセットできるようにして、
glUseProgram(shaderProgram);
として GPU にセットすれば使える(片方ずつ別々の場所でセットすることはできないらしい)。
↓ サンプルプログラムはこちら。このプログラム、drawRect:(いわゆる display() 関数)の中でマテリアル指定はしていません。

サンプルプログラム:GLShaderSample.zip (30KB)
↓ シェーダを切り替えられるようにしたバージョンはこちら。
サンプルプログラム:GLShaderSample2.zip (34KB)
頂点シェーダとピクセルシェーダでの処理しか考えられていない OpenGL よりも、生成された 2D のレンダリング結果をさらにぼかして使ったりするためのレンダリングターゲットのサポートが始めから用意されている DirectX の方が、シェーダを使わなきゃいけないレベルでいろいろやる分には簡単そう。もちろん OpenGL でも同じことは一応できるようにはなってるんだけど。
コメントを書く