GLSL†
OpenGL Shading Language
GLSLプログラミング†
GLSLプログラミングを行うためには実行プラットフォームが少なくとも,
GL_ARB_vertex_shader,GL_ARB_fragment_shader拡張に対応している必要がある.
OpenGL拡張の対応を調べたり,拡張を使えるようにするにはGLEWを用いるのが一番簡単である
(参照:GLEWについて).
GLSLシェーダはいくつかのOpenGL命令を用いてアプリケーション実行時にロード,コンパイル,リンクされる.
シェーダのコンパイル†
GLSLシェーダをOpenGLアプリケーション中でロード,コンパイルする手順は以下.
- glCreateShader()でシェーダオブジェクトを生成する.
GLuint glCreateShader(GLenum shaderType);
shaderTypeにはGL_VERTEX_SHADER, GL_GEOMETRY_SHADER, GL_FRAGMENT_SHADERのいずれかを指定する.
- シェーダオブジェクトにシェーダソースコード(文字列)をセットする.
void glShaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length);
shaderはシェーダオブジェクト(glCreateShaderの返値),countは文字列の数,stringがソースコードを格納した文字列配列,
lengthはstringの長さを示し,NULLを指定すればstringがnull terminatedであることを示す.
- シェーダをコンパイルする.
void glCompileShader(GLuint shader);
これらの手順を関数にまとめたものを以下に示す.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| |
inline GLuint CompileGLSLShader(GLenum target, const char* shader)
{
GLuint object = glCreateShader(target);
if(!object) return 0;
glShaderSource(object, 1, &shader, NULL);
glCompileShader(object);
GLint compiled = 0;
glGetShaderiv(object, GL_COMPILE_STATUS, &compiled);
if(!compiled){
char temp[256] = "";
glGetShaderInfoLog( object, 256, NULL, temp);
fprintf(stderr, " Compile failed:\n%s\n", temp);
glDeleteShader(object);
return 0;
}
return object;
}
|
CompileGLSLShader()にはソースコード文字列を引数として渡さなければならない.
ファイル(*.vs,*.gs,*.fsなど)に記述したシェーダコードを読み込んで文字列化する関数の例を以下に示す.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| |
inline GLuint CompileGLSLShaderFromFile(GLenum target, const char* fn)
{
FILE *fp;
fp = fopen(fn, "rb");
if(fp == NULL) return 0;
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *text = new char[size+1];
fread(text, size, 1, fp);
text[size] = '\0';
fclose(fp);
printf("Compile %s\n", fn);
GLuint object = CompileGLSLShader(target, text);
delete [] text;
return object;
}
|
ファイルから読み込むほかに,以下のようにしてソースコード中に直接記述する方法もある.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| | #define RXSTR(A) #A
const char phong_vs[] = RXSTR(
varying vec3 vPos;
varying vec3 vNrm;
void main(void)
{
vPos = (gl_ModelViewMatrix*gl_Vertex).xyz;
vNrm = gl_NormalMatrix*gl_Normal;
gl_Position = ftransform();
}
);
|
シェーダのリンク†
必要なシェーダ(バーテックス,ジオメトリ,フラグメント)をコンパイル後,それらをリンクして,
1つのGLSLプログラムにまとめる.
- glCreateProgram()でGLSLプログラムオブジェクトを生成.
GLuint glCreateProgram(void);
ここで生成したプログラムオブジェクトはGLSLでの描画切替にも用いるので,OpenGL描画関数にこの変数を渡せるようにしておくこと.
- glAttachShader()でシェーダオブジェクトをプログラムオブジェクトに関連付ける.
void glAttachShader(GLuint program, GLuint shader);
programはプログラムオブジェクト(glCreateProgramの返値),shaderは関連付けたいシェーダオブジェクトを指定する.
- glLinkProgram()でプログラムをリンクする.
void glLinkProgram(GLuint program);
リンクがうまくいったかどうかは,glGetProgramiv()にプログラムオブジェクトとGL_LINK_STATUSを渡すことで調べることができる.
プログラムのリンクを行う関数の例を以下に示す.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| |
inline GLuint LinkGLSLProgram(GLuint vs, GLuint fs)
{
GLuint program = glCreateProgram();
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
GLint charsWritten, infoLogLength;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength);
char * infoLog = new char[infoLogLength];
glGetProgramInfoLog(program, infoLogLength, &charsWritten, infoLog);
printf(infoLog);
delete [] infoLog;
GLint linkSucceed = GL_FALSE;
glGetProgramiv(program, GL_LINK_STATUS, &linkSucceed);
if(linkSucceed == GL_FALSE){
glDeleteProgram(program);
return 0;
}
return program;
}
|
シェーダソースファイルからコンパイル,リンクを行う関数の例を以下に示す.
返値はrxGLSL型の変数となっており,シェーダファイル名,プログラムオブジェクトなどを格納する構造体である.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| | struct rxGLSL
{
string VertProg; string GeomProg; string FragProg; string Name; GLuint Prog; };
inline rxGLSL CreateGLSLFromFile(const string &vs, const string &fs, const string &name)
{
rxGLSL glsl;
glsl.VertProg = vs;
glsl.FragProg = fs;
glsl.Name = name;
GLuint v, f;
v = CompileGLSLShaderFromFile(GL_VERTEX_SHADER, vs.c_str());
f = CompileGLSLShaderFromFile(GL_FRAGMENT_SHADER, fs.c_str());
glsl.Prog = LinkGLSLProgram(v, f);
return glsl;
}
|
シェーダによる描画†
上記の関数を用いてアプリケーション初期時に以下のようにシェーダプログラムをビルドした後,
rxGLSL g_GLSL = CreateGLSLFromFile("phong.vs", "phong.fs", "phong");
描画時にglUseProgram()を用いてGLSL描画に切り替える.
void glUseProgram(GLuint program);
1
2
3
4
5
6
| | glUseProgram(g_GLSL.Prog);
glUniform3f(glGetUniformLocation(g_GLSL.Prog, "eyePosition"), eye_pos[0], eye_pos[1], eye_pos[2]);
glutSolidTeapot(0.5);
glUseProgram(0);
|
glUniform*()はGLSLシェーダのuniform変数に値を渡す命令であり,
その種類は下記参照.
glUniform†
シェーダ内のuniform変数に値を渡すのに用いるOpenGLの命令.
変数,定数を用いた受け渡し†
- 浮動小数点数
void glUniform1f(GLint location, GLfloat v0);
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
- 整数
void glUniform1i(GLint location, GLint v0);
void glUniform2i(GLint location, GLint v0, GLint v1);
void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2);
void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
locationにglGetUniformLocationで取得した変数の位置,v0-v3に受け渡す値を指定する.
f接尾辞の場合はfloat,vec2,vec3,vec4とその配列に,
i接尾辞の場合はint,ivec2,ivec3,ivec4とその配列に値を渡すのに用いられる.
配列を用いた受け渡し†
- 浮動小数点数
void glUniform1fv(GLint location, GLsizei count, const GLfloat *value);
void glUniform2fv(GLint location, GLsizei count, const GLfloat *value);
void glUniform3fv(GLint location, GLsizei count, const GLfloat *value);
void glUniform4fv(GLint location, GLsizei count, const GLfloat *value);
- 整数
void glUniform1iv(GLint location, GLsizei count, const GLint *value);
void glUniform2iv(GLint location, GLsizei count, const GLint *value);
void glUniform3iv(GLint location, GLsizei count, const GLint *value);
void glUniform4iv(GLint location, GLsizei count, const GLint *value);
locationにglGetUniformLocationで取得した変数の位置,countは修正する要素の数(GLSL側のuniform変数が配列でないならば1でなければならない),
valueは要素数countの配列のポインタでこの配列の中身が渡される.
行列の値の受け渡し†
void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
void glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
上の3つは正方行列用でそれぞれ,2x2,3x3,4x4行列の値(要素数4,9,16)を書き換える.
locationはglGetUniformLocationで取得した変数の位置,countは修正する要素の数(GLSL側のuniform変数が配列でないならば1でなければならない),
transposeにGL_TRUEを指定した場合,行列の要素はrow majorで格納され,GL_FALSEを指定すればcolumn majorで格納される.
valueは要素数countの配列のポインタでこの配列の中身が渡される.
ベクトル型†
型名 | 説明 |
vec2,vec3,vec4 | 2D,3D,4D浮動小数点数ベクトル(float) |
ivec2,ivec3,ivec4 | 2D,3D,4D整数ベクトル(int) |
bvec2,bvec3,bvec4 | 2D,3D,4Dブール値ベクトル(bool) |
行列型†
型名 | 説明 |
mat2,mat3,mat4 | 2x2,3x3,4x4行列(float) |
テクスチャ型†
型名 | 説明 |
sampler1D,sampler2D,sampler3D | 1D,2D,3Dテクスチャ(GL_TEXTURE_1D,2D,3Dに対応) |
samplerCube | キューブマップテクスチャ(TEXTURE_CUBE_MAPに対応) |
sampler1Dshadow,sampler2Dshadow | 1D,2Dデプステクスチャ(GL_TEXTURE_1D,2DでGL_DEPTH_COMPONENTのものに対応) |
sampler2DRect | 2のn乗以外の大きさのテクスチャ(GL_TEXTURE_RECTANGLEに対応,要 GL_ARB_texture_rectangle) |
sampler2DRectShadow | 2のn乗以外の大きさのデプステクスチャ(要 GL_ARB_texture_rectangle) |
sampler1DArray, sampler2DArray | 1D,2Dテクスチャ配列(TEXTURE_1D,2D_ARRAYに対応,要 GL_EXT_texture_array) |
sampler1DArrayShadow,sampler2DArrayShadow | 1D,2Dデプステクスチャ配列(要 GL_EXT_texture_array) |
ビルトイン変数†
定数(attribute)†
変数名 | 型 | 説明 |
gl_Vertex | vec4 | 頂点座標 |
gl_Normal | vec3 | 頂点法線 |
gl_Color | vec4 | 頂点色 |
gl_MultiTexCoord* | vec4 | テクスチャ*のテクスチャ座標 |
|
gl_ModelViewMatrix | mat4 | モデルビュー行列 |
gl_ProjectionMatrix | mat4 | プロジェクション行列 |
gl_ModelViewProjectionMatrix | mat4 | モデルビューとプロジェクション行列の積 |
gl_NormalMatrix | mat3 | モデルビュー行列の逆行列(法線変換用) |
変数(uniform)†
シェーダー間のデータ受け渡しに使える.
変数名 | 型 | 説明 |
gl_FrontColor | vec4 | 表面の色 |
gl_BackColor | vec4 | 背面の色 |
gl_TexCoord[] | vec4 | テクスチャ座標 |
|
gl_Position | vec4 | 頂点位置(頂点シェーダのみ) |
gl_FragColor | vec4 | フレームバッファに書き込まれる色(フラグメントシェーダのみ) |
gl_FragDepth | float | フレームバッファに書き込まれるデプス値(フラグメントシェーダのみ) |
TIPS†
キャスト†
warning C7503: OpenGL does not allow C-style casts
Cとはキャストのやり方が違っているので,例えば,
i = (int)x;
ではなく,
i = int(x);
とする.
|