11. テクスチャ処理

テクスチャ処理では OpenGL ES 2.0 と同等の動作を行うことができますが、いくつか 3DS 固有の制約があります。

11.1. テクスチャユニット

3DS は 4 つのテクスチャユニット(TEXTURE03)を搭載していますが、テクスチャユニットによって扱うことのできるテクスチャの種類が異なります。また、ラスタライズを行うラスタライザからテクスチャユニットに、独立して出力されるテクスチャ座標は 3 組までです。4 つのテクスチャユニットすべてにテクスチャ座標を出力する場合、TEXTURE2 または TEXTURE3 がほかのテクスチャユニットと同じテクスチャ座標を共有することになります

表 11-1. テクスチャユニットが扱うことのできるテクスチャ

テクスチャ
ユニット

2次元
テクスチャ

キューブマップ
テクスチャ

シャドウ
テクスチャ

プロジェクション
テクスチャ

プロシージャル
テクスチャ

TEXTURE0

 

TEXTURE1

 

 

 

 

TEXTURE2

 

 

 

 

TEXTURE3

 

 

 

 

1 次元、3 次元テクスチャには対応していません。キューブマップ、シャドウ、プロジェクションのように、w 成分が必要となるテクスチャの処理は TEXTURE0 でのみ行うことができます。また、TEXTURE3 はプロシージャルテクスチャ専用のユニットです。搭載されているテクスチャユニットの数を示す GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS は 4 で定義されています。

11.1.1. テクスチャ座標の入力

テクスチャユニット 0 のみ w 成分を入力することができ、そのほかのテクスチャユニットには u と v の 2 成分のみ入力が可能です。プロジェクションテクスチャは、単に 2 次元テクスチャに w 成分を有効にしたものですが、座標(u, v)が w で除算されて生成されるため、頂点シェーダで出力する座標値には注意が必要となります。

頂点シェーダからテクスチャ座標を送るには属性名 texture0texture0wtexture1texture2 で出力レジスタをマッピングします。texture0w は、キューブマップ、シャドウ、プロジェクションテクスチャのように、w 成分を必要とする場合には必ず出力しなければなりません。出力していない場合のテクスチャ座標 0 の出力は不定です。w 成分を必要としないテクスチャに対する texture0w の出力は無視されます。

表 11-2. 頂点シェーダで指定する属性名とテクスチャ座標の対応

属性名

頂点シェーダから送られる属性

texture0

テクスチャ座標 0 の u, v 成分

texture0w

テクスチャ座標 0 の w 成分

texture1

テクスチャ座標 1 の u, v 成分

texture2

テクスチャ座標 2 の u, v 成分

11.1.1.1. テクスチャ座標の精度について

テクスチャユニット内では、テクスチャ座標値は整数部と小数部を合わせて 16 ビットの値で表現され、整数部の絶対値が大きくなると小数部のビット数が小さくなります。

テクスチャのサンプリング精度は小数部のビット精度に依存しています。小数部がテクスチャの幅または高さのテクセル数を表現するのに十分なビット数になる場合は、最適なテクスチャのサンプリングを行うことができます。バイリニアフィルタリングを行う場合は、さらに 6 ビットを小数部に確保するようにしてください。

11.1.2. 使用方法

OpenGL ではテクスチャユニットの有効・無効の切り替えを glEnable()glDisable() の引数に TEXTURE_2D などを指定することで行っていましたが、3DS では予約ユニフォーム dmp_Texture[i].samplerTypei はテクスチャユニットの番号)に対する設定によって行います。GL_TEXTURE_2D を引数に、glEnable() または glDisable() を呼び出した場合の動作は不定です。

テクスチャユニットを無効にするには、どのテクスチャユニットでも GL_FALSE を指定して glUniform1i() を呼び出し、予約ユニフォームに値を設定することで行われます。有効にする場合は、テクスチャユニットによって予約ユニフォームに設定する値が異なります。

表 11-3. 予約ユニフォーム dmp_Texture[i].samplerType に対する設定値

予約ユニフォーム

設定する値

扱うテクスチャ

dmp_Texture[0].samplerType

GL_FALSE

無効(デフォルト)

GL_TEXTURE_2D

2 次元テクスチャ

GL_TEXTURE_CUBE_MAP

キューブマップテクスチャ

GL_TEXTURE_SHADOW_2D_DMP

シャドウテクスチャ

GL_TEXTURE_SHADOW_CUBE_DMP

キューブマップシャドウテクスチャ

GL_TEXTURE_PROJECTION_DMP

プロジェクションテクスチャ

dmp_Texture[1].samplerType

GL_FALSE

無効(デフォルト)

GL_TEXTURE_2D

2 次元テクスチャ

dmp_Texture[2].samplerType

GL_FALSE

無効(デフォルト)

GL_TEXTURE_2D

2 次元テクスチャ

dmp_Texture[3].samplerType

GL_FALSE

無効(デフォルト)

GL_TEXTURE_PROCEDURAL_DMP

プロシージャルテクスチャ

テクスチャユニットが入力に使用するテクスチャ座標は、テクスチャユニット 0 がテクスチャ座標 0 固定、テクスチャユニット 1 がテクスチャ座標 1 固定、テクスチャユニット 2 と 3 については予約ユニフォーム dmp_Texture[i].texcoordi はテクスチャユニットの番号で 2 または 3 )で指定しなければなりません。テクスチャユニットによって予約ユニフォームに設定することができる値が異なります。4 つのテクスチャユニットすべてを使用する場合、テクスチャユニット 2 またはテクスチャユニット 3 が入力に使用するテクスチャ座標をほかのテクスチャユニットと共有しなければなりません。

テクスチャコンバイナから無効化されているテクスチャユニットを参照した場合、テクスチャコンバイナに入力されるカラー値は不定になります。

表 11-4. 予約ユニフォーム dmp_Texture[i].texcoord に対する設定値

予約ユニフォーム

設定する値

入力に使用するテクスチャ座標

dmp_Texture[2].texcoord

GL_TEXTURE1

テクスチャ座標 1

GL_TEXTURE2

テクスチャ座標 2(デフォルト)

dmp_Texture[3].texcoord

GL_TEXTURE0

テクスチャ座標 0(デフォルト)

GL_TEXTURE1

テクスチャ座標 1

GL_TEXTURE2

テクスチャ座標 2

予約ユニフォームによる設定を除き、テクスチャユニットに対する設定は glActiveTexture() で指定したテクスチャユニットに対して行われます。

コード 11-1. glActiveTexture() の定義
void glActiveTexture(GLenum texture);

texture には GL_TEXTURE0GL_TEXTURE1GL_TEXTURE2 を指定することができます。テクスチャユニット 3 を示す GL_TEXTURE3 を指定した場合や上記以外の値を指定した場合は GL_INVALID_ENUM のエラーが生成されます。

プロシージャルテクスチャの設定はすべて予約ユニフォームで行います。

11.1.3. 使用するテクスチャの指定

テクスチャユニットで使用するテクスチャは glActiveTexture() でテクスチャユニットを指定した後の、glBindTexture() によるテクスチャオブジェクトの指定で行われます。

テクスチャユニットごとに異なるテクスチャを使用する場合は、以下のコード例のように glActiveTexture()glBindTexture() を呼び出してください。

コード 11-2. テクスチャユニットごとにテクスチャを指定する例
// Texture Unit0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, imageTexID);
// Texture Unit1
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bumpTexID);

11.1.4. テクスチャパラメータ

テクスチャのラッピングモードやフィルタなど、テクスチャにパラメータを付加するには glTexParameter*() を使用します。

コード 11-3. glTexParameter*() の定義
void glTexParameterf(GLenum target, GLenum pname, GLfloat param);
void glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
void glTexParameteri(GLenum target, GLenum pname, GLint param);
void glTexParameteriv(GLenum target, GLenum pname, const GLint* params);

glTexParameteri() はパラメータに整数を、glTexParameterf() はパラメータに浮動小数点数を渡して付加する関数です。関数名の末尾に "v" の付いたものはベクトル(配列)を渡さなければならないパラメータの付加に使用します。

target に指定する値は glTexImage2D()target と同じです(表 7-2)。pname は付加するパラメータの名前、param はパラメータの値です。3DS で独自に追加されているパラメータが存在します。

3DS では、1 つのフラグメントに対して最大 8 テクセルを取得してフィルタリングを行っています。

表 11-5. pname と付加されるパラメータの対応

pname

int / float / vector

付加されるパラメータ

GL_TEXTURE_WRAP_S

int

