GLSL
GLSL (OpenGL Shading Language) はGLslangとしても知られ、C言語をベースとした高レベルシェーディング言語である。これはアセンブリ言語やハードウェアに依存した言語を使わないで、アプリケーションソフトウェア開発者がグラフィックスパイプラインを直接制御できるようにOpenGL ARB (Architecture Review Board) [1]で策定された。
Contents
背景
Direct3D 7までの時代、すなわち1990年代までのリアルタイム3Dコンピューターグラフィックスは、OpenGLやDirect3DといったAPIを通して、グラフィックスカード上のチップ(GPU)にあらかじめ用意された固定のレンダリングパイプライン上で、固定機能のシェーダー(頂点トランスフォームや陰影計算を専門に担当するユニット)を組み合わせることで実現されていた。Direct3D 8が登場した2000年以降は、グラフィックスカードの進化・性能向上に伴い、新機能はハードウェア実装による固定機能ではなく、アプリケーション開発者がソフトウェアプログラム(プログラマブルシェーダー)によって頂点レベル・フラグメントレベル(ピクセルレベル)での制御・カスタマイズを行ない、レンダリングパイプライン内での柔軟性や表現力を増すことができる形で追加されることが多くなっている。
元々、このプログラマブルシェーディング機能は複雑で直感的でないアセンブリ言語で書かれたシェーダーを使わないと実現できなかった。OpenGL ARBは、OpenGLをグラフィックス産業の歴史の中でオープンスタンダードなものにしていく中で、グラフィックス処理を行うプログラミングをより直感的・効率的にできる方法として、OpenGL Shading Languageを作り出した。
OpenGL Shading Languageは2003年に発表されたOpenGL 1.5の拡張機能として導入された[2]が、OpenGL ARBはOpenGL 2.0にGLSLを含めることを正式に決定した。OpenGL 2.0は1992年に発表されたOpenGL 1.0から数えて初のメジャーバージョンアップである。
初期のOpenGLプログラマブルシェーダーは、頂点単位のトランスフォームや陰影計算を行なうバーテックスシェーダー (vertex shader) と、フラグメント(ピクセル)単位の陰影計算を行なうフラグメントシェーダー (fragment shader) のみが利用可能であった。その後、プリミティブの増減や変更などを実行できるジオメトリシェーダー (geometry shader) がOpenGL 3.2/GLSL 1.5にて標準化された。またOpenGL 4.0で固定機能シェーダーであるテッセレーションステージが追加されるに伴い、テッセレーション・コントロールシェーダー (tessellation control shader) と、テッセレーション・エバリュエーションシェーダー (tessellation evaluation shader)、これら2つのプログラマブルなシェーダーがGLSLの仕様に追加された。フラグメントシェーダーもサンプルレベルでの制御が可能となった。
なお、OpenGLと同様の3DグラフィックスAPIであるDirectX(Direct3D)およびそのシェーディング言語であるHLSLにはバージョン11以降、GPUにおける汎用的なコンピューティング(GPGPU)を可能とするDirectX Compute Shader(DirectCompute)が追加されているが、OpenGLおよびGLSLのバージョン4.0時点ではこれに相当するシェーダーは含まれていなかった。しかし、バージョン4.3においてOpenGLコンピュートシェーダー (compute shader) として同等機能が導入されることになった。なお、コンピュートシェーダーの導入以前からOpenGLの管轄を行なっているクロノスが同様にオープン仕様として策定している、GPUを汎用コンピューティングに用いることのできるAPIとしてOpenCLが存在するが、こちらはCPUやGPU等あらゆる計算資源を計算に用いることのできる異種計算資源混在(ヘテロジニアス)環境向けのAPIであり、グラフィックスパイプラインとの連携を主目的としたコンピュートシェーダーとは得意分野が若干異なる。
GLSLを使うメリットとして、
- レンダリングアルゴリズムの柔軟なカスタマイズや再利用性が増すことで、従来のハードウェア固定機能にとらわれない、柔軟でユニークかつ高品質なリアルタイム3DCGシーンの構築が可能となる。
- MacintoshやWindows、Linuxを含む複数のOS間での互換性を確保できる。
- アセンブリ言語を用いるよりもコードの再利用性やメンテナンス性が増す。
- OpenGL Shading Languageをサポートするどんなハードウェアベンダーのグラフィックスカード上でも動作するシェーダーを書くことができる能力を持つ。
- それぞれのハードウェアベンダーはデバイスドライバ内にGLSLコンパイラを含めることができるので、そのグラフィックスカードのアーキテクチャに最適化されたコードを生成することができる。
などが挙げられる。 従来の固定機能シェーダーに対するデメリットとしては、
- シェーダーのコンパイルおよびアタッチなど、レンダリングのための準備作業が増える。
- OpenGL APIの他に、GLSLの学習コストがかかる。
- GPU特性やハードウェア仕様を把握してGLSLコードを記述する必要があり、CPUと比較してチューニングが難しい。
などが挙げられる。
なお、GLSLの派生規格として、組み込み環境向けのOpenGL ES用のシェーダー言語「GLSL ES」が存在する。これはESSLと呼ばれることもある[3]。
Webブラウザ向けのOpenGL ES派生規格としてWebGLが存在するが、WebGLでもGLSLが使用される。
クロノスが策定しているローレベルグラフィックスAPIであるVulkanは、シェーダープログラムの中間表現SPIR-Vを入力として受け付けるが、SPIR-Vを出力するオフラインシェーダーコンパイラglslangValidatorにおいて最初にサポートされた上位レベルシェーディング言語はGLSLである。のちにSPIR-VはOpenGL 4.6にも導入された。
詳細
データ型
OpenGL Shading Language 1.50の仕様では64の基本データ型を定義している。いくつかはC言語内で使われていたものとまったく同じものであるが、一方他のものはグラフィックス処理に特化している。 例えば以下のような型が定義されている[4]。
void
値を返さない関数に用いるbool
条件型。値はtrueかfalseのどちらかを返すint
符号付32bit整数float
単精度浮動小数点数vec2
2要素を持つ単精度浮動小数点数ベクトルvec3
3要素を持つ単精度浮動小数点数ベクトルvec4
4要素を持つ単精度浮動小数点数ベクトルbvec2
2要素を持つ論理型ベクトルbvec3
3要素を持つ論理型ベクトルbvec4
4要素を持つ論理型ベクトルivec2
2要素を持つ符号付32bit整数ベクトルivec3
3要素を持つ符号付32bit整数ベクトルivec4
4要素を持つ符号付32bit整数ベクトルmat2
2x2要素を持つ単精度浮動小数点数行列mat3
3x3要素を持つ単精度浮動小数点数行列mat4
4x4要素を持つ単精度浮動小数点数行列sampler1D
1次元のテクスチャにアクセスするためのハンドルsampler2D
2次元のテクスチャにアクセスするためのハンドルsampler3D
3次元のテクスチャにアクセスするためのハンドルsamplerCube
キューブマップテクスチャにアクセスするためのハンドルsampler1DShadow
1次元のデプステクスチャにアクセスするためのハンドルsampler2DShadow
2次元のデプステクスチャにアクセスするためのハンドル
なお、符号なし32bit整数のサポートはOpenGL 3.0 (GLSL 1.3) で標準化され、また科学計算などの分野で必要とされることの多い倍精度浮動小数点数のサポートはOpenGL 4.0 (GLSL 4.0) で標準化されている。
演算子
OpenGL Shanding LanguageはホストプログラムにC言語がよく使われていることを背景にして、それによく似た多くの演算子、加えてベクトル演算に特化した特殊な演算子(Tupleを返すSwizzle演算など)も提供している。このことにより、シェーダー開発者はシェーダーを柔軟にかつ効率よく書くことができる。GLSLはポインタを除くCやC++での演算子を含んでいる。
関数と制御構造
C言語に似ているということは、もちろんGLSLは、if、else if/else、for、do-while、break、continue
などの繰り返しや分岐といった制御文をサポートしている。
ユーザ定義関数もサポートしており、ビルトイン関数と同様広く使われている。このことにより、グラフィックスカードメーカーは、ハードウェアレベルでそれらの組み込み関数を任意で最適化することができる。これらの関数の多くはexp()
やabs()
のようなC言語の標準ライブラリで見られるものとよく似ているが、一方でsmoothstep()
やtexture2D()
のようなグラフィックスプログラミングに特化しているようなものもある。
変数
GLSLコード内における変数の宣言・使用方法は、C言語でのそれに似ている。
変数の修飾子は4つある(以下バーテックスシェーダー、ジオメトリシェーダー、フラグメントシェーダーをそれぞれVS, GS, FSと示す)。
const
変化しない。uniform
全てのシェーダーで使用可能なグローバルな読み出し専用変数。in
入力変数。VSではOpenGLから渡される頂点情報セットを表す(旧attribute
)。GSではVSによって計算された頂点情報セット、FSではVSまたはGSによって計算された頂点情報が補間された値を表す(旧varying
)。out
出力変数。 VSではGSまたはFSへ(旧varying
)、GSではFSへ渡す頂点情報セットを表す。FSでは最終的にピクセル単位で出力する色情報を表す。inout
入出力変数。
コンパイルと実行
GLSLシェーダープログラムは単体のアプリケーションではない。シェーダーの実行にはOpenGL APIを利用するホストアプリケーションが必要である。ホストアプリケーションを記述する言語には、OpenGL APIをサポートする第一級言語であるC言語およびC++、あるいはWebGLをサポートするJavaScriptなどがよく利用される。
GLSLシェーダー自身は単純にOpenGL APIのエントリポイント(API関数)経由で、ハードウェアベンダーのデバイスドライバーに対してソースコード文字列が渡されるだけである。シェーダープログラムのソースコードはホストプログラム上の文字列リテラルとして記述されたり、アプリケーション実行時に外部テキストファイルなどから読み込まれたりしたものがメモリ上の文字列データとして実体化されるが、オフラインの事前コンパイル方式ではなく、あくまでドライバーにはソースコード文字列の形式で送られ、ドライバーが実行時にシェーダーのソースコードをコンパイルして「シェーダープログラムオブジェクト」を生成する。なお、OpenGL 4.1で標準化されたGL_ARB_get_program_binaryにより、コンパイル済みバイナリのシリアライズ・逆シリアライズがサポートされるようになったが、バイナリがベンダー間で互換性のある中間形式であるかどうかは保証されない。OpenGL 4.6では中間表現SPIR-Vがサポートされるようになり、オフラインコンパイルが可能になったことから、OpenGLでプログラマブルシェーダーを利用するために必ずしもGLSLを利用する必要はなくなった。なお、Direct3Dのシェーディング言語であるHLSLはリリース当初から、コンパイル結果はベンダー非依存のバイトコードとなり、またコンパイル済みバイナリの読み込みもサポートしていた。
単純なGLSLバーテックスシェーダーの例
これは固定機能パイプラインと同様に入力頂点を変換する。
void main(void)
{
gl_Position = ftransform();
}
ftransform()
はGLSL 1.40とGLSL ES 1.0からはサポートされない。代わりに、プログラマは新しいOpenGL 3.1標準に従いモデルビュー行列と投影行列を明示的に指定する必要がある。
#version 140
uniform mat4 projectionMatrix;
uniform mat4 modelviewMatrix;
in vec3 position;
void main(void)
{
gl_Position = projectionMatrix * modelviewMatrix * vec4(position, 1.0);
}
単純なGLSLジオメトリシェーダーの例
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in Input
{
vec4 Position;
} VSout[3];
void main(void)
{
for(int i = 0; i < 3; i++)
{
gl_Position = VSout[i].Position;
EmitVertex();
}
EndPrimitive();
}
単純なGLSLフラグメントシェーダーの例
void main(void)
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red.
}
バージョン
GLSLはOpenGL仕様とともにバージョンアップされている。OpenGL 3.2までは、対応するGLSLのバージョン番号はOpenGL本体のバージョン番号と無関係にナンバリングされていたが、OpenGL 3.3以降は同一の番号が割り当てられるようになった。
OpenGLバージョン | GLSLバージョン | #versionディレクティブ |
---|---|---|
1.5 | 1.0 | |
2.0 | 1.1 | #version 110 |
2.1 | 1.2 | #version 120 |
3.0 | 1.3 | #version 130 |
3.1 | 1.4 | #version 140 |
3.2 | 1.5 | #version 150 |
3.3 | 3.3 | #version 330 |
4.0 | 4.0 | #version 400 |
4.1 | 4.1 | #version 410 |
4.2 | 4.2 | #version 420 |
4.3 | 4.3 | #version 430 |
4.4 | 4.4 | #version 440 |
4.5 | 4.5 | #version 450 |
4.6 | 4.6 | #version 460 |
ツール
GLSLシェーダーは単独で動作するプログラムではなく、シェーダープログラムをGPU上で走らせるためには、まずC/C++などで書かれたホストアプリケーションに入力する必要がある。具体的にはOpenGL APIを使ってシェーダープログラムをコンパイル・リンクしたのち、OpenGLレンダリングコンテキストにプログラムオブジェクトをバインドしてからプリミティブのレンダリングを実行する必要があるが、それらの一連の処理を簡略化するためにいくつかのGLSL開発者・デザイナー用ツール(オーサリングツール)が存在する。
- RenderMonkey - ATIによって開発。DirectXシェーダーと同様にGLSLシェーダーを作成、コンパイル、デバッグできるインタフェースを提供している。Microsoft Windows上でのみ実行できる。
- GLSLEditorSample - macOS上でのみ実行できるCocoaアプリケーション。シェーダーの作成とコンパイルはできるがデバッガ機能は組み込まれていない。
- Lumina - 新しいGLSL開発ツール。プラットフォーム独立でインタフェースにQtを使っている。
- Blender - GPLライセンスのモデリングおよびアニメーション作成パッケージで、バージョン2.4.1で内蔵しているゲームエンジンがGLSLをサポートするようになった。
- Mozilla Firefox - 開発者向けツールとして、WebGL用のバーテックスシェーダー・フラグメントシェーダーを参照・編集できる"シェーダーエディター"が実装されている[5]。