3DS での 3D グラフィックスは、シェーダプログラムによってグラフィックスのパイプラインをカスタマイズし、様々なグラフィックスエフェクトを制御することができます。
3DS のシェーダプログラムには、頂点処理、ジオメトリ生成、フラグメント処理の 3 種類が存在します。
この内、頂点処理のシェーダプログラム(以降、頂点シェーダ)にはユーザーがプログラミングした独自のものを使用することができます。
ジオメトリ生成のシェーダプログラム(以降、ジオメトリシェーダ)は SDK で提供されており、それらのジオメトリシェーダと頂点シェーダをリンクして使用することができます。
フラグメント処理のシェーダプログラム(以降、フラグメントシェーダ)はプログラミングすることはできません。フラグメント処理は固定のパイプラインで実装されていますが、予約ユニフォームによる制御が可能です。以降、このフラグメント処理のパイプラインを"予約フラグメント処理"、シェーダプログラムを"予約フラグメントシェーダ"と記述します。
5.1. シェーダの作成
ユーザーが作成可能なシェーダプログラムは頂点シェーダのみです。頂点処理に関する一連の手続きは OpenGL ES 2.0 の仕様に従っていますが、いくつかの機能はサポートされていません。
シェーダプログラムは PICA グラフィックスコア独自のアセンブリ言語で記述します。アプリケーションがシェーダプログラムを使用するには、専用のアセンブラとリンカによって生成されたバイナリをロードし、アタッチしなければなりません。OpenGL ES 2.0 の仕様にある、glShaderSource()
および glCompileShader()
は実装されていません。
頂点シェーダの作成方法については、「8. 頂点シェーダ」および「頂点シェーダ リファレンスマニュアル」を参照してください。
5.2. シェーダのロード
「5.1. シェーダの作成」でも述べたように、シェーダプログラムはバイナリデータをロードしてからアタッチしなければなりません。まず、glCreateShader()
でシェーダオブジェクトを生成します。
GLuint glCreateShader(GLenum type);
ロードするシェーダプログラムの種別によって type
に渡す値が変わります。予約フラグメントシェーダは固定実装のためロードする必要がありません。
type |
生成されるオブジェクト |
---|---|
|
ユーザーが作成した頂点シェーダ用のオブジェクト |
|
SDK が提供するジオメトリシェーダ用のオブジェクト |
シェーダプログラムのバイナリをメモリ上にロードし、glShaderBinary()
で GPU と関連付けます。
void glShaderBinary(GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length);
shaders
にはシェーダオブジェクトの配列、n
には配列の要素数をそれぞれ渡します。アセンブラとリンカによって生成されたバイナリのみをロードすることができますので、binaryformat
には GL_PLATFORM_BINARY_DMP
を渡します。binary
にはシェーダプログラムのバイナリをロードしたアドレス、length
にはそのバイト数をそれぞれ渡します。
ロードされたシェーダプログラムはリンカに渡された順に配列に関連付けられます。配列の要素数および設定すべきシェーダオブジェクトの種別は、リンカが出力するマップファイルで確認することができます。詳しくは「頂点シェーダ リファレンスマニュアル」を参照してください。
5.3. シェーダのアタッチ
ロードされたシェーダプログラムをアプリケーションで使用するには、glCreateProgram()
で生成したプログラムオブジェクトにシェーダプログラムをアタッチし、プログラムオブジェクトをリンクさせなければなりません。
GLuint glCreateProgram(void);
OpenGL ES 2.0 とは異なり、プログラムオブジェクトはシェーダオブジェクトとは独立した 13 ビットの名前空間を持っています。そのため、同時に生成できるのは 8191 個までですが、生成済みのプログラムオブジェクトを glDeleteProgram()
で破棄した場合には再度生成することができるようになります。
プログラムオブジェクトにシェーダプログラムをアタッチするには glAttachShader()
を使用します。
void glAttachShader(GLuint program, GLuint shader);
program
には glCreateProgram()
の返り値を、shader
にはシェーダオブジェクトを渡します。
頂点シェーダとジオメトリシェーダはロードしたバイナリからアタッチしましたが、ロードする必要のなかった予約フラグメントシェーダは、shader
に GL_DMP_FRAGMENT_SHADER_DMP
を渡してアタッチします。
1 つのプログラムオブジェクトには、頂点シェーダ、ジオメトリシェーダ、予約フラグメントシェーダをそれぞれ 1 つずつアタッチすることができます。つまり、ポイントシェーダ(ジオメトリシェーダ)をアタッチした後に続けてラインシェーダ(ジオメトリシェーダ)をアタッチした場合は、ラインシェーダだけが有効となります。
プログラムオブジェクトをリンクさせるには glLinkProgram()
を使用します。
void glLinkProgram(GLuint program);
複数のプログラムオブジェクトをリンクすることができます。ただし、リンクされたプログラムオブジェクトに glAttachShader()
で別のシェーダプログラムをアタッチした場合は、再度 glLinkProgram()
でリンクする必要があります。頂点シェーダとジオメトリシェーダで使用するユニフォームの合計数が 2048 を超えるプログラムオブジェクトのリンクは失敗します。
5.4. シェーダの使用
リンクされたシェーダプログラムを 3D 処理のパイプラインに適用するには glUseProgram()
を使用します。
void glUseProgram(GLuint program);
この関数により、リンクされている複数のシェーダプログラムを切り替えて使用することができます。
OpenGL ではシェーダプログラムの正当性を glValidateProgram()
で確認することができましたが、3DS では関数を呼び出しても何も行われません。
void glValidateProgram(GLuint program);
5.5. シェーダのデタッチ
不要になったシェーダプログラムは glDetachShader()
でデタッチすることができます。
void glDetachShader(GLuint program, GLuint shader);
5.6. シェーダの破棄
不要になったシェーダオブジェクトは glDeleteShader()
で破棄することができます。
void glDeleteShader(GLuint shader);
5.7. シェーダへの問い合わせ
有効・無効の判定やパラメータの取得など、シェーダに関連する情報はプログラムオブジェクトとシェーダオブジェクトに対する問い合わせで取得することができます。
5.7.1. 有効・無効の判定
プログラムオブジェクトやシェーダオブジェクトが有効であるかどうかを glIsProgram()
と glIsShader()
で問い合わせることができます。
GLboolean glIsProgram(GLuint program); GLboolean glIsShader(GLuint shader);
これらの関数は、引数で渡されたプログラムオブジェクトやシェーダオブジェクトが有効であれば GL_TRUE
を、そうでなければ GL_FALSE
を返します。
5.7.2. アタッチされているシェーダオブジェクトの取得
プログラムオブジェクトにアタッチされているシェーダオブジェクトを glGetAttachedShaders()
で取得することができます。
void glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
program
で指定されたプログラムオブジェクトにアタッチされているシェーダオブジェクトの一覧を、shaders
に指定された配列に格納します。maxcount
には shaders
に指定した配列のサイズを指定してください。program
に不正な値を指定した場合や maxcount
に負の値を指定した場合は GL_INVALID_VALUE
のエラーが生成されます。
count
には格納したシェーダオブジェクトの数が格納されます。NULL
を指定した場合は格納されませんが、アタッチされているシェーダオブジェクトの数は、後述する glGetProgramiv()
に GL_ATTACHED_SHADERS
を渡して呼び出すことで取得することができます。
5.7.3. パラメータの取得
プログラムオブジェクトとシェーダオブジェクトのパラメータを glGetProgramiv()
と glGetShaderiv()
で取得することができます。
void glGetProgramiv(GLuint program, GLenum pname, GLint* params); void glGetShaderiv(GLuint shader, GLenum pname, GLint* params);
これらの関数は pname
に指定されたパラメータ名に対応するパラメータの値を params
に格納します。pname
に不正な値が指定された場合は GL_INVALID_ENUM
エラーが生成されます。program
および shader
に不正な値が指定された場合は GL_INVALID_VALUE
エラーが生成されます。
glGetProgramiv()
の pname
に指定可能なパラメータ名と params
に格納されるパラメータを以下に示します。
pname |
params に格納される値 |
---|---|
|
プログラムオブジェクトが削除待ち状態ならば |
|
|
|
|
|
常に 0 が格納されます。 |
|
プログラムオブジェクトにアタッチされているシェーダオブジェクトの数が格納されます。 |
|
アクティブ状態の頂点属性の数が格納されます。 |
|
アクティブ状態の頂点属性のうち、最も長い名前の文字数が格納されます。文字数には終端文字( |
|
アクティブ状態のユニフォームの数が格納されます。 |
|
アクティブ状態のユニフォームのうち、最も長い名前の文字数が格納されます。文字数には終端文字( |
glGetShaderiv()
の pname
に指定可能なパラメータ名と params
に格納されるパラメータを以下に示します。
pname |
params に格納される値 |
---|---|
|
シェーダの種別が格納されます。 |
|
シェーダオブジェクトが削除待ち状態ならば |
|
常に |
|
常に 0 が格納されます。 |
|
常に 0 が格納されます。 |