S 方向のラッピングモード(表 11-6

GL_TEXTURE_WRAP_T

int

T 方向のラッピングモード(表 11-6

GL_TEXTURE_MIN_FILTER

int

縮小時のフィルタ(表 11-7

GL_TEXTURE_MAG_FILTER

int

拡大時のフィルタ(表 11-8

GL_TEXTURE_BORDER_COLOR

vec4(float)

ラッピングモードで GL_CLAMP_TO_BORDER が指定されている場合に使用されるボーダーカラー(各成分とも 0.0 ~ 1.0)

GL_TEXTURE_LOD_BIAS

float

LOD バイアス値(-16.0 ~ 16.0。デフォルト 0.0)

GL_TEXTURE_MIN_LOD

int

LOD の最小レベル(デフォルト -1000)

GL_GENERATE_MIPMAP

int(bool)

ミップマップテクスチャの自動生成(デフォルト GL_FALSE)。詳細については、「11.1.4.1. ミップマップテクスチャの自動生成」を参照してください。

S、T 方向のラッピングモードは以下の値で指定します。

表 11-6. S、T 方向のラッピングモードの指定

param

説明

GL_REPEAT

繰り返し(デフォルト)

GL_MIRRORED_REPEAT

反転して繰り返し

GL_CLAMP_TO_EDGE

テクスチャ座標 0.0 ~ 1.0 以外はテクスチャイメージの端のカラー

GL_CLAMP_TO_BORDER

テクスチャ座標 0.0 ~ 1.0 以外はボーダーカラー

テクスチャイメージが縮小されてレンダリングされる場合のフィルタは以下の値で指定します。

表 11-7. 縮小時のフィルタの指定

param

説明

GL_NEAREST

ニアレストに選定されたテクセルのカラーを使用する(デフォルト)

GL_LINEAR

バイリニアサンプリング(4 サンプルの平均)でカラーを決定する

GL_NEAREST_MIPMAP_NEAREST

ミップマップテクスチャの選定をニアレストで行い、ニアレストに選定されたテクセルのカラーを使用する

GL_NEAREST_MIPMAP_LINEAR

2 つのレベルのミップマップテクスチャを選定し、それぞれのレベルでニアレストに選定されたカラーから補間する

GL_LINEAR_MIPMAP_NEAREST

ミップマップテクスチャの選定をニアレストで行い、バイリニアサンプリングでカラーを決定する

GL_LINEAR_MIPMAP_LINEAR

2 つのレベルのミップマップテクスチャを選定し、それぞれのレベルでバイリニアサンプリングされたカラーから補間する

テクスチャイメージが拡大されてレンダリングされる場合のフィルタは以下の値で指定します。

表 11-8. 拡大時のフィルタの指定

param

説明

GL_NEAREST

ニアレストに選定されたテクセルのカラーを使用する(デフォルト)

GL_LINEAR

バイリニアサンプリング(4 サンプルの平均)でカラーを決定する

11.1.4.1. ミップマップテクスチャの自動生成

テクスチャパラメータ GL_GENERATE_MIPMAPGL_TRUE を設定すると、glTexImage2D()glCopyTexImage2D()glCopyTexSubImage2D() の呼び出しで level に -2 以下の値を渡したときに、最も低いレベルのテクスチャ以外のミップマップテクスチャが自動生成されます。ただし、自動生成されるミップマップテクスチャの幅と高さは、テクスチャのフォーマット(formattype の組み合わせ)によって、その最小値が以下のように制限されています。

表 11-9. 自動生成されるミップマップテクスチャの幅と高さの最小値

フォーマット

format

type

幅、高さの最小値

RGBA4

GL_RGBA
GL_RGBA_NATIVE_DMP

GL_UNSIGNED_SHORT_4_4_4_4

64

RGBA5551

GL_RGBA
GL_RGBA_NATIVE_DMP

GL_UNSIGNED_SHORT_5_5_5_1

64

RGBA8

GL_RGBA
GL_RGBA_NATIVE_DMP

GL_UNSIGNED_BYTE

32

RGB565

GL_RGB
GL_RGB_NATIVE_DMP

GL_UNSIGNED_SHORT_5_6_5

64

RGB8

GL_RGB
GL_RGB_NATIVE_DMP

GL_UNSIGNED_BYTE

32

テクスチャのフォーマットによる最小値の違いにより、同じ幅と高さのテクスチャでも level に指定することのできる値の範囲が異なります。最小値よりも小さなサイズのミップマップテクスチャを自動生成させるような指定をした場合は GL_INVALID_OPERATION のエラーが生成されます。例えば、128x128 テクセルのテクスチャに対して、フォーマットが RGB8 のときは level に -2 または -3 を指定することができますが、フォーマットが RGB565 のときは level に -2 のみ指定することができます。

自動生成を行う設定をしていた場合は、自動生成されたミップマップテクスチャが優先されます。ミップマップテクスチャのデータを含むテクスチャイメージをロードすると、そのミップマップテクスチャのデータは無効となります。

自動生成を行う設定をしていた場合、glCopyTexImage2D()glCopyTexSubImage2D()level には、対象のテクスチャをロードしたときの glTexImage2D()level に渡した値と同じ値を渡さなければなりません。異なる場合は GL_INVALID_OPERATION のエラーが生成されます。ただし、level に 0 以外を渡したとしても、コピー先は最も低いレベルのテクスチャであり、ミップマップテクスチャを書き換えることにはなりません。

自動生成を行わない設定をしていた場合は、glCopyTexImage2D()glCopyTexSubImage2D()level には、対象のテクスチャをロードしたときの glTexImage2D()level に渡した値に関わらず、0 を指定しなければなりません。0 以外を指定した場合は GL_INVALID_OPERATION のエラーが生成されます。

11.1.4.2. フィルタに GL_NEAREST を指定した場合の注意事項

テクスチャパラメータの GL_TEXTURE_MIN_FILTER および GL_TEXTURE_MAG_FILTER に対して GL_NEAREST を指定した場合、垂直または水平な直線(色の境界が明確な直線を成す場合を含む)のある画像をテクスチャとして使用し、その直線が画面の走査線に垂直または水平になるようにポリゴンを描画すると、本来直線に見えるはずの模様がデコボコな線として描画されることがあります。

この現象は、ポリゴン内のテクスチャ座標を補間する際の計算精度が起因となっています。走査線に垂直または水平な、ある一列に並んだフラグメント列を考えたとき、各フラグメントがテクスチャ画像上の垂直または水平な、ある一列に並んだテクセルをサンプリングすると、テクスチャの画像上の直線はそのままの直線としてポリゴン上に描画されます。しかし、それらの各フラグメントが、ある一列に並んだテクセルと、その隣の列に並んだテクセルの境界付近をサンプリングする場合、テクスチャ座標の誤差によって、どちらの列のテクセルをサンプルするかがフラグメントごとに異なり、テクスチャの画像上の直線がデコボコな線としてポリゴン上に描画されてしまうことがその原因です。そのため、両端のテクスチャ座標が 0 ~ 1 であるような矩形ポリゴンをテクスチャと同じサイズで描画するのと同じように、各フラグメントがテクセルの中央をサンプルするようにテクスチャ座標や描画面積を調整することで回避することができます。

11.1.4.3. 縮小時のフィルタに GL_XXX_MIPMAP_LINEAR を指定した場合の注意事項

テクスチャパラメータの GL_TEXTURE_MIN_FILTER に対して GL_XXX_MIPMAP_LINEAR を指定した場合はトライリニアフィルタが有効となり、2 つのレベルのミップマップテクスチャから取得したカラーを用いて補間処理を行ったカラーで描画されます。しかし、この補間処理には計算精度による誤差が発生する可能性があり、たとえ同じ成分値の 2 つのカラーを処理した場合でも、誤差によって異なるカラーが描画される場合があります。

補間処理が行われるのは LOD 計算の結果、2 つのレベルのミップマップテクスチャからカラーを取得しなければならない場合ですので、あるレベルのミップマップテクスチャだけからカラーを取得する場合は補間処理が行われません。そのため、補間処理が行われた部分が、補間処理が行われなかった部分に比べてわずかに暗くなります。その結果、色味の差異がミップマップレベルの境界に沿ってエッジのように描画されてしまいます。

この現象の緩和策として、テクセルカラーの固定値である成分を利用する方法があります。例えば、GL_RGB フォーマットのテクスチャはアルファ成分が 1.0 の固定値ですが、この固定値の成分もトライリニアフィルタによる補間処理が行われたテクセルではわずかに減少してしまいます。一方、補間処理が行われなかったテクセルでは、そのまま 1.0 で描画されます。カラーの補正は、補間処理によって減少したアルファ成分の差分値をテクスチャカラーと乗算した結果をテクスチャカラーに加算することで行います。

この補正処理はテクスチャコンバイナで行うことができます。以下に設定例を示します。

コード 11-4. トライリニアフィルタ時の補正処理
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[0].combineRgb"), 
        GL_MULT_ADD_DMP);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[0].operandRgb"), 
        GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_COLOR);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[0].srcRgb"), 
        GL_TEXTURE0, GL_TEXTURE0, GL_TEXTURE0);

この設定により、補間処理が行われなかった部分は乗算結果が 0.0 で出力されるためテクスチャカラーそのものが出力されることになり、補間処理が行われた部分はアルファ成分の差分値とテクスチャカラーの乗算結果をテクスチャカラーに加算して補正した結果が出力されることになります。この設定では入力ソースのすべてにテクスチャカラーを指定しますので、1 段目のテクスチャコンバイナ(コンバイナ 0)でなければ設定することができません。

GL_RGBA フォーマットのように、成分中に固定値のものがない場合は、固定値の成分を持つ別のテクスチャを用意し、マルチテクスチャとすることで補正します。補正のために用意するテクスチャは、元のテクスチャと同じサイズ、同じミップマップレベル数にし、同じ uv の値が入力されなければなりません。データサイズやキャッシュ効率を考慮し、ETC1 圧縮テクスチャで用意することを推奨します。

11.1.4.4. テクスチャレベル(ミップマップ)パラメータの取得

以下の関数で、現在アクティブになっているテクスチャユニットにバインドされているテクスチャの、ミップマップのレベルごとのパラメータを取得することができます。ただし、プロシージャルテクスチャ用のテクスチャユニット(GL_TEXTURE3)は glActiveTexture() で指定できないため、プロシージャルテクスチャの情報は取得できません。

コード 11-5. テクスチャレベルパラメータの取得
void glGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname,
                              GLfloat *params);
