Edit
GLSLについて

OpenGL, OpenGLES, WebGLなどに採用されているシェーダー言語。Vertex Shader, Fragment Shaderなど複数のシェーダーをパイプラインを通じて実行させ、最終出力を得る。OpenGLES側等で、glCreateShaderでシェーダー登録用の番号(シェーダーID)を作成し、その番号と実際のシェーダーソーステキストを glShaderSourceで指定することで、OpenGLESに読み込まれ、glCompileShaderを使って、内部の実行可能なコードを作っておくことで、いつでもこの、シェーダーIDを使ってシェーダーの利用設定ができる。通常はアプリの初期処理ですべて読み込んでおく場合が多いだろう。

このシェーダー登録の上限はメモリの許す限りであり、ゲームなどのシェーダーを多用するアプリでは、2,000個近くのシェーダーが登録されることもある。

その後、各種シェーダーの組み合わせをプログラムIDという名前で登録して、そのプログラムを利用という指定方法になる。glCreateProgramによって、プログラムIDを作成し、glAttachShaderで、そのプログラムIDと利用するシェーダーIDを登録する。この関数は登録するシェーダー数だけ実行される(Vertex とFragmentだけなら2回)。その後、glLinkProgramで各種シェーダープログラムが接続されこのプログラムIDが動作できる。(通常ここでも内部でコンパイルされるので、コンパイルエラーを吐く、エラーの取得方法は別ページを参照の事)またこのプログラム作成も上限はメモリの許す限りであるため、初期処理など最初に作成しておくのが良いだろう。(コンパイルには多少のオーバーヘッドが予想されるため)

実際に利用する場合には、このプログラムIDを利用する為 glUseProgram という関数を利用することで、この登録されたプログラムIDが描画の段階で動作する。通常は1つのオブジェクトに1つのプログラムという使い方も少なくなく。その場合にはこのプログラムIDをオブジェクト描画ごとに切り替えることになる。

Edit
基本的なシェーダーのコンパイル手順

シェーダーのコンパイルは、プログラム実行時にコンパイルされるため、ソース中でソースを指定してコンパイルを行うように指示をする。

順番もどり値OpenGLの関数概要
1GLuint (shader番号)glCreateShader(GLenum type)バーテックスシェーダとフラグメントシェーダのシェーダオブジェクトを作成する。typeは、GL_VERTEX_SHADER と、GL_FRAGMENT_SHADERなどが選択できる
2voidglShaderSource(GLuint shader, GLsizei count, const GLchar ** shaderSource, const GLint * length)作成したそれぞれのシェーダオブジェクトに対してソースプログラムを読み込む。lengthはNULLでもOK
3voidglCompileShader(GLuint shader)読み込んだソースプログラムをコンパイルします
4voidglDeleteShader(GLuint shader)シェーダオブジェクトを削除する

Edit
エラーなどの判定

順番もどり値OpenGLの関数概要
1voidglGetShaderiv(GLuint shader, GLenum type, GLint * status)コンパイラの結果などを戻す関数。type には、GL_COMPILE_STATUS, GL_LINK_STATUSなどを設定する。statusに結果が戻ってくる

Edit
基本的なシェーダーの設定

順番もどり値OpenGLの関数概要
1GLuintglCreateProgram()プログラムオブジェクトを作成する
2glAttachShader()プログラムオブジェクトに対してシェーダオブジェクトを登録する
3voidglBindAttribLocation(GLuint program, GLuint index, const GLchar * name)※LinkProgramより前に行う必要がある
4voidglLinkProgram(GLuint program)シェーダプログラムをリンクします
5glUseProgram()シェーダプログラムを適用する
6voidglDetachShader(GLuint program, GLuint shader)プログラムオブジェクトからシェーダオブジェクトのリンクを解除する。※DeleteShaderの前に行う事

Edit
OpenGL ESとGLSL ESのバージョン対応表

OpenGL ESGLSL ES追加された機能
1.0未対応
1.1未対応バッファオブジェクト、自動ミップマップ生成、拡張テクスチャ処理、頂点スキニング機能、ユーザー定義クリッププレーン、拡張ポイントスプライト、ポイントスプライト配列、静的・動的状態クエリー、テクスチャ描画、新しいコア追加、プロファイル拡張
2.01.0プログラマブルシェーダー対応(Vertex, Fragmentの2つ)
3.03.0マルチレンダーターゲット、マルチサンプルアンチエイリアス(MSAA)、Uniform Block、Transform Feedbackなど多数
3.13.1コンピュートシェーダーなど
3.23.2ジオメトリシェーダー、テッセレーションシェーダー、テクスチャ圧縮技術ASTC、など多数

