3DS で扱うことのできるテクスチャには、ポリゴンモデルに貼り付ける 2 次元テクスチャ、キューブマップテクスチャのほかに、シャドウで使用するシャドウテクスチャ、ガスレンダリングで使用するガステクスチャ、予約フラグメントシェーダで使用する参照テーブル(テクスチャとしては使用しません)が存在します。
この章では、それらのテクスチャを使用するために必要な手順と、ネイティブフォーマットの違いについて説明します。
7.1. テクスチャオブジェクトの生成
テクスチャと関連付けるテクスチャオブジェクトを glGenTextures()
で生成します。
void glGenTextures(GLsizei n, GLuint* textures);
7.2. テクスチャオブジェクトの指定
テクスチャと関連付けるテクスチャオブジェクトを glBindTexture()
で指定します。この関数の呼び出し以降、各種テクスチャへの処理は指定されたテクスチャオブジェクトに対して行われるようになります。テクスチャイメージのロードなど、テクスチャオブジェクトへの処理結果はオブジェクトが破棄されるまで保持されます。そのため、テクスチャオブジェクトを切り替えることで、テクスチャイメージを再ロードすることなくテクスチャを切り替えることができます。
void glBindTexture(GLenum target, GLuint texture);
target
にテクスチャの種類を、texture
に関連付けるテクスチャオブジェクトを渡します。target
に下表以外の値を指定した場合は GL_INVALID_ENUM
のエラーを生成します。
target に指定する値 |
テクスチャの種類 |
---|---|
|
2 次元テクスチャ、シャドウテクスチャ、ガステクスチャ |
|
キューブマップテクスチャ |
|
キューブマップテクスチャ |
|
キューブマップテクスチャ |
|
キューブマップテクスチャ |
|
キューブマップテクスチャ |
|
キューブマップテクスチャ |
|
参照テーブル(予約フラグメントシェーダで使用) |
|
テクスチャコレクション(「7.9. テクスチャコレクション」を参照) |
7.3. テクスチャイメージのロード
一般的なテクスチャイメージである 2 次元テクスチャのほかにも、キューブマップテクスチャ、シャドウテクスチャ、ガステクスチャといった特殊なテクスチャも glTexImage2D()
でロードします。glTexSubImage2D()
によるテクスチャの部分ロードはサポートしていません。
void glTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels);
target
には以下のいずれかを指定します。
target に指定する値 |
テクスチャの用途 |
---|---|
|
2 次元テクスチャ、シャドウテクスチャ、ガステクスチャ |
|
キューブマップの +X 面のテクスチャ |
|
キューブマップの -X 面のテクスチャ |
|
キューブマップの +Y 面のテクスチャ |
|
キューブマップの –Y 面のテクスチャ |
|
キューブマップの +Z 面のテクスチャ |
|
キューブマップの –Z 面のテクスチャ |
pixels
の指す領域に格納されているテクスチャイメージのフォーマットを format
と type
の組み合わせで指定します。3DS が扱うことのできるフォーマットの一覧を下表に示します。バイト数の列は 1 テクセルあたりのバイト数です。バイト数の後に"*"のついたフォーマットは PICA ネイティブフォーマットであり、OpenGL 標準のフォーマットとはバイトオーダーが異なるものです。PICA ネイティブフォーマットの詳細は「7.10. PICA ネイティブフォーマット」で説明します。
format |
type |
形式 |
バイト数 |
---|---|---|---|
|
|
RGBA4 |
2 |
|
|
RGBA5551 |
2 |
|
|
RGBA8 |
4 |
|
|
RGB565 |
2 |
|
|
RGB8 |
3 |
|
|
A8 |
1 |
|
|
A4 |
0.5 |
|
|
L8 |
1 |
|
|
L4 |
0.5 |
|
|
LA8 |
2 |
|
|
LA4 |
1 |
|
|
- |
4 |
|
|
- |
4 |
|
|
- |
2 |
|
|
RGBA4 |
2 |
|
|
RGBA5551 |
2 |
|
|
RGBA8 |
4* |
|
|
RGB565 |
2 |
|
|
RGB8 |
3* |
|
|
A8 |
1 |
|
|
A4 |
0.5 |
|
|
L8 |
1 |
|
|
L4 |
0.5 |
|
|
LA8 |
2* |
|
|
LA4 |
1 |
|
|
- |
4* |
|
|
- |
4* |
|
|
- |
2* |
R、G、B:カラー(Red、Green、Blue)
A:アルファ
L:輝度
OpenGL ES1.1 での仕様と同様に、RGB のように A 成分の存在しないテクスチャをテクスチャコンバイナから参照した場合、A 成分には 1 が出力されます。これは、圧縮テクスチャについても同様です。
format
が GL_RGB
または GL_RGB_NATIVE_DMP
で、type
が GL_UNSIGNED_BYTE
の組み合わせは target
に GL_TEXTURE_2D
を指定している場合にのみ指定可能です。format
に GL_*_NATIVE_DMP
を指定した場合、pixels
で指定されるデータは PICA のネイティブフォーマットでなければなりません。また、GL_GAS_DMP
を指定した場合は、pixels
は 0(NULL
)でなければなりません。
width
と height
にはテクスチャイメージの幅と高さを指定します。ともに 8 ~ 1024 の 2 のべき乗の数でなければなりません。
target
の指定が GL_TEXTURE_CUBE_MAP_*
である場合、width
と height
の値は同じでなければなりません。また、各面の設定は pixels
(と target
)以外がすべて同じ指定でなければなりません。
pixels
に 0(NULL
)を指定した場合はイメージデータのロードは行われず、領域の確保だけが行われます。
internalformat
には内部基本形式を指定します。internalformat
と format
の指定が同じでない場合は GL_INVALID_OPERATION
のエラーが生成されます。イメージの RGBA 成分と内部基本形式の各成分との対応は以下のようになっています。
内部基本形式 |
RGBA |
内部形式 |
---|---|---|
|
A |
A |
|
R |
L |
|
R、A |
L、A |
|
R、G、B |
R、G、B |
|
R、G、B、A |
R、G、B、A |
|
R、G |
Nx、Ny |
GL_HILO8_DMP
の場合、B 成分と A 成分にはそれぞれ 0.0 と 1.0 が出力されます。
OpenGL の仕様と異なり、level
にはミップマップ段数を負の値(例えば、段数が 2 ならば -2。0 と -1 は同じ段数 1 として扱う)で設定します。個別にミップマップの各レベルで使用するテクスチャを指定することはできず、pixels
には最も大きなサイズのレベルで使用するテクスチャから最も小さなサイズのレベルで使用するテクスチャまでを連続して格納したデータを指定してください。
border
には、0 以外の値を指定することはできません。
glTexImage2D()
の target
に特別なフラグを論理和で渡すことで、GPU のアクセス先や領域確保時の処理を指定することができます。詳細については、「3DS プログラミングマニュアル - グラフィックス応用編」「メインメモリに置かれたデータの使用」を参照してください。
7.3.1. コンポーネントが 4 ビットのフォーマットについて
type
が GL_UNSIGNED_BYTE_4_4_DMP
または GL_UNSIGNED_4BITS_DMP
のテクスチャフォーマットは、1 つのコンポーネントが 4 ビットで構成されているため、そのデータの並びは特殊なものになっています。
type
が GL_UNSIGNED_BYTE_4_4_DMP
のフォーマットは、1 バイトに 2 つのコンポーネントを含むフォーマットです。format
には GL_LUMINANCE_ALPHA
または GL_LUMINANCE_ALPHA_NATIVE_DMP
を組み合わせることができます。上位 4 ビットに輝度成分、下位 4 ビットにアルファ成分が格納されます。
type
が GL_UNSIGNED_4BITS_DMP
のフォーマットは、1 バイトに 2 テクセルを含むフォーマットです。format
には GL_LUMINANCE
、GL_LUMINANCE_NATIVE_DMP
、GL_ALPHA
、GL_ALPHA_NATIVE_DMP
のいずれかを組み合わせることができます。テクセルの並びで見ると、成分は下位 4 ビット、上位 4 ビットの順に格納されます。
type
に GL_UNSIGNED_4BITS_DMP
を指定するテクスチャフォーマット(4 ビットフォーマット)と、それ以外のテクスチャフォーマット(非 4 ビットフォーマット。ETC1 方式の圧縮テクスチャ含む)を同時に有効にし、マルチテクスチャとして使用する場合はテクスチャの配置に制限があります。
4 ビットフォーマットのテクスチャを VRAM に配置する場合は 4 ビットフォーマットと非 4 ビットフォーマットのテクスチャを異なるメモリに配置しなければなりません。その際、VRAM-A と VRAM-B は異なるメモリとして扱われます。なお、同じメモリに配置した場合の動作は不定です。
4 ビットフォーマットのテクスチャをメインメモリに配置した場合はテクスチャの配置に制限はありません。
7.4. 圧縮テクスチャのロード
圧縮された画像データをテクスチャイメージとしてロードすることができます。glCompressedTexSubImage2D()
による圧縮テクスチャの部分ロードはサポートしていません。
void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data);
target
に指定する値は glTexImage2D()
の target
と同じです(表 7-2)。ただし、この関数で確保した領域をシャドウテクスチャやガステクスチャに使用することはできません。
width
と height
にはテクスチャイメージの幅と高さを指定します。ともに 16 ~ 1024 の 2 のべき乗の数でなければなりません。
level
と border
に指定する値と、キューブマップテクスチャおよびミップマップテクスチャについての制限は glTexImage2D()
と同じです。詳細は「7.3. テクスチャイメージのロード」を参照してください。
テクスチャの圧縮方式は ETC1(Ericsson Texture Compression)方式のみがハードウェアでサポートされています。そのため、internalformat
には GL_ETC1_RGB8_NATIVE_DMP
または GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP
が指定可能です。
ETC1 方式は 24 bit RGB フォーマットの 4x4 テクセルを 64 bit に圧縮します。GL_ETC1_RGB8_NATIVE_DMP
はアルファチャンネルには対応していませんが、GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP
は 16 テクセル× 4 bit のアルファ成分データを付加することによってアルファチャンネルに対応しています。
なお、アルファチャンネルに対応していないフォーマットの圧縮テクスチャをテクスチャコンバイナから参照した場合、A 成分には 1 が出力されます。
imageSize
にはイメージデータのバイトサイズを指定します。imageSize
はテクスチャの元画像の幅を w、高さを h とすれば以下の計算式で求めることができます。blockSize
にはアルファチャンネルなしでは 8 が、アルファチャンネルありでは 16 が適用されます。
imageSize
= (w / 4) * (h / 4) * blockSize
3DS で扱う ETC1 方式は標準の仕様とは異なっています。標準仕様とのフォーマットの違いは「7.10. PICA ネイティブフォーマット」で説明します。フォーマットの詳細については「3DS プログラミングマニュアル - グラフィックス応用編」を参照してください。
glCompressedTexImage2D()
の target
に特別なフラグを論理和で渡すことで、GPU のアクセス先や領域確保時の処理を指定することができます。詳細については、「3DS プログラミングマニュアル - グラフィックス応用編」「メインメモリに置かれたデータの使用」を参照してください。
7.5. フレームバッファからのコピー
フレームバッファオブジェクトに関連付けられているカラーバッファ、デプスバッファの画像をテクスチャとして取得(コピー)することができます。
7.5.1. カラーバッファからのコピー
カラーバッファの画像をテクスチャとして取得(コピー)することができます。
void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
target
に指定する値は glTexImage2D()
の target
と同じです(表 7-2)。そのほかの引数も以下の違いを除けば同じです。
-
internalformat
で指定可能な内部形式のフォーマットはGL_RGB
またはGL_RGBA
のみで、カラーバッファのフォーマットからの変換を伴うコピーはできません(ピクセルサイズが同じフォーマットは可能です)。 -
x
、y
にはカラーバッファからコピーする領域の開始点(左下原点、右上正方向)を指定します。width
、height
にはコピーする領域の幅と高さを指定します。x
、y
は 8 の倍数で指定しなければなりません。 -
level
には 0 のみが指定可能です。
glCopyTexImage2D()
の target
に特別なフラグを論理和で渡すことで、GPU のアクセス先や領域確保時の処理を指定することができます。詳細については、「3DS プログラミングマニュアル - グラフィックス応用編」「メインメモリに置かれたデータの使用」を参照してください。
7.5.2. カラーバッファからの部分コピー
カラーバッファからテクスチャイメージの部分領域にコピーすることもできます。
void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
コピー先のテクスチャイメージの領域を、glTexImage2D()
で事前に確保していなければなりません。
xoffset
と yoffset
にコピー先領域の座標(左下原点、右上正方向。8 の倍数でなければなりません)を指定すること、width
と height
には 8 の倍数(2 のべき乗でなくてもよい)を指定すること以外は、glCopyTexImage2D()
と同じです。詳細は「7.5.1. カラーバッファからのコピー」を参照してください。
7.5.3. デプスバッファからのコピー
glEnable()
の引数に GL_DEPTH_STENCIL_COPY_DMP
を渡して呼び出し、デプスステンシルコピー機能を有効にした状態で glCopyTexImage2D()
または glCopyTexSubImage2D()
を呼び出したときはカラーバッファではなく、デプスバッファ(ステンシル含む)の内容がテクスチャにコピーされます。
カレントのデプスバッファのフォーマットによって、コピー先に指定するテクスチャのフォーマットは決められています。コピー時にフォーマットの変換は行われませんので、対応していないフォーマットのテクスチャにコピーをしようとした場合は GL_INVALID_OPERATION
のエラーが生成されます。テクスチャにコピーされる内容は、テクスチャがネイティブフォーマットであるかどうかによって変化することはありません。
デプスバッファのフォーマット |
テクスチャの format |
テクスチャの type |
成分の内容 |
---|---|---|---|
|
|
|
R: Stencil |
|
|
|
R: D [23 : 16] |
|
|
|
R: D [15 : 8] |
※ 「成分の内容」列の "D [x : y]" は、その成分に設定されるデプス値のビット位置を示しています。
デプスステンシルコピー機能は、GL_DEPTH_STENCIL_COPY_DMP
を引数にして、glEnable()
、glDisable()
、glIsEnabled()
を呼び出すことで、有効化、無効化、有効・無効の判定を行うことができます。
glCopyTexImage2D()
と glCopyTexSubImage2D()
はブロックモードがブロック 32 モードのときに使用することができません。エラーは生成されませんが、画像の転送が正しく行われません。ブロックモードの設定については「3DS プログラミングマニュアル - グラフィックス応用編」を参照してください。
7.6. レンダーターゲットへのテクスチャの指定
glTexImage2D()
で確保したテクスチャイメージを glFramebufferTexture2D()
でフレームバッファオブジェクトに関連付けることで、レンダリング結果を直接テクスチャに書き込む(render to texture)ことができます。シャドウやガスで使用される特殊なテクスチャはそれぞれの機能においてレンダリング結果が直接テクスチャに書き込まれるため、この関数でテクスチャをレンダーターゲットに指定しなければなりません。
void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
target
に指定することができるのは GL_FRAMEBUFFER
のみです。
attachement
にはテクスチャに書き込む情報を指定します。カラーバッファならば GL_COLOR_ATTACHMENT0
、デプスバッファならば GL_DEPTH_ATTACHMENT
を指定します。
textarget
に指定する値は glTexImage2D()
の target
と同じです(表 7-2)。
texture
には、フレームバッファオブジェクトに関連付けるテクスチャオブジェクトを指定します。
level
には 0 のみが指定可能です。
デプスバッファ(ステンシルバッファ含む)のレンダーターゲットにテクスチャを指定する場合、デプスバッファのフォーマットによって、テクスチャのフォーマットは決められています。対応するフォーマットは「7.5.3. デプスバッファからのコピー」と同じです(表 7-5)。デプスバッファのフォーマットが GL_DEPTH24_STENCIL8_EXT
の場合、attachment
に GL_DEPTH_STENCIL_ATTACHMENT
を指定できますが、GL_DEPTH_ATTACHMENT
と同じ結果になります。
7.7. 参照テーブルのロード
OpenGL の 1 次元テクスチャをロードする関数 glTexImage1D()
を、3DS では参照テーブルのロードに使用します。参照テーブルとは、プロシージャルテクスチャやフラグメントライティング、フォグ、ガスで参照する 1 次元のテーブルのことで、テクスチャとして使用することはありません。
void glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
target
にはロード先の参照テーブルを GL_LUT_TEXTUREi_DMP
で指定します。i
は参照テーブルの番号(0 ~ glGetIntegerv()
の pname
に GL_MAX_LUT_TEXTURES_DMP
を渡して得られる値 - 1)です。つまり、参照テーブル番号は 0 ~ 31 の範囲で指定することができます。GL_LUT_TEXTUREi_DMP
は(GL_LUT_TEXTURE0_DMP
+ i
)で定義されています。
level
には 0 、type
には GL_FLOAT
、format
および internalformat
には GL_LUMINANCEF_DMP
のみを指定することができます。level
に 0 以外を指定した場合は GL_INVALID_VALUE
のエラーを、type
、format
、internalformat
に上記以外を指定した場合は GL_INVALID_ENUM
のエラーを生成します。
width
にはテーブルの要素数を、pixels
にはテーブルの要素を指定します。width
に指定することのできる最大値は glGetIntegerv()
の pname
に GL_MAX_LUT_ENTRIES_DMP
を渡して得られる 512 ですが、テーブルの要素数および要素は予約フラグメント処理によって独自の制限が決められています。
glGetIntegerv()
の pname
に GL_TEXTURE_BINDING_LUTi_DMP
(i
は 0 ~ 31)を渡して呼び出すと、GL_LUT_TEXTUREi_DMP
に関連付けられているテクスチャオブジェクト(の ID)を取得することができます。
すでにロードされている参照テーブルの内容を一部分だけ書き換えるには、glTexSubImage1D()
を使用します。
void glTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels);
コピー先の参照テーブルの領域は、glTexImage1D()
で事前に確保していなければなりません。
xoffset
と width
に書き換えたい要素の先頭番号と要素数を指定すること以外は、glTexImage1D()
と同じです。xoffset
と width
の合計がテーブルの要素数を超える場合は GL_INVALID_VALUE
のエラーを生成します。
glCopyTexImage1D()
、glCopyTexSubImage1D()
は実装されていません。また、テクスチャパラメータの設定には対応していません。
7.8. テクスチャオブジェクトの破棄
不要になったテクスチャオブジェクトは glDeleteTextures()
で破棄することができます。
void glDeleteTextures(GLsizei n, const GLuint* textures);
7.9. テクスチャコレクション
テクスチャコレクションは 3DS が独自に導入したもので、テクスチャオブジェクトとテクスチャの関連付けを記録します。テクスチャコレクションを使用することで、記録された各種テクスチャとテクスチャオブジェクトの関連付けをまとめて行うことができます。テクスチャコレクションはテクスチャオブジェクトと名前空間を共有していますので、glGenTextures()
、glBindTexture()
、glDeleteTextures()
を使用して生成・指定・破棄を行います。
7.9.1. テクスチャコレクションの生成
テクスチャコレクションは特殊なテクスチャオブジェクトとして動作します。そのためテクスチャオブジェクトと同じように、glGenTextures()
でテクスチャコレクションとして使用するオブジェクトを生成します。
7.9.2. テクスチャコレクションの指定
テクスチャコレクションとして使用するテクスチャオブジェクトを指定するには glBindTexture()
を使用します。target
に GL_TEXTURE_COLLECTION_DMP
を渡して呼び出してください。デフォルトでは、名前 0(texture
に 0 を渡した状態)のオブジェクトがテクスチャコレクションとなっています。
呼び出し後は、各種テクスチャ(2 次元テクスチャ、キューブマップテクスチャ、参照テーブル)への glBindTexture()
によるテクスチャオブジェクトの関連付けはテクスチャコレクションに記録されていきます。同じテクスチャへの関連付けは上書きされ、テクスチャコレクションへの記録はほかのテクスチャコレクションへ切り替えられるまで行われます。
テクスチャコレクションを切り替えると、各種テクスチャとテクスチャオブジェクトとの関連付けはテクスチャコレクションに記録されているオブジェクトにすべて切り替わります。
7.9.3. テクスチャコレクションの破棄
テクスチャオブジェクトと同じように、glDeleteTextures()
でテクスチャコレクションを破棄することができます。テクスチャコレクションを破棄しても、記録されているテクスチャオブジェクトのテクスチャとの関連付けに影響ありません。
使用中のテクスチャコレクションへの glDeleteTextures()
の呼び出しでは、すぐにテクスチャコレクションが破棄されません。ほかのテクスチャコレクションに切り替えられるまで使用状態のまま残ります。デフォルトのテクスチャコレクションは破棄できません。デフォルトのテクスチャコレクションに対する glDeleteTextures()
の呼び出しは無視されます。
7.10. PICA ネイティブフォーマット
GPU のテクスチャユニットがサポートしているテクスチャフォーマットは OpenGL の仕様と異なっています。テクスチャユニットが実際にサポートしているフォーマットを PICA ネイティブフォーマットと呼びます。PICA ネイティブフォーマットのテクスチャをロードする場合、ライブラリ内でのフォーマット変換が行われないため、標準フォーマットよりも効率が良くなります。
OpenGL の仕様との大きな違いは以下の 3 つです。
- バイトオーダー
内部のアドレス処理の関係でバイトデータの記述順序が異なります。
- V フリップ
U、V 座標とテクセルとの配置の関係が V 方向で反対になっています。
- アドレッシング
リニアアドレッシング(OpenGL)とブロックアドレッシング(PICA ネイティブフォーマット)の相違により、テクセルおよび圧縮データブロックの記述順序が異なります。
OpenGL のフォーマットから PICA ネイティブフォーマットへ変換するには、非圧縮テクスチャ(glTexImage2D()
でロード)であれば V フリップ変換→アドレッシング変換→バイトオーダー変換の順に行い、圧縮テクスチャ(glCompressedTexImage2D()
でロード)であれば、V フリップ変換→ETC 圧縮→アドレッシング変換→バイトオーダー変換の順に行います。ETC 圧縮の前に V フリップ変換を行わなければならないことに注意してください。
7.10.1. バイトオーダーの違い
glTexImage2D()
の type
に GL_UNSIGNED_BYTE
を指定し、複数バイトで 1 テクセルを表現するフォーマットは、そのバイト数でバイトスワップ(バイトデータの入れ替え)を行います。
圧縮フォーマットの場合は 1 ブロック(4x4 テクセル分の 8 バイト)単位でバイトデータの入れ替えを行います。ただし、アルファチャンネルありの場合は、アルファ部分(前半の 8 バイト)のバイトデータの入れ替えは行いません。
7.10.2. V フリップの違い
OpenGL の仕様では(u, v)=(0.0, 0.0)にあるテクセルを先頭にイメージがデータ化されますが、PICA ネイティブフォーマットでは(u, v)=(0.0, 1.0)にあるテクセルを先頭にイメージがデータ化されます。非圧縮・圧縮テクスチャでの違いはありません。
7.10.3. アドレッシングの違い
OpenGL の仕様では u 方向に連続したテクセルを格納(リニアアドレッシング)していきますが、PICA ネイティブフォーマットではブロック単位で u 方向に連続しますが、ブロック内はジグザグにテクセルを格納(ブロックアドレッシング)していきます。