void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname,
                              GLint *params);

取得した値を格納する変数の型が異なるだけで、それぞれの関数で取得する値に違いはありません。

target にはテクスチャの種類を指定します。指定可能な値は以下のとおりです。

表 11-10. テクスチャレベルパラメータを取得するテクスチャの種類の指定

target に指定する値

テクスチャの種類

GL_TEXTURE_2D

2 次元テクスチャ(シャドウテクスチャ、ガステクスチャを含む)

GL_TEXTURE_CUBE_MAP_POSITIVE_X

キューブマップテクスチャ(+X 方向の面)

GL_TEXTURE_CUBE_MAP_NEGATIVE_X

キューブマップテクスチャ(-X 方向の面)

GL_TEXTURE_CUBE_MAP_POSITIVE_Y

キューブマップテクスチャ(+Y 方向の面)

GL_TEXTURE_CUBE_MAP_NEGATIVE_Y

キューブマップテクスチャ(-Y 方向の面)

GL_TEXTURE_CUBE_MAP_POSITIVE_Z

キューブマップテクスチャ(+Z 方向の面)

GL_TEXTURE_CUBE_MAP_NEGATIVE_Z

キューブマップテクスチャ(-Z 方向の面)

level にはパラメータを取得するミップマップのレベルを指定します。0 を指定すると、一番低いレベルの(サイズが一番大きな)テクスチャのパラメータを取得します。その次のレベルは 1 を、さらに次のレベルは 2 を指定することで取得可能です。

pname には取得するパラメータの種類を指定します。指定可能な値と params に格納されるパラメータの対応は以下のとおりです。

表 11-11. 取得するテクスチャレベルパラメータの指定

pname に指定する値

パラメータ

GL_TEXTURE_WIDTH

テクスチャの幅(テクセル数)

GL_TEXTURE_HEIGHT

テクスチャの高さ(テクセル数)

GL_TEXTURE_DEPTH

未対応のため 0 固定

GL_TEXTURE_INTERNAL_FORMAT

テクスチャの内部フォーマット

GL_TEXTURE_BORDER

未対応のため 0 固定

GL_TEXTURE_RED_SIZE

赤成分のビット数(テクセル単位)

GL_TEXTURE_GREEN_SIZE

緑成分のビット数(テクセル単位)

GL_TEXTURE_BLUE_SIZE

青成分のビット数(テクセル単位)

GL_TEXTURE_ALPHA_SIZE

アルファ成分のビット数(テクセル単位)

GL_TEXTURE_LUMINANCE_SIZE

輝度成分のビット数(テクセル単位)

GL_TEXTURE_INTENSITY_SIZE

強度成分のビット数(テクセル単位。シャドウテクスチャのみ)

GL_TEXTURE_DEPTH_SIZE

深度成分のビット数(テクセル単位。シャドウテクスチャのみ)

GL_TEXTURE_DENSITY1_SIZE_DMP

交差が考慮されない密度情報(密度情報 1)のビット数(テクセル単位。ガステクスチャのみ)

GL_TEXTURE_DENSITY2_SIZE_DMP

交差が考慮される密度情報(密度情報 2)のビット数(テクセル単位。ガステクスチャのみ)

GL_TEXTURE_COMPRESSED

圧縮テクスチャかどうか

GL_TRUE: 圧縮テクスチャ
GL_FALSE: 非圧縮テクスチャ

GL_TEXTURE_COMPRESSED_IMAGE_SIZE

level で指定されたミップマップレベルのテクスチャのバイトサイズ(圧縮テクスチャのみ。非圧縮テクスチャに指定した場合は GL_INVALID_OPERATION エラー)

pname GL_TEXTURE_INTERNAL_FORMAT を指定したときに取得するテクスチャの内部フォーマットと、テクセルを構成する各成分のビット数の対応を以下に示します。

表 11-12. 内部フォーマットとテクセルを構成する各成分のビット数の対応

内部フォーマット

アルファ

輝度

強度

深度

密度 1

密度 2

GL_RGBA4

4

4

4

4

 

 

 

 

 

GL_RGB5_A1

5

5

5

1

 

 

 

 

 

GL_RGBA

8

8

8

8

 

 

 

 

 

GL_RGB565

5

6

5

 

 

 

 

 

 

GL_RGB

8

8

8

 

 

 

 

 

 

GL_ALPHA

 

 

 

8

 

 

 

 

 

GL_ALPHA4_EXT

 

 

 

4

 

 

 

 

 

GL_LUMINANCE

 

 

 

 

8

 

 

 

 

GL_LUMINANCE4_EXT

 

 

 

 

4

 

 

 

 

GL_LUMINANCE_ALPHA

 

 

 

8

8

 

 

 

 

GL_LUMINANCE4_ALPHA4_EXT

 

 

 

4

4

 

 

 

 

GL_SHADOW_DMP

 

 

 

 

 

8

24

 

 

GL_GAS_DMP

 

 

 

 

 

 

 

16

16

GL_HILO8_DMP

8

8

 

 

 

 

 

 

 

GL_ETC1_RGB8_NATIVE_DMP

8

8

8

 

 

 

 

 

 

GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP

8

8

8

4

 

 

 

 

 

target pname に不正な値を指定した場合は GL_INVALID_ENUM のエラーを、ロードされていないミップマップレベルを level に指定した場合は GL_INVALID_VALUE のエラーを生成します。

11.1.5. テクスチャの設定によるパフォーマンスへの影響

テクスチャのフォーマットやサイズ、各種設定によって、グラフィックス処理のパフォーマンスに影響することがあります。以下にその傾向を列挙します。

  • 圧縮テクスチャが最も高速に処理され、以降は 1 テクセルあたりのバイトサイズが小さいフォーマットの方が高速に処理されます。
  • サイズが小さいほど高速に処理されます。
  • メモリアクセスの競合が起こるため、同時に使用するテクスチャの枚数が多いほど処理が低速になります。
  • 縮小時のフィルタ設定では、GL_NEARESTGL_LINEARGL_NEAREST_MIPMAP_NEARESTGL_LINEAR_MIPMAP_NEARESTGL_NEAREST_MIPMAP_LINEARGL_LINEAR_MIPMAP_LINEAR のそれぞれが同じ速度で処理されます。ただし、GL_NEAREST(_XXX)GL_LINEAR(_XXX) は 1 ピクセル辺りでフェッチするテクセル数が異なり、GL_NEAREST(_XXX) が 1 テクセル、GL_LINEAR(_XXX) が 4 テクセルですので、メモリ負荷は GL_NEAREST(_XXX) の方が小さくなります。
  • テクスチャを縮小して貼る場合は、ミップマップがある方が高速に処理されます。ただし、ミップマップを使用した場合でもフィルタ設定によっては処理負荷が変わり、GL_*_MIPMAP_LINEARGL_*_MIPMAP_NEAREST に比べて 2 倍程度の処理負荷がかかる場合があります。
  • 拡大時のフィルタ設定では、GL_NEARESTGL_LINEAR はほぼ同じパフォーマンスですが、GL_NEAREST がわずかに高速になる場合があります。
  • ガステクスチャとシャドウテクスチャはミップマップが使えないため、通常テクスチャより処理が低速になります。
  • シャドウテクスチャは、シャドウ専用の特殊なフィルタを使用するため、トライリニアフィルタ(通常テクスチャで縮小フィルタを GL_*_MIPMAP_LINEAR に設定したとき)に相当する処理負荷がかかります。つまり、通常テクスチャ(トライリニアフィルタ設定除く)に比べて 2 倍程度の処理負荷がかかります。
  • プロシージャルテクスチャには設定条件による差はありません。また、一般的な 2D テクスチャよりも高速に処理されます。
  • 複数のテクスチャを使用する場合、すべてのテクスチャが VRAM-A または VRAM-B のどちらか一方にまとめて配置されている方が、分割して配置されているよりも高速に処理されます。
  • 描画結果の上方向と一致するように作成されたテクスチャよりも、フレームバッファの上方向と一致するように作成されたテクスチャの方が高速に処理される可能性があります。これはフラグメントを生成する方向とテクスチャを読み込む方向が一致することで、テクスチャキャッシュのヒット率が向上するためです。上下の反転はパフォーマンスに影響しません。なお、フラグメントは 8x8 ピクセル単位で横方向に処理され、テクスチャは 8x4 テクセル単位で読み出されます。また、3DS の LCD は短い長さの辺を上下端としている点に注意してください。

 