Edit
コーディングの基本

シェーダーコードは基本的にC言語と同じ記述方法で記載する。よって基本は main 関数にそのコードを記載する形となり、通常はグローバル変数や、シェーダー変数などは main より前に記述されることが多い。独自関数や引数、戻り値などの基本仕様はすべてC言語と同じとなる。

Edit
シェーダーバージョンの指定

GLSL ESのバージョンを指定するには、下記の行をシェーダーソースの先頭に記入する。

バージョン指定方法
1.0<バージョン指定無し>
3.0#version 300 es

Edit
Extension利用時

extension指定されている機能を利用したい場合には、#extension を利用できる。

<例>

#extension GL_ARB_explicit_attrib_location : enable

Edit
C言語との違いについて

概ねC言語の記述通りではあるが、GLSLシェーダー独特の修飾子が存在する。

修飾子概要
in, out, inoutC++で言う所の参照渡し。他の関数で定義変数を、他の関数から簡単に修正できる。ある意味危険ではあるが、高速化には役に立つ。in は更新のみ、out は参照のみ、inout は読み書きできる変数として指定できる。
highp, mediump, lowp精度修飾子。C言語のように short, long, long long などの表現ではなく、highp int のように整数型をより高精度にする。というような表記になる。詳細は下記を参照
varyingVertex Shaderから、Fragment Shaderに値を引き渡したい場合に、両方のコードに同じ型で同じ名前の変数を記述し、varying修飾子を記述することで実現できる。※ただしGLES3.0以降では削除され、in out が代行する
uniformOpenGLESプログラムからシェーダーに値を渡したい場合に利用する。通常は sampler2Dなどのビルトイン修飾詞とセットで指定をし、Vertex Shader、Fragment Shaderの両方のソースから利用できる。基本的にはどのような型にも利用できる汎用修飾子。※GLES3.0以降からは uniform ブロックにも対応
attribute上記 uniform と同じOpenGLESプログラムからシェーダーに値を渡したい場合に利用する。gl_Vertex、gl_Normal、gl_Position、gl_PointSizeなどの頂点に関するビルトイン変数を利用する場合に指定し、Vertex Shaderからのみ利用することができる。基本的には頂点情報だけをやり取りするための専用修飾子。※ただしGLES3.0以降では削除され、in out が代行する
centroidMSAAのポリゴンの外がピクセルの中心になる問題に対して、必ずポリゴン内で補間するように補正する変数に対して指定する。※GLES3.0以降で利用できる修飾子
smooth, flat値の受け渡しの際の補間の方法を指定可能。指定が無い場合はsmooth。int型の場合には flatのみ指定可能。※GLES3.0以降で利用できる修飾子
layout属性インデックスをGLSL側で指定可能。他にも、shared : 複数のプログラムでのレイアウトの一貫性を保証、packed : コンパイラによって変数配置の変更削除などの最適化を許可、std140 : std140のレイアウトに設定、row_major : 行列を行優先、column_major : 行列を列優先などの変数の振る舞いを設定可能。※GLES3.0以降で利用できる修飾子

Edit
各シェーダーのビルトイン変数の詳細

これらビルトイン変数は原則、3.0の仕様となる。gl_FragColor、gl_Color、gl_SecondaryColor、gl_Normal、gl_Vertex、gl_MultiTexCoord、gl_FogCoord、attribute、varying、gl_FragColor, shadow?D, texture?Dなど、多くのビルトイン関数が削除された。

Edit
VertexShader

入出力変数名概要
入力gl_VertexIDint頂点番号が設定される
入力gl_InstanceIDintインスタンス作成の場合にインスタンス番号が設定される
出力gl_Positionvec4クリッピングスペース上における座標。通常の座標を求めたい場合は、(x/w, y/w, z/w)で得られる。
出力gl_PointSizefloat点のサイズ

Edit
FragmentShader

入出力変数名概要
入力gl_FrontFacingboolポリゴンの表裏のブール値
入力gl_FragCoordvec4ウィンドウ座標 (x,y,z, 1/w)
入力gl_PointCoordvec2ポイントスプライト時の2次元座標
入力gl_HelperInvocationbool3.0では使えない。4,5以上
出力gl_FragDepthfloatデプス値を設定

Edit
精度修飾子について

上記のようにC言語とは精度表現が違う。精度修飾子は当然ながら1つの変数に1つだけつけることが出来る。

