マルチテクスチャ(MultiTexture)

SAMPLE http://ooo.iiyudana.net/bin/gl/multi_texture.exe( マルチテクスチャ )


全体の流れ

DEP glext.h VER 1.3 DESC ひとつの物( Primitive )に絵( Texture )をたくさん貼り付ける [0][1][2][3][4][5][6][7] テクスチャユニット( サンプラー )は8つあり、テクスチャオブジェクトを設定することで 一度の描画で複数のテクスチャを参照できる。 ペイントソフトのレイヤーと同じ概念。 POINT TextureObject を 各 Unit に bind する OpenGL は GL_TEXTURE0 から順にフラグメントに適用する テクスチャマトリックスは ユニットごとに持つ POINT テクスチャユニットの設定に関連したAPIは以下のもの。 現在のユニットの影響を受けるため、把握しておくこと。 ユニットをサンプラーとして考えると必要な設定が理解しやすい。
[.] glTexGen(); // tc 自動生成 Param [.] glEnable( GEN_S ); // UV 自動生成の各成分ごとの ON/OFF [.] glEnable( GL_TEXTURE_2D ); // サンプリング処理の ON/OFF [.] Texture Enviroment ( glTexEnv ) [.] TextureMatrix [.] バインドするテクスチャオブジェクトの指定
DEFAULT GL_TEXTURE0
# include <GL/glext.h> void App::init() { PFNGLACTIVETEXTUREPROC glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture"); // 操作するテクスチャユニットを指定する // 一枚のみを利用しているときはこれが暗黙の指定になっている。 glActiveTexture( GL_TEXTURE0 ); // UNIT0 にテクスチャオブジェクトをセットする glBindTexture( GL_TEXTURE_2D, id ); // ブレンド方法の指定 // 次の設定が最も simple blend 方法 ( 各 unit にすること ) glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // 2D Texure をサンプリング処理を有効化する。 glEnable( GL_TEXTURE_2D ); // 2 番目のユニットを指定 glActiveTexture( GL_TEXTURE1 ); // 上と同じように設定するだけ glBindTexture( GL_TEXTURE_2D, id2 ); glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); }
// 描画時は各UNITごとに Texture座標を指定する App::draw() { }
glClientActiveTexture(); で texture 座標を割り当てる texture unit を選択 glTexCoordPointer(); で texture 座標配列を ( 明示的 | buffer object ) から指定 glEnableClientState( GL_TEXTURE_COORD_ARRAY ); WARNING 描画毎に Unit は使い回すので state の管理は必要 glTexEnv(); の計算は texture object の intenral format にも依存 && alpha 成分も計算の対象 ( glTexImage(), TexParamter(), TexEnv(), BindTexture() ) はカレントに対して有効
// 単一の tex unit に戻す glActiveTexture( GL_TEXTURE1 ); glDisable( GL_TEXTURE_2D ); glActiveTexture( GL_TEXTURE0 );
MultiTexture 用に複数の TextureCoord を指定する方法は3つある。
[.] glMultiTexCoord(); [.] glTexCoordPointer(); // 頂点配列を指定する [.] glTexGen();
次のように使い分ける. MultiTex && VertexArray -> glTexCoordPointer(); MultiTex && Scratch -> glMultiTexCoord(); MultiTex && 自動生成. -> glTexGen(); // ( Shader 利用するなら不要 )
/ / Multi tc の指定方法. // Server 側の Unit ( State ) を選択する glActiveTexture(); // 複数の tc を VertexArray に指定する. // VertexArray の tc を割り当てる [ U.n.i.t ] を指定する. glClientActiveTexture(); // Client 側の UnitTex を指定する. glEnableClientState( ); // TexCoord を指定 glTexCoordPointer( 2, GL_FLOAT, 0, buf ); 複数の TexCoord を指定する glClientActiveTexture( GL_TEXTUREn ); glTexCoordPointer(): glClientActiveTexture() が指す TexUnit に TexCoord を割り当てる. glEnableClientState( GL_TEXTURE_COORD_ARRAY ); も指定している, TexUnit が利用される.
WARNING glBegin() - glEnd() では指定できない POINT [.] Texcoord.w の成分により w 除算される [.] glTexCoord2f( 1, 0 ); == glTexCoord4f( 1, 0, 0, 1 ); [.] glTexGen をした時も, Texture Matrix の影響をうける WARNING [.] 部分的に glTexGen はできない ? [.] GL_TEXTURE_2D && glTexGen は併用できない ? -> それはないはず
void drawCube() { float s = 30; // 8 頂点 static float v[] = { -s, -s, s, s, -s, s, s, s, s, -s, s, s, -s, -s, -s, s, -s, -s, s, s, -s, -s, s, -s, }; // 6 QUADS の index static unsigned short idx[] = { 0, 1, 2, 3, 4, 5, 6, 7, 1, 5, 6, 2, 4, 0, 3, 7, 4, 5, 1, 0, 3, 2, 6, 7, }; // 各面の Normal static float n[] = { 0, 0, 1, 0, 0, -1, 1, 0, 0, -1, 0, 0, 0, -1, 0, 0, 1, 0, }; // 各面の Texcoord static float t[] = { 0, 0, 1, 0, 1, 1, 0, 1, }; glBegin( GL_QUADS ); for( int i=0; i<6; i++ ){ // 法線を設定 // ここの影響をうける glNormal3fv( n + (3*i) ); // world となるように normal を指定する ? // 先ほどの見え方から推測すると, // ここで指定した normal が , 視線空間上で mapping される //glNormal3fv( n ); for( int j=0; j<4; j++ ){ // 現在の idx int p = idx[ 4*i + j ]; glMultiTexCoord2f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1] ); // z も指定してみる //glMultiTexCoord3f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], t[2*j + 1] ); // w も指定してみる //glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], t[2*j + 1], 1 ); // 前言撤回 -> ここも影響をうける glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, -1 ); glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, -100 ); // w 除算される -> 頂点処理 と同じ流れ //glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, 0.5f ); glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, 2 ); //glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], -1, 1 ); // Z 値はなんでもいい glMultiTexCoord4f( GL_TEXTURE1, t[2*j + 0], t[2*j + 1], 10000, 1 ); glVertex3fv( v + 3*p ); } } glEnd(); }



glMultiTexCoord

SYNTAX void glMultiTexCoord( GLenum unitTex, TYPE tc ); DESC 指定したテクスチャユニットに Texcoord をセットする POINT glTexCoord(); は実は. glMultiTexCoord( GL_TEXTURE0, ); と同じ.
// ユニット1 に UV を指定する float t = { 0, 0, 1 }; glMultiTexCoord3fv( GL_TEXTURE0, t ); float t = { 0, 0, 1 }; glMultiTexCoord3fv( GL_TEXTURE1, t ); glBegin( GL_QUADS ); for( int i=0; i<4; i++ ){ glVertex3fv( vtx ); } glEnd();
拡張機能のため 関数ポインタを取得しておく
PFNGLMULTITEXCOORD2DVPROC glMultiTexCoord2dv; PFNGLMULTITEXCOORD3FVPROC glMultiTexCoord3fv; glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC)wglGetProcAddress("glMultiTexCoord2dv"); glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC)wglGetProcAddress("glMultiTexCoord3fv");
より複雑に指定するには GL_COMBINE mode を使う ( Shader を使った方が簡単だけど )
{ // Preset の補間( GL_ADD, GL_MODULATE )ではなく, CUSTOM の補間を使う glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); // 線形補間 を指定 // ここも複数指定できる // { GL_COMBINE_RGB } // { GL_COMBINE_A } // // GL_REPLACE a0 // GL_MODULATE a0a1 // GL_ADD a0 + a1 // GL_ADD_SIGNED a0 + a1 - 0.5f // GL_SUBSTRACT a0 - a1 // GL_INTERPOLATE a1 * ( 1 - a2 ) + a0 * a2; // glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE ); ///glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE ); glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD_SIGNED ); // 補間する 係数 を指定する ( Alpha 成分のみが使われる ) static const float c[] = { 1, 1, 1, 0.5f }; //glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, c ); // 次のような計算をすることになる // GL_INTERPOLATE // V1 * ( 1 - V2 ) + V0 * V2; // POINT // V2 も Vector 扱い // rgb, a を別途指定できる // f.r = ( 1 - a2.r ) + a0.r * a2.r; // f.g = ( 1 - a2.g ) + a0.g * a2.g; // f.b = ( 1 - a2.b ) + a0.b * a2.b; // f.a = ( 1 - a2.a ) + a0.a * a2.a; // Document からの仮定( この順番 ) // // a0 : 今 処理中の UNIT がサンプルする Texture 色 // a1 : 前の Texture UNIT の結果 // // 今 Alpha にしているのは UNIT1 の結果の RGB の値 // CubeMap が明るい -> a0 が優先 // 変数 a2 に何を使うか 決める // GL_PREVIOUS == 前の UNIT の結果 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS ); //glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_TEXTURE ); //glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA ); // a2.rgb にどの値を使うか決める // // a2.r = TexUnit1.r // a2.g = TexUnit1.g // a2.b = TexUnit1.b // // WARNING // GL_SRC_RGB という 定数 はなし // a2.rgb に 前の Unit の結果のどの成分を使うか ? // GL_SRC_COLOR なので // a2.rgb = UnitPrev.rgb // glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR ); //glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_RGB ); //glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_ALPHA ); //glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT ); // Primary Color( 頂点色 )を指定すれば Texture の色は無視される // glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR ); glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR ); glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR ); glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR ); }



glActiveTexture

SYNTAX PFNGLACTIVETEXTUREPROC glActiveTexture;
# if defined(WIN32) glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture"); # endif



ProxyTexure

DESC proxy texture は GL に texture のサポートを問い合わるもの 圧縮 texture も対応している