11.1.6. テクスチャキャッシュについて

テクスチャキャッシュのサイズは、1 次キャッシュが 256 Byte、2 次キャッシュが 8 KByte です。キャッシュ内部では、圧縮テクスチャ(ETC フォーマット)だけがそのままのデータフォーマットで扱われ、それ以外のフォーマット(アルファ付き ETC フォーマットを含む)のテクスチャは 32 bit フォーマットに変換されます。

1 次キャッシュはユニットそれぞれに独立していますが、2 次キャッシュは全ユニットで共有しています。

1 次キャッシュにヒットせずに 2 次キャッシュからデータを取得する場合は約 5 サイクル、2 次キャッシュにもヒットせずに VRAM からデータを取得する場合はさらに 30 サイクル程度のペナルティが発生します。ただし、上記のペナルティを隠蔽できるように、テクセルのフェッチを先読みして行うようにハードウェアで実装されています。

テクスチャキャッシュは、4way セットアソシエイティブ方式です。キャッシュラインの数は 16 です。2 次キャッシュのサイズは 8K バイトですので、キャッシュラインは 1 ライン当り 512 バイトとなります。

キャッシュラインは、テクスチャ座標値から計算される、8x4 ブロックアドレス(4x4 テクセル単位のアドレスを 2 で割ったもの)の下位4ビットになります。ETC1 の場合は、4x4 テクセルブロックを 2x2 個並べたブロック単位のアドレスの [5:2] ビットの値になります。同一のキャッシュラインに連続的にアクセスした場合に、キャッシュのスラッシングが発生します。

11.2. コンバイナ

3DS に 6 基搭載されている(テクスチャ)コンバイナは、フラグメントライトのプライマリ、セカンダリのカラー、テクスチャユニットから出力されるテクスチャカラー、頂点カラー、定数カラーなどを合成することができます。ゲームキューブや Wii でのアプリケーション開発経験者でしたら、TEV でのカラー・アルファ合成処理をイメージしていただければ理解しやすいと思います。

OpenGL ES 1.1 ではコンバイナの設定を TexEnv で行っていましたが、3DS では予約ユニフォームへの値の設定で行います。TexEnv のパラメータと予約ユニフォームの対応は以下のようになっています。

表 11-13. OpenGL ES 1.1 の TexEnv のパラメータと予約ユニフォームの対応表

TexEnv

予約ユニフォーム

設定の内容

COMBINE_RGB

dmp_TexEnv[i].combineRgb

カラーのコンバイナ関数

COMBINE_ALPHA

dmp_TexEnv[i].combineAlpha

アルファのコンバイナ関数

SRCn_RGB

dmp_TexEnv[i].srcRgb

カラーのソース

SRCn_ALPHA

dmp_TexEnv[i].srcAlpha

アルファのソース

OPERANDn_RGB

dmp_TexEnv[i].operandRgb

カラーのオペランド

OPERANDn_ALPHA

dmp_TexEnv[i].operandAlpha

アルファのオペランド

RGB_SCALE

dmp_TexEnv[i].scaleRgb

カラーのスケーリング値

ALPHA_SCALE

dmp_TexEnv[i].scaleAlpha

アルファのスケーリング値

TEXTURE_ENV_COLOR

dmp_TexEnv[i].constRgba

定数カラー(アルファ成分あり)

n はソース(0 ~ 2)、i はコンバイナの番号(0 ~ 5)

各コンバイナはソースからの入力をオペランドで加工し、3 つのソースからの入力をコンバイナ関数で計算した結果にスケーリング値を乗算したものを 0.0 ~ 1.0 にクランプして出力します。また、コンバイナへの入力は計算前に 0.0 ~ 1.0 にクランプされており、頂点カラー(プライマリカラー)は絶対値でラスタライズした結果がクランプされた値となります。

カラー成分へのオペレーションは共通した設定でそれぞれの成分(赤、緑、青)に対して行われ、アルファ成分へのオペレーションは独立した設定で行われます。なお、無効化されたテクスチャユニットを参照した場合、入力されるカラー値は不定となります。

図 11-1. コンバイナのオペレーション

srcRgb0 srcRgb1 srcRgb2 operandRgb0 operandRgb1 operandRgb2 CombineRgb srcAlpha0 srcAlpha1 srcAlpha2 operandAlpha0 operandAlpha1 operandAlpha2 CombineAlpha scaleRgb scaleAlpha Input Output

コンバイナへの 3 つの入力ソースは、それぞれ以下のものから選択(重複可)することができます。

  • テクスチャユニットから出力されるテクスチャカラー
  • 定数カラー
  • プライマリカラー
  • フラグメントライトのプライマリカラー
  • フラグメントライトのセカンダリカラー
  • 前段のコンバイナの出力(コンバイナ 0 以外)
  • 前段のコンバイナバッファの出力(コンバイナ 0 以外)
図 11-2. コンバイナへの入力ソース

Combiner0 CombinerBuffer0 Combiner1 CombinerBuffer1 Combiner2 CombinerBuffer2 Combiner3 CombinerBuffer3 Combiner4 CombinerBuffer4 Combiner5 TextureUnit0 TextureUnit1 TextureUnit2 TextureUnit3 Primary Color Fragment Lighting Primary Color Fragment Lighting Secondary Color ConstantRGBA

11.2.1. コンバイナ関数の予約ユニフォーム

コンバイナ関数の予約ユニフォームは dmp_TexEnv[i].combineRgbdmp_TexEnv[i].combineAlpha です。glGetUniformLocation() で取得した予約ユニフォームのロケーションに glUniform1i() で値を設定します。

コンバイナ関数の予約ユニフォームへの設定値は以下のものから選択します。dmp_TexEnv[i].combineRgbdmp_TexEnv[i].combineAlpha に設定可能な値は同じです。

GL_DOT3_RGBA を設定する場合は、そのコンバイナのカラー(combineRgb)とアルファ(combineAlpha)のコンバイナ関数は同じ(GL_DOT3_RGBA)でなければなりません。

表 11-14. コンバイナ関数の予約ユニフォームに設定可能な値

設定値

コンバイナ関数

GL_REPLACE

Src0(デフォルト)

GL_MODULATE

Src0 * Src1

GL_ADD

Src0 + Src1

GL_ADD_SIGNED

Src0 + Src1 - 0.5

GL_INTERPOLATE

Src0 * Src2 + Src1 * (1 - Src2)

GL_SUBTRACT

Src0 - Src1

GL_DOT3_RGB

4 * ((Src0_Red - 0.5) * (Src1_Red - 0.5) + (Src0_Green - 0.5) * (Src1_Green - 0.5) + (Src0_Blue - 0.5) * (Src1_Blue - 0.5))

GL_DOT3_RGBA

4 * ((Src0_Red - 0.5) * (Src1_Red - 0.5) + (Src0_Green - 0.5) * (Src1_Green - 0.5) + (Src0_Blue - 0.5) * (Src1_Blue - 0.5))

GL_ADD_MULT_DMP

(Src0 + Src1) * Src2 ※加算後にクランプ(0.0 ~ 1.0)されてから乗算されます

GL_MULT_ADD_DMP

(Src0 * Src1) + Src2

11.2.2. 入力ソースの予約ユニフォーム

入力ソースの予約ユニフォームは dmp_TexEnv[i].srcRgbdmp_TexEnv[i].srcAlpha です。

glGetUniformLocation() で取得した予約ユニフォームのロケーションに glUniform3i() で値を設定します。先頭から、ソース 0、ソース 1、ソース 2 の順です。

入力ソースの予約ユニフォームへの設定値は以下のものから選択します。dmp_TexEnv[0].srcRgbdmp_TexEnv[0].srcAlphadmp_TexEnv[i].srcRgbdmp_TexEnv[i].srcAlpha に設定可能な値は同じです。

注意:

コンバイナ 0 以外のコンバイナは、3 つの入力ソースのいずれかに GL_CONSTANTGL_PREVIOUSGL_PREVIOUS_BUFFER_DMP のうちの 1 つが指定されていなければなりません。

表 11-15. 入力ソースの予約ユニフォームに設定可能な値

設定値

入力ソース

GL_TEXTURE0

テクスチャユニット 0 のテクスチャカラー

GL_TEXTURE1

テクスチャユニット 1 のテクスチャカラー

GL_TEXTURE2

テクスチャユニット 2 のテクスチャカラー

GL_TEXTURE3

テクスチャユニット 3 のテクスチャカラー

GL_CONSTANT