修飾子付きの型提供される精度C言語で近い型
------double double(精度:2の112乗)
highp float範囲:2^-62〜2^62 精度:2^16double(精度2の52乗)
mediump float範囲:2^-14〜2^14 精度:2^10float(精度2の23乗)
lowp float範囲:2^-8〜2^8float(精度2の23乗)
highp int±2^16long(±2^31)
mediump int±2^10short(±2^15)
lowp int±2^8short(±2^15)

vertex Shaderコードは、lowp、mediump、そしてhighpのいずれを使用してコンパイルとリンクを行っても、エラー無しである必要があり、また Fragment Shaderコードは、lowpとmediumpを使用してコンパイルしてもエラー無しである必要がある

Edit
精度修飾子の初期値設定

precision特別修飾子を利用することで、精度修飾子の初期値を設定できる。

例:precision highp float 

これで、それ以降の float は指定がなければ、すべて highp 精度修飾子が適用される。

Edit
定数について

Edit
定数配列

GLSLにおける定数はC言語で利用されている、static や const などの修飾詞は使えないため、通常の変数として定義する。また右側にも型を指定する必要がある。

<例>

float myArray[4] = float[]( 1.0f,1.0f,1.0f,1.0f );

Edit
キャスト

いわゆる定義のキャストは、C言語とは表記が違う。

<C言語:値の前に括弧で型を宣言>

int my_int = (int) my_float;

<GLSL:型を記載し引数の形で値を指定>

int my_int = int ( my_float );

Edit
プリミティブ形状(基本)の一覧

プリミティブの種類プリミティブ識別定数入力頂点数概要
GL_POINTS1点のサイズが設定できるため、ポイントスプライトが利用できる(点のサイズを大きくしてそこにテクスチャーを貼ることで、常に画面側に表示されるビルボード的な表現方法)
ライン(エッジ)GL_LINES2
三角形ポリゴンGL_TRIANGLES3ポリゴンの基本形態。面になるため実際の立体物にはこのプリミティブでの表現が中心になる。

Edit
OpenGL ES側(メインプログラム)とシェーダーの接続

シェーダープログラムとメインプログラムとの接続には、各変数タイプ毎にOpenGLES関数が提供されている。基本はシェーダー内の変数IDを取得し、そのIDを利用して値を操作する形となる。こここでの、programID とは、glUseProgram関数で指定されたものを指す。

関数名概要
glGetUniformLocation(programID, <uniform変数名>)uniformで定義されている変数のIDを取得する。
glGetAttribLocation(programID, <attribute変数名>)attributeで定義されている変数のIDを取得する。
glEnableVertexAttribArray指定した変数IDの変数に対して頂点座標の配列属性を有効にする
glVertexAttribPointer上の関数で座標属性を有効化したあと、その変数IDに各種頂点に関する設定と、頂点データのポインタを指定することで変数の内容を更新します
glVertexAttrib頂点配列や頂点バッファを使用せずに頂点データを渡す場合はこちらを使用
glUniformXXXXX上のattribute変数用に対して、uniform変数への操作にはこちらを利用する。XXXXXの部分は、変数の型に合わせて各種準備されている。例:glUniformMatrix4fvなど

Edit
ファイルからシェーダーソースを読み込む場合の注意点

シェーダーソースをUTF-8で保存する場合は、BOMコードをつけないようにし、改行コードはUnixのLF(0x0A)のファイル形式で保存すること。Windows形式の改行コード 0x0D, 0x0Aなどの場合、ファイルの先頭から Syntax Errorになる場合がある。

Edit
ベクトル要素

シェーダーで利用できる変数の方には、最小管理単位として浮動小数点型と整数型の2種類しかない。またそれら最小管理単位を複数まとめた集合型(配列でも操作できるので配列型とも認識できる。また代表的用語としてベクター型とも言う)という指定があり、代表的なものには vector型やmatrix型などがある。

要素の型言語予約型各要素名主な使い方
floatvec2
vec3
vec4x, y, z, w命名セット xyz型。主に座標や法線を表すベクトルに表現する場合
r, g, b, a命名セット rgb型。色を表すベクトルにアクセスする場合に使用
s, t, p, q命名セット stpq型。テクスチャ座標を表すベクトルにアクセスする場合に使用

Edit
独特なアクセス方法

集合型(例:vec4など)は、通常のC言語と大きく違い、各要素をまとめてアクセスする表記がある。ただし省略指定は上記の命名セット毎でしか利用できない。

vec4.xy ... vec2型 として x y の2つの要素として取得出来る。
vec4.rgb ... vec3型として、r g b の3つの要素として取得出来る。