定数カラー(dmp_TexEnv[i].constRgba)(コンバイナ 0 のデフォルト)

GL_PRIMARY_COLOR

プライマリカラー(頂点カラー)

GL_PREVIOUS

前段のコンバイナの出力(コンバイナ 0 は設定不可。コンバイナ 0 以外のデフォルト)

GL_PREVIOUS_BUFFER_DMP

前段のコンバイナバッファの出力(コンバイナ 0 は設定不可)

GL_FRAGMENT_PRIMARY_COLOR_DMP

フラグメントライトのプライマリカラー

GL_FRAGMENT_SECONDARY_COLOR_DMP

フラグメントライトのセカンダリカラー

11.2.3. オペランドの予約ユニフォーム

オペランドの予約ユニフォームは dmp_TexEnv[i].operandRgbdmp_TexEnv[i].operandAlpha です。

glGetUniformLocation() で取得した予約ユニフォームのロケーションに glUniform3i() で値を設定します。先頭から、ソース 0、ソース 1、ソース 2 の順です。

オペランドの予約ユニフォームへの設定値は以下のものから選択します。

表 11-16. オペランドの予約ユニフォームに設定可能な値

設定値

オペランド

GL_SRC_COLOR

Color(operandAlpha は設定不可。operandRgb のデフォルト)

GL_ONE_MINUS_SRC_COLOR

1 - Color(operandAlpha は設定不可)

GL_SRC_ALPHA

Alpha(operandAlpha のデフォルト)

GL_ONE_MINUS_SRC_ALPHA

1 - Alpha

GL_SRC_R_DMP

Color_Red

GL_ONE_MINUS_SRC_R_DMP

1 - Color_Red

GL_SRC_G_DMP

Color_Green

GL_ONE_MINUS_SRC_G_DMP

1 - Color_Green

GL_SRC_B_DMP

Color_Blue

GL_ONE_MINUS_SRC_B_DMP

1 - Color_Blue

11.2.4. スケーリング値の予約ユニフォーム

スケーリング値の予約ユニフォームは dmp_TexEnv[i].scaleRgbdmp_TexEnv[i].scaleAlpha です。

glGetUniformLocation() で取得した予約ユニフォームのロケーションに glUniform1f() で値を設定します。

スケーリング値の予約ユニフォームへの設定値は以下のものから選択します。

表 11-17. スケーリング値の予約ユニフォームに設定可能な値

設定値

スケーリング

1.0

コンバイナの出力はそのまま(デフォルト)

2.0

コンバイナの出力を 2 倍にする(0.0 ~ 1.0 にクランプ)

4.0

コンバイナの出力を 4 倍にする(0.0 ~ 1.0 にクランプ)

11.2.5. 定数カラーの予約ユニフォーム

定数カラーの予約ユニフォームは dmp_TexEnv[i].constRgba です。glGetUniformLocation() で取得した予約ユニフォームのロケーションに glUniform4f() で値を設定します。先頭から R、G、B、A の順です。

定数カラーの予約ユニフォームのデフォルト設定値は (R, G, B, A) = (0.0, 0.0, 0.0, 0.0) です。

11.2.6. コンバイナの設定例

設定例として、プライマリカラーをそのまま描画するために、コンバイナ 2 でプライマリカラーを参照して、そのまま出力する接続の例を以下に示します。

コンバイナ 2 の入力ソース 0 にプライマリカラー(GL_PRIMARY_COLOR)を、オペランド 0 に入力ソースのカラーそのまま(GL_SRC_COLOR)を、コンバイナ関数に入力ソース 0 をそのまま出力(GL_REPLACE)を、スケールに 1.0 を設定すると、コンバイナの出力はプライマリカラーだけになり、それ以外の影響を受けなくなります。この設定では、コンバイナ 0 と 1 は出力結果に影響を与えません。

接続図は以下のようになっています。

図 11-3. コンバイナの設定例 1

TextureUnit0 TextureUnit1 TextureUnit2 TextureUnit3 Primary Color Fragment Lighting Primary Color Fragment Lighting Secondary Color ConstantRGBA Combiner0 GL_REPLACE Combiner1 GL_REPLACE Combiner2 GL_REPLACE GL_PRIMARY_COLOR

実際にプログラムで指定する際のコード例を以下に示します。

コード 11-6. コンバイナの設定コード例 1
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].srcRgb"), 
        GL_PRIMARY_COLOR, GL_PREVIOUS, GL_PREVIOUS);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].srcAlpha"), 
        GL_PRIMARY_COLOR, GL_PREVIOUS, GL_PREVIOUS);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[2].combineRgb"), 
        GL_REPLACE);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[2].combineAlpha"), 
        GL_REPLACE);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].operandRgb"), 
        GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].operandAlpha"), 
        GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
glUniform1f(glGetUniformLocation(program, "dmp_TexEnv[2].scaleRgb"), 1.0);
glUniform1f(glGetUniformLocation(program, "dmp_TexEnv[2].scaleAlpha"), 1.0);

より複雑な設定例として、テクスチャ 0 とテクスチャ 1 の出力をコンバイナ 1 で加算し、その結果にコンバイナ 2 でプライマリカラーを乗算するような設定を示します。

図 11-4. コンバイナの設定例 2

TextureUnit0 TextureUnit1 TextureUnit2 TextureUnit3 Primary Color Fragment Lighting Primary Color Fragment Lighting Secondary Color ConstantRGBA Combiner0 GL_REPLACE Combiner1 GL_ADD Combiner2 GL_MODULATE GL_PRIMARY_COLOR GL_TEXTURE0 GL_TEXTURE1

コード 11-7. コンバイナの設定コード例 2
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].srcRgb"), 
        GL_TEXTURE0, GL_TEXTURE1, GL_PREVIOUS);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].srcAlpha"), 
        GL_TEXTURE0, GL_TEXTURE1, GL_PREVIOUS);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[1].combineRgb"), 
        GL_ADD);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[1].combineAlpha"), 
        GL_ADD);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].operandRgb"), 
        GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].operandAlpha"), 
        GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].srcRgb"), 
        GL_PREVIOUS, GL_PRIMARY_COLOR, GL_PREVIOUS);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].srcAlpha"), 
        GL_PREVIOUS, GL_PRIMARY_COLOR, GL_PREVIOUS);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[2].combineRgb"), 
        GL_MODULATE);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[2].combineAlpha"), 
        GL_MODULATE);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].operandRgb"), 
        GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].operandAlpha"), 
        GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);

11.3. コンバイナバッファ

最終のコンバイナ(コンバイナ 5 )以外にはコンバイナバッファが並列して設置されています。コンバイナバッファは前段のコンバイナまたはコンバイナバッファの出力を入力ソースに選択することができ、前段のコンバイナバッファの出力を受け継いでいけば、後段のコンバイナで直前のコンバイナより前段にあるコンバイナの出力を入力ソースに選択することができます。

11.3.1. コンバイナバッファの予約ユニフォーム

コンバイナバッファ 0 への入力はありませんので、予約ユニフォーム dmp_TexEnv[0].bufferColor で初期値としての定数カラーを設定します。定数カラーは glGetUniformLocation() で取得した予約ユニフォームのロケーションに glUniform4f() で値を設定します。先頭から R、G、B、A の順です。

コンバイナバッファ 0 の定数カラーのデフォルト設定値は (R, G, B, A) = (0.0, 0.0, 0.0, 0.0) です。

コンバイナバッファ 1 ~ 4 への入力ソースは、前段のコンバイナの出力か前段のコンバイナバッファの出力から選択することができます。予約ユニフォームは dmp_TexEnv[i].bufferInputi は 1 ~ 4)で、カラー成分とアルファ成分の入力を個別に選択することができます。glGetUniformLocation() で取得した予約ユニフォームのロケーションに glUniform2i() で値を設定します。先頭からカラー成分、アルファ成分の順です。

コンバイナバッファへの入力ソースの予約ユニフォームへの設定値は以下のものから選択します。

表 11-18. コンバイナバッファへの入力ソースの予約ユニフォームに設定可能な値

設定値

入力ソース

GL_PREVIOUS

前段のコンバイナの出力(デフォルト)

GL_PREVIOUS_BUFFER_DMP

前段のコンバイナバッファの出力

11.3.2. コンバイナバッファの設定例

コンバイナバッファを使用した設定例として、テクスチャ 0 にフラグメントライティングのプライマリカラーを乗算した結果とテクスチャ 1 にフラグメントライティングのセカンダリカラーを乗算した結果を加算して出力する接続の例を以下に示します。

図 11-5. コンバイナバッファの設定例

TextureUnit0 TextureUnit1 TextureUnit2 TextureUnit3 Primary Color Fragment Lighting Primary Color Fragment Lighting Secondary Color ConstantRGBA Combiner0 GL_MODULATE Combiner1 GL_MODULATE Combiner2 GL_ADD GL_TEXTURE0 CombinerBuffer1 GL_PREVIOUS CombinerBuffer0 GL_FRAGMENT_PRIMARY_COLOR_DMP GL_TEXTURE1 GL_FRAGMENT_SECONDARY_COLOR_DMP CombinerBuffer2

実際にプログラムで指定する際のコード例を以下に示します。

コード 11-8. コンバイナバッファの設定コード例
// Combiner 0
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[0].srcRgb"), 
        GL_TEXTURE0, GL_FRAGMENT_PRIMARY_COLOR_DMP, GL_PREVIOUS);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[0].srcAlpha"), 
        GL_TEXTURE0, GL_PREVIOUS, GL_PREVIOUS);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[0].combineRgb"), 
        GL_MODULATE);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[0].combineAlpha"), 
        GL_REPLACE);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[0].operandRgb"), 
        GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[0].operandAlpha"), 
        GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
// CombinerBuffer 1
glUniform2i(glGetUniformLocation(program, "dmp_TexEnv[1].bufferInput"), 
        GL_PREVIOUS, GL_PREVIOUS);
// Combiner 1
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].srcRgb"), 
        GL_TEXTURE1, GL_FRAGMENT_SECONDARY_COLOR_DMP, GL_PREVIOUS);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].srcAlpha"), 
        GL_TEXTURE1, GL_PREVIOUS, GL_PREVIOUS);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[1].combineRgb"), 
        GL_MODULATE);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[1].combineAlpha"), 
        GL_REPLACE);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].operandRgb"), 
        GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[1].operandAlpha"), 
        GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);
// Combiner 2
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].srcRgb"), 
        GL_PREVIOUS_BUFFER_DMP, GL_PREVIOUS, GL_PREVIOUS);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].srcAlpha"), 
        GL_PREVIOUS_BUFFER_DMP, GL_PREVIOUS, GL_PREVIOUS);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[2].combineRgb"), 
        GL_ADD);
glUniform1i(glGetUniformLocation(program, "dmp_TexEnv[2].combineAlpha"), 
        GL_REPLACE);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].operandRgb"), 
        GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR);
glUniform3i(glGetUniformLocation(program, "dmp_TexEnv[2].operandAlpha"), 
        GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA);

11.4. プロシージャルテクスチャ

プロシージャルテクスチャは従来のテクスチャと異なり、画像を参照せず、手続き的計算によりテクセルの色が決定されます。プロシージャルテクスチャは、完全に秩序を持ったパターンや、ややランダムで秩序を伴うパターンで効果を発揮します。テクスチャ画像にアクセスをすることがないため、メモリアクセスの競合を回避したり、コンテンツサイズを抑制したりといった効果があります。

プロシージャルテクスチャを扱うことができるのはテクスチャユニット 3 だけで、テクスチャユニット 3 はプロシージャルテクスチャ専用のテクスチャユニットになっています。計算によりテクセル色を決定しますが、テクスチャ座標 u、v に対応するテクセル色を決定するという意味では通常のテクスチャと同様の働きをしていると考えることもできます。

プロシージャルテクスチャは予約フラグメントシェーダの一部でもありますので、パラメータの設定は予約ユニフォームへの glUniform*() の呼び出しで行います。

11.4.1. プロシージャルテクスチャユニット

プロシージャルテクスチャユニットは 3 つの計算部で構成されています。入力に近い側から、乱数生成部、クランプ部、マッピング部と呼びます。乱数生成部がテクスチャ座標 u、v に揺らぎを与え、クランプ部がパターンの鏡面対称、繰り返しを決定し、マッピング部が u、v 座標値からテクセル色を計算します。

図 11-6. プロシージャルテクスチャユニットの構成

乱数 クランプ G(u, v) F(g) Color(f) 乱数生成部 クランプ部 マッピング部 color

入力されたテクスチャ座標は上図のように処理されていますが、目的の画像を得るためのパラメータを設定するときには、以下の手順で行った方が直感的で理解しやすいでしょう。

  1. プロシージャルテクスチャの有効化
  2. RGBA 共有モードまたはアルファ独立モードの設定
    G(u, v) および F(g) の設定に相当します。
  3. 基本形状の選択
    G(u, v) の選択に相当します。
  4. 基本色の設定
    色はカラー参照テーブルとして設定します。Color(f) の設定に相当します。
  5. 基本形状とカラー参照テーブルの関係の設定
    手順 3 の基本形状と手順 4 のカラー参照テーブルがどのように対応するか決定します。F(g) の設定に相当します。
  6. 乱数パラメータの選択
    必要な場合には乱数を有効にして、乱数の影響の大きさを決めます。不要な場合は乱数を無効にします。乱数生成部に相当します。乱数の有効、無効に関わらず、u と v は絶対値化されてクランプ部に出力されます。
  7. 繰り返しおよび対称性の設定
    クランプの設定に相当します。

11.4.2. プロシージャルテクスチャの有効化

プロシージャルテクスチャで使用するテクスチャユニット 3 の有効・無効の設定は、予約ユニフォーム(dmp_Texture[3].samplerType)への値の設定で行います。glActiveTexture() によるユニット選択や glEnable() によるテクスチャ種別の選択はエラーとなりますので注意してください。

有効にする場合は GL_TEXTURE_PROCEDURAL_DMP を、無効にする場合は GL_FALSEglUniform1i() で設定してください。テクスチャの種別として GL_TEXTURE_PROCEDURAL_DMP 以外には対応していません。

コード 11-9. プロシージャルテクスチャの有効化
glUniform1i(
    glGetUniformLocation(s_PgID, "dmp_Texture[3].samplerType"), 
    GL_TEXTURE_PROCEDURAL_DMP);

11.4.3. RGBA 共有モード / アルファ独立モードの設定

アルファ成分のマッピング部での計算に使用する関数を RGB 成分の設定と共有(RGBA 共有モード)するか、独立して設定(アルファ独立モード)するかを選択します。アルファ独立モードを選択した場合、マッピング部の G 関数と F 関数を 2 つずつ設定しなければなりません。とりあえず画像を出力してみたいという場合は、RGBA 共有モードを使用した方が設定は容易です。

予約ユニフォーム(dmp_Texture[3].ptAlphaSeparate)に glUniform1i()GL_FALSE を設定した場合は RGBA 共有モード、GL_TRUE を設定した場合はアルファ独立モードが選択されます。デフォルトは RGBA 共有モードです。

図 11-7. アルファ独立モード時のマッピング部

Grgb(u, v) Frgb(grgb) Color(frgb) マッピング部 color Ga(u, v) Fa(ga) fa alpha

11.4.4. 基本形状の選択

プロシージャルテクスチャの基本形状をマッピング部の G 関数によって決定します。

表 11-19 で掲載している基本形状は以下の割り当てで色付けされています。

表 11-19. G 関数の設定値と選択される関数および基本形状

設定値

選択される関数

基本形状

GL_PROCTEX_U_DMP
(デフォルト)

u

GL_PROCTEX_V_DMP

v

GL_PROCTEX_U2_DMP

u2

GL_PROCTEX_V2_DMP

v2

GL_PROCTEX_ADD_DMP

(u + v) / 2

GL_PROCTEX_ADD2_DMP

(u2 + v2) / 2

GL_PROCTEX_ADDSQRT2_DMP

sqrt(u2 + v2)

GL_PROCTEX_MIN_DMP

min(u, v)

GL_PROCTEX_MAX_DMP

max(u, v)

GL_PROCTEX_RMAX_DMP

((u + v) / 2 + sqrt(u2 + v2)) / 2

基本形状はテクスチャ座標に -1.0 ~ 1.0(中心が 0.0)、繰り返しの指定に GL_MIRRORED_REPEAT を設定して描画されたものです。

G 関数選択のための予約ユニフォームは、RGB 成分が dmp_Texture[3].ptRgbMap、アルファ成分が dmp_Texture[3].ptAlphaMap です。それぞれの予約ユニフォームに対して、glUniform1i() で設定します。

dmp_Texture[3].ptAlphaMap への設定はアルファ独立モードでのみ有効です。

木目ならば GL_PROCTEX_U_DMPGL_PROCTEX_V_DMP を、年輪ならば GL_PROCTEX_ADDSQRT2_DMP を選択するなど、目的とするテクスチャ画像に近い形状を選んでください。

11.4.5. カラー参照テーブルの設定

カラー参照テーブルは G 関数と F 関数を経て計算された値を実際のテクセル色へと変換するためのテーブルで、RGBA の各成分で別々に設定することができます。

カラー参照テーブルの内容は LOD を使用するかどうかで異なります。

図 11-8. LOD の使用によるカラー参照テーブルの内容の違い

ptTexOffset ColorTable1 ptTexWidth ColorTable2 ColorTable1 ColorTable2 width T ΔT ptTexWidth 256 + ptTexOffset ptTexOffset = 0 ColorTable Level 0 ptTexWidth = 128 width = 512 T ΔT LODを使用する LODを使用しない ColorTable Level 1 Level 2 Level 6 ColorTable Level 0 ColorTable Level 1 Level 2 Level 6 ptTexWidth = 128