いわゆるC言語での型のキャストに似ているが、キャストを明示しなくても、要素の組み合わせで自動的に新しい型として利用できる。応用としては拡張も可能。

vec4 = vec4( vec2, vec2 )
vec4 = vec4( vec3, 1.0 )
vec4 = vec4( vec4.xy, 1.0, vec4.w )

集合型は配列番号によってもアクセスができる。

vec4.x == vec4[0] は同じ場所を指す。
vec4.b == vec4[2] は同じ場所を指す。

Edit
OpenGLES関数などの命名規則

OpenGLES関数では、関数の末尾に特定の文字を付与することでベクトル要素を明確に指定している。

修飾文字内容
関数の末尾に「i」integer 型を表す
関数の末尾に「v」vector 型を表す

Edit
GLSL 3.0 の注意点

Edit
gl_FragColorなどのビルトイン変数の廃止

attributeなどの修飾子の廃止に合わせて、ビルドイン変数も削除された。例えば fragment シェーダーでは、gl_FragColorなどの出力先用のビルトイン変数が存在していたが、削除され、out 指定されたものが、その対象になるようになった。

<旧>

main () {
     gl_FragColor = vColor;
}

<新>

out vec4 ouputColor;
main () {
    outputColor = vColor;
}

Edit
Fragment Shader

Edit
基本的な構造

Edit
テクスチャー

シェーダーコード内で、テクスチャー情報を受け取るためには下記の定義が必要になる。

uniform sampler2D texture;

Edit
TIPS&トラブルシューティング

Edit
Cg からのコンバート

NVIDIAが提供する Cg Toolkit をインストールすると、cgc コマンドがインストールされ、下記のように利用することで、cg shader のソースを、GLSL のシェーダーソースにコンバートできる。

# cgc -profile glslv -profileopts version=100  -o myshader.vsh myshader.cg

注意点は OpenGL ES 2.0の、GLSL 1.0 では、コンバートされたGLSLソースの先頭に記述される、#version 指定がエラーとなるので、version は 100以外を利用しないように注意。profile には、vertexなら glslv、fragmenなら glslf、geometryなら glslg となるようだ。

またコンバート結果で attribute 指定に ivec4 を指定する場合があるが、GLSL では attributeで int型が使えないためエラーになる。よってattribute ではなく、uniform にする必要がある。他にもビルトイン変数である、gl_Color や、gl_Vertex , gl_TexCoord などが、定義されないため varying で定義が必要になる場合がある。

<profileオプションの詳細(共通)>

指定できるprofileopts解説
version=<val>ターゲットのバージョンを指定
userTexCoordgl_TexCoordの代わりにユーザー定義を利用
ATI_draw_buffersuse ATI_draw_buffers extension for MRT
EXT_gpu_shader4use EXT_gpu_shader4 extension where useful
ARB_draw_instanceduse ARB_draw_instanced instead of EXT_draw_instanced
ARB_uniform_buffer_objectuse ARB_uniform_buffer_object extension

Edit
fragment shader で in/out 行がエラーになる。

Tegra K1 などのチップでは、precision 指定を先頭に入れておかないとエラーになる場合がある。

precision highp float;

Edit
GLSLで Cgの型(halfなど)を使いたい。

GPUが、GL_EXT_Cg_shader に対応していればそのまま利用できる。

Edit
glUniformの変数ID(index)がマイナスでもエラーにならない。

変数名などが違っていて、glGetUniformLocationの戻り値が、-1になっておりそれに気が付かず、glUniform1fなどの変数アクセスをしても glerror にならない。これを利用して、シェーダーのソースの共通化の工夫が出来る。

Edit
uniform変数へのアクセスタイミング

glGetUniformLocation などのindex取得 = linkProgramの後。programID取得後。
glUniform1f などのアクセス = glUseProgramの後

Edit
GLSLで半浮動小数点(2バイト)を使いたい。

OpenGLES3.0の一部の実装では下記のハーフフロートオプションが利用できる。対応しているGPUかどうかは、GL Specを確認のこと。

  1. GL_OES_vertex_half_float
  2. GL_OES_texture_half_float
  3. GL_EXT_color_buffer_half_float
  4. GL_ARB_half_float_pixel
  5. GL_ARB_half_float_vertex
  6. GL_NV_half_float

主な使い方はCPU側では、型の指定に GL_FLOAT の代わりに、GL_HALF_FLOAT_OES を指定することで、利用できる。シェーダーでは、#version 300 es の次の行あたりに、#extention

Edit
高速化

Edit
Location獲得命令は、変数名が無い場合、非常に遅くなる。