LOD を使用しない場合、カラー参照テーブルには部分配列として複数のカラーテーブルを格納することができます。オフセットとテーブルの幅を変更することで、同じ計算結果から色合いの異なるテクスチャを描画することもできます。

カラー参照テーブルは最大 512 要素の参照テーブルで、256 要素を境にして前半にはカラーテーブル、後半には前半で格納したカラーテーブルの要素間の差分値を格納します。差分値は必ず 257 要素目から格納しなければならないので、カラー参照テーブルの要素数は "256 +(実際に参照されるカラーテーブルの要素数)+(カラーテーブルの先頭オフセット)" で定義されます。要素数の計算で対象となるのは最後のカラーテーブルです。

実際に参照されるカラーテーブルの幅(dmp_Texture[3].ptTexWidth)には、128 までの 2 のべき乗を glUniform1i() で設定します。カラーテーブルの先頭オフセット(dmp_Texture[3].ptTexOffset)には、0 ~ 128 の整数を glUniform1i() で設定します。

LOD を使用する場合、カラーテーブルの幅とオフセットは、それぞれ 128 と 0 でなければなりません。LOD のレベルに対応して、実際に参照されるカラーテーブルが決定されます。カラー参照テーブルの要素数は最大の 512 固定です。

表 11-20. LOD のレベルとカラーテーブルの対応

LOD のレベル

開始位置

0

0

128

1

128

64

2

192

32

3

224

16

4

240

8

5

248

4

6

252

2

7.7. 参照テーブルのロード」で説明したとおり、参照テーブルは glTexImage1D() を呼び出して配列からロードします。カラー参照テーブルの要素数の大きさの浮動小数点配列を用意して、前半部分にカラーテーブルの要素(0.0 ~ 1.0)を格納し、配列の後半(ΔT)には前半 256 要素に格納したカラーテーブル(T)の要素間の差分値を格納していきます。カラーテーブルの要素数を size、先頭オフセットを offset 要素を Ci 、変換関数を func() とすれば、要素と差分値の計算式は以下の式で表されます。

C i offset size func

差分値の最後はカラーテーブルの収束値と最終要素との差分を計算して格納するか、単に 0.0 を格納してください。

glTexImage1D() の呼び出しはカラー参照テーブルの要素数を最大の 512、カラー参照テーブルを格納した配列を data、設定する参照テーブル番号を 0 とすれば以下のコードで行うことができます。

コード 11-10. カラー参照テーブルのロード
glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 512, 0, 
             GL_LUMINANCEF_DMP, GL_FLOAT, data);

RGBA の各成分で使用するカラー参照テーブルは、glUniform1i() で参照テーブル番号を以下の予約ユニフォームに指定します。ここで指定する参照テーブル番号は GL_LUT_TEXTUREi_DMPi(0 ~ 31) が表す数値で、テクスチャの名前(ID)や GL_LUT_TEXTUREi_DMP を直接指定するわけではないことに注意してください。

表 11-21. カラー参照テーブルを指定する予約ユニフォーム

予約ユニフォーム

設定する値

dmp_Texture[3].ptSamplerR

赤成分のカラー参照テーブルとする参照テーブル番号を指定する。

dmp_Texture[3].ptSamplerG

緑成分のカラー参照テーブルとする参照テーブル番号を指定する。

dmp_Texture[3].ptSamplerB

青成分のカラー参照テーブルとする参照テーブル番号を指定する。

dmp_Texture[3].ptSamplerA

アルファ成分のカラー参照テーブルとする参照テーブル番号を指定する。

どの予約ユニフォームも 0 ~ 31 の値を指定します。

アルファ独立モード時は dmp_Texture[3].ptSamplerA の設定が無視されます。

プロシージャルテクスチャのカラー参照テーブルにも、縮小時のフィルタには通常のテクスチャと同様のフィルタを適用することができます。予約ユニフォーム(dmp_Texture[3].ptMinFilter)に glUniform1i() で設定する値を、以下の表から選択します。

表 11-22. カラー参照テーブルのフィルタ

設定する値

適用するフィルタ

GL_NEAREST

u, v 方向はニアレスト、LOD なし

GL_LINEAR

u, v 方向はリニア、LOD なし(デフォルト)

GL_NEAREST_MIPMAP_NEAREST

u, v 方向はニアレスト、LOD はニアレスト

GL_NEAREST_MIPMAP_LINEAR

u, v 方向はニアレスト、LOD はリニア

GL_LINEAR_MIPMAP_NEAREST

u, v 方向はリニア、LOD はニアレスト

GL_LINEAR_MIPMAP_LINEAR

u, v 方向はリニア、LOD はリニア

カラー参照テーブルの参照時に LOD バイアスをかけることができます。0.0 ~ 6.0 の範囲の値を、予約ユニフォーム(dmp_Texture[3].ptTexBias)に glUniform1f() で設定します。0.0 で無効化され、デフォルトは 0.5 に設定されています。

11.4.6. 基本形状とカラー参照テーブルとの対応関係の設定

基本形状を選択した G 関数と基本色を設定したカラー参照テーブルとの対応関係は F 関数で設定されます。F 関数は、G 関数からの出力(0.0 ~ 1.0)をカラー参照テーブルの参照値(0.0 ~ 1.0)へマッピングする参照テーブルとして設定します。参照テーブルは 256 要素の大きさで、128 要素を境にして前半にはマッピングテーブル、後半には前半で格納したマッピングテーブルの要素間の差分値を格納します。形状とカラーの対応関係の設定ですので、同じ形状とカラー参照テーブルを用いていても、マッピングテーブルを変更することで様相の異なるテクスチャとして描画することができます。F 関数に F(x)=x や F(x)=x2 のように単純な計算結果を用いたり、飛び飛びの値でインデックスのように用いたりするだけでも出力結果は大きく異なるものになる可能性があります。

カラー参照テーブルと同様に、F 関数のマッピングテーブルは glTexImage1D() を呼び出して、配列から参照テーブルとしてロードします。マッピングテーブルの要素数(256)の大きさの浮動小数点配列を用意して、前半部分にマッピングテーブルの要素(0.0 ~ 1.0)を格納し、配列の後半には前半の 128 要素に格納したマッピングテーブルの要素間の差分値を格納していきます。マッピングテーブルの要素を Fi 、変換関数を func() とすれば、要素と差分値の計算式は以下の式で表されます。

glTexImage1D() の呼び出しはマッピングテーブルの要素数を 256、マッピングテーブルを格納した配列を data、設定する参照テーブル番号を 0 とすれば以下のコードで行うことができます。

コード 11-11. マッピングテーブルのロード
glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 256, 0, 
             GL_LUMINANCEF_DMP, GL_FLOAT, data);

F 関数として使用するマッピングテーブルは、glUniform1i() で参照テーブル番号を以下の予約ユニフォームに指定します。ここで指定する参照テーブル番号は GL_LUT_TEXTUREi_DMPi(0 ~ 31) が表す数値で、テクスチャの名前(ID)や GL_LUT_TEXTUREi_DMP を直接指定するわけではないことに注意してください。

表 11-23. マッピングテーブルを指定する予約ユニフォーム

予約ユニフォーム

設定する値

dmp_Texture[3].ptSamplerRgbMap

RGB の F 関数とする参照テーブル番号を指定する。

dmp_Texture[3].ptSamplerAlphaMap

アルファの F 関数とする参照テーブル番号を指定する。

どちらの予約ユニフォームも 0 ~ 31 の値を指定します。
dmp_Texture[3].ptSamplerAlphaMap の設定はアルファ独立モード時のみ有効です。

11.4.7. 乱数パラメータの選択

プロシージャルテクスチャのランダム要素として、G 関数に入力されるテクスチャ座標 u と v に揺らぎ(ノイズ)を与えることができます。ノイズは基本形状に影響を与えます。例えば G 関数が GL_PROCTEX_U_DMP であるとき、テクスチャ座標 u にノイズによる影響を与えれば、直線でしか描画できなかった木目がより自然な歪みを持って描画できるようになります。

ノイズの有効・無効の設定は、予約ユニフォーム(dmp_Texture[3].ptNoiseEnable)への値の設定で行います。有効にする場合は GL_TRUE を、無効にする場合は GL_FALSEglUniform1i() で設定してください。

コード 11-12. ノイズの有効化
glUniform1i(
    glGetUniformLocation(s_PgID, "dmp_Texture[3].ptNoiseEnable"), GL_TRUE);

ノイズを与える関数はブラックボックスになっていますが、アプリケーションから波の周波数(F)、位相(P)、振幅(A)の 3 パラメータを与えることで制御することができます。F パラメータは揺らぎの緩急を調整し、大きくすれば険しく、小さくすれば緩やかな波になります。P パラメータは揺らぎの開始位置を変更します。海面のテクスチャなどを描画する際には、P パラメータだけを変更して波の変化を表現することができます。A パラメータを大きくすれば揺らぎの影響が大きくなり、基本形状はより崩れます。

F、P、A の 3 パラメータは u 成分、v 成分で別々のパラメータを設定することができます。

表 11-24. ノイズの予約ユニフォーム

予約ユニフォーム

設定する値

dmp_Texture[3].ptNoiseU

u 成分の F、P、A パラメータを指定する。A パラメータのみ -8.0 ~ 8.0 の範囲にクランプされます。

(F-parameter, P-parameter, A-parameter)

デフォルト (0.0, 0.0, 0.0)

dmp_Texture[3].ptNoiseV

v 成分の F、P、A パラメータを指定する。A パラメータのみ -8.0 ~ 8.0 の範囲にクランプされます。

(F-parameter, P-parameter, A-parameter)

デフォルト (0.0, 0.0, 0.0)

揺らぎのパラメータ以外にも、ノイズを与える関数にノイズ変調と呼ばれる乱数の連続性の変化を制御することができます。ノイズ変調(ノイズ連続性関数)は参照テーブルで指定し、これをノイズ変調テーブルと呼びます。ノイズ関数は与えられたノイズ変調テーブルを使って、計算だけでは離散的な値となってしまう揺らぎを自然な値にしようとします。ノイズ連続性関数には 3x2 - 2x3 のように 0.0 と 1.0 付近で緩やかに変化する関数が適しています。

カラー参照テーブルと同様に、ノイズ変調テーブルは glTexImage1D() を呼び出して配列からロードします。ノイズ変調テーブルの要素数(256)の大きさの浮動小数点配列を用意して、前半部分にノイズ変調テーブルの要素(0.0 ~ 1.0)を格納し、配列の後半には前半の 128 要素に格納したノイズ変調テーブルの要素間の差分値を格納していきます。ノイズ変調テーブルの要素を Ni 、変換関数を func() とすれば、要素と差分値の計算式は以下の式で表されます。

glTexImage1D() の呼び出しはノイズ変調テーブルの要素数を 256、ノイズ変調テーブルを格納した配列を data、設定する参照テーブル番号を 0 とすれば以下のコードで行うことができます。

コード 11-13. ノイズ変調テーブルのロード
glTexImage1D(GL_LUT_TEXTURE0_DMP, 0, GL_LUMINANCEF_DMP, 256, 0, 
                 GL_LUMINANCEF_DMP, GL_FLOAT, data);

ノイズ連続性関数として使用するノイズ変調テーブルは、参照テーブル番号を以下の予約ユニフォームへ glUniform1i() によって指定します。ここで指定する参照テーブル番号は GL_LUT_TEXTUREi_DMPi(0 ~ 31) が表す数値で、テクスチャの名前(ID)や GL_LUT_TEXTUREi_DMP を直接指定するわけではないことに注意してください。

表 11-25. ノイズ変調テーブルを指定する予約ユニフォーム

予約ユニフォーム

設定する値

dmp_Texture[3].ptSamplerNoiseMap

ノイズ連続性関数とする参照テーブル番号を指定する。

0 ~ 31

ノイズの F、P、A の 3 パラメータが出力結果にどのような影響を与えるのかを、ノイズの影響がないときには同心円で描画されるプロシージャルテクスチャに対して、u, v 両方向に関して各パラメータを変化させたときの描画結果で紹介します。これらの描画に際して、ノイズ連続性関数には F(x) = x を使用しています。

図 11-9 は A パラメータのみを変化させたときの描画結果です。そのほかのパラメータについては、F = 0.3、P = 0.0 に設定しています。A が大きいほど大きく波打ちますが、円周上で影響を受ける箇所に変化がほとんどないことに注目してください。

図 11-9. A パラメータの影響

図 11-10 は F パラメータのみを変化させたときの描画結果です。そのほかのパラメータについては、A = 0.3、P = 0.0 に設定しています。F が大きいほど揺らぎの周波数が高くなり、円周上で影響を受ける箇所の間隔が狭くなっていることに注目してください。また、F パラメータはノイズの計算時に絶対値が使用されるため、符号を反転させても結果は変わりません。

図 11-10. F パラメータの影響

図 11-11 は P パラメータのみを変化させたときの描画結果です。そのほかのパラメータについては、A = 0.3、F = 0.3 に設定しています。P が変化すると揺らぎの形状のみが変化していることに注目してください。P パラメータを変化させることで、プロシージャルテクスチャにアニメーションのような変化をもたらすことができます。

P パラメータを変化させてアニメーションさせる場合、P パラメータに大きな値を設定すると、P パラメータの小さな変化が揺らぎの形状に影響を与えなくなります。これはハードウェアの計算精度に起因する現象です。例えば、フレームごとに一定の値を P パラメータに加算してノイズの変化を使ったアニメーションを行う場合は、P パラメータが大きな値になる前に小さな値に戻す必要があります。F パラメータと P パラメータがともに正の数である場合、F パラメータと P パラメータの乗算結果が 16 の倍数となるときと、P パラメータに 0.0 を設定したときは同じ結果を得ることができるという特性があります。つまり、乗算結果が 16 となるときに P パラメータを 0 に戻すことで、アニメーションの連続性を保つことができます。ただし、F パラメータに大きな値が設定されているときは、P パラメータに 0 を指定した場合と、乗算結果が 16 となる場合で同じ形状にならない場合があります。

F パラメータと A パラメータが固定値かつ、(|u| + u の位相)および(|v| + v の位相)の符号が変わらない範囲で P パラメータの値を変化させた場合、F×P が任意の値 X となる場合と、X+16 となる場合とで同じノイズ結果を得ることができます。ただし、ノイズ計算の過程における計算精度により、F パラメータに大きな値を設定すると、上記の場合でも同じ乱数結果を得られない可能性があります。また、P パラメータに大きな値が設定されていると、細かな値の変化がノイズ結果に反映されなくなる場合があります。

図 11-11. P パラメータの影響

11.4.8. 繰り返しおよび対称性の設定

通常のテクスチャで設定したラッピングモードと同様の機能が、プロシージャルテクスチャにもあります。クランプ計算部と呼ばれ、設定可能なモードにはパルスやゼロクランプなどの専用モードがあります。また、繰り返しの途中でテクスチャ座標の整数部分が同じ部分をブロックにしてずらす、シフト計算部もあります。

クランプ計算部ではテクスチャ座標が 0.0 ~ 1.0 の範囲に収まらない部分を、どのように範囲内の値に変換するのかをクランプモードによって決定します。

表 11-26. クランプモード

クランプモード

座標値のクランプ

GL_SYMMETRICAL_REPEAT_DMP

GL_MIRRORED_REPEAT

GL_PULSE_DMP

GL_CLAMP_TO_EDGE
(デフォルト)

GL_CLAMP_TO_ZERO_DMP

テクスチャ座標の u 成分と v 成分で別々のクランプモードを設定することができます。設定するには、予約ユニフォーム dmp_Texture[3].ptClampU または dmp_Texture[3].ptClampV に対して glUniform1i() を呼び出します。

GL_SYMMETRICAL_REPEAT_DMP は、同じ画像が格子状に並びます。GL_MIRRORED_REPEAT は、偶数番目が鏡のように反転します。GL_PULSE_DMP は、描画に利用しようとする画素に最も近いテクスチャの端の画素を拾います。GL_CLAMP_TO_EDGE は、-1.0 ~ 1.0 の範囲内ではテクスチャ内部の画像を参照し、範囲外ではテクスチャの端の画素を参照します。GL_CLAMP_TO_ZERO_DMP は -1.0 ~ 1.0 の範囲内(-1.0 および 1.0 を含まず)ではテクスチャ画像を参照し、範囲外(-1.0 および 1.0 を含む)では座標 0 の画像を参照します。

シフト計算部では、シフトモードによってどのように座標をシフト操作するのかを決定し、クランプモードによってシフト幅が変化します。この処理はクランプ計算部の前に適用され、同じ画像が連続して描画されるのを防ぐことができます。

表 11-27. シフトモード

シフトモード

シフト計算

シフト幅

GL_NONE_DMP
(デフォルト)

シフト計算なし

なし

GL_ODD_DMP

整数部が奇数から偶数へ変化する座標でシフト

GL_MIRRORED_REPEAT のみ 1.0、ほかは 0.5

GL_EVEN_DMP

整数部が偶数から奇数へ変化する座標でシフト

GL_MIRRORED_REPEAT のみ 1.0、ほかは 0.5

テクスチャ座標の u 成分と v 成分で別々のシフトモードを設定することができます。設定するには、予約ユニフォーム dmp_Texture[3].ptShiftU または dmp_Texture[3].ptShiftV に対して glUniform1i() を呼び出します。

図 11-12. シフトモードの違いとクランプモードによるシフト幅の違い

1.0 0.0 2.0 3.0 4.0 1.0 0.0 2.0 3.0 4.0 GL_NONE_DMP GL_EVEN_DMP GL_ODD_DMP GL_NONE_DMP GL_EVEN_DMP GL_ODD_DMP GL_SYMMETRICAL_REPEAT_DMP GL_MIRRORED_REPEAT 0.5 0.5 1.0 1.0