2012年3月9日金曜日

マルチテクスチャ

glinterleavedarraysではマルチテクスチャを扱えなさそうなので。
頂点配列による描画とVBOを利用した描画を考察。

固定機能でマルチテクスチャなんかやってられんな・・・というのが1点。
指定が回りくどいにも程があるのとAPIの呼び出し順序がカオス過ぎる。

いづれにしても可変頂点フォーマットを実現するには、頂点要素は分離しておく
必要性がありそうだ。


■頂点配列による描画

頂点配列描画用データ
// 位置
float position[] = {
  -1.0f, +1.0f, 0.0f,
  +1.0f, +1.0f, 0.0f,
  -1.0f, -1.0f, 0.0f,
  +1.0f, -1.0f, 0.0f
};
// 法線
float normal[] = {
  0.0f, 0.0f, 1.0f,
  0.0f, 0.0f, 1.0f,
  0.0f, 0.0f, 1.0f,
  0.0f, 0.0f, 1.0f
};
// テクスチャ座標0
float texcoord0[] = {
  0.0f, 1.0f,
  1.0f, 1.0f,
  0.0f, 0.0f,
  1.0f, 0.0f
};
// テクスチャ座標1
float texcoord1[] = {
  0.0f, 1.0f,
  1.0f, 1.0f,
  0.0f, 0.0f,
  1.0f, 0.0f
};
// インデクス
GLuint indices[] = {
  0, 1, 2,
  2, 1, 3
};
// 三角形の数
size_t ntri = sizeof(indices) / sizeof(GLuint) / 3;
// テクスチャ
GLuint texture[2];

頂点配列描画
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// 頂点
glVertexPointer(3, GL_FLOAT, 0, position);
// 法線
glNormalPointer(GL_FLOAT, 0, normal);
// テクスチャ0
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glClientActiveTexture(GL_TEXTURE0);
glTexCoordPointer(2, GL_FLOAT, 0, texcoord0);
// テクスチャ1
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glClientActiveTexture(GL_TEXTURE1);
glTexCoordPointer(2, GL_FLOAT, 0, texcoord1);
// 描画
glDrawElements(GL_TRIANGLES, ntri * 3, GL_UNSIGNED_INT, indices);
// 後始末
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

■VBOによる描画

頂点配列描画用データにVBOを追加
GLuint buffers[5];

VBOの初期化
glGenBuffers(5, buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(position), position, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(normal), normal, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texcoord0), texcoord0, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, buffers[3]);
glBufferData(GL_ARRAY_BUFFER, sizeof(texcoord1), texcoord1, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[4]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

VBOで描画
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// 頂点
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glVertexPointer(3, GL_FLOAT, 0, 0);
// 法線
glBindBuffer(GL_ARRAY_BUFFER, buffers[1]);
glNormalPointer(GL_FLOAT, 0, 0);
// テクスチャ0
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glClientActiveTexture(GL_TEXTURE0);
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
// テクスチャ1
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glClientActiveTexture(GL_TEXTURE1);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[3]);
glTexCoordPointer(2, GL_FLOAT, 0, 0);
// インデクス
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[4]);
// 描画
glDrawElements(GL_TRIANGLES, ntri * 3, GL_UNSIGNED_INT, 0);
// 後始末
glDisable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

■GLSL(シェーダ)版
実はGLSLは初めてだったりする。
DirectXではHLSLやHLSLになる前のアセンブリシェーダは使い倒していたのだが
すっかり疎遠になってほぼ忘れかけている(汗
そんな私でもGLSLに限らず細かいことは床井先生のところを見れば万事問題解決!

テクスチャ座標0と1が異なる場合なのは上記と変わらず。
テスト中にglGetUniformLocationから-1(そんなシンボルないよ)と返ってきたが、シェーダの
コンパイル時に最適化が掛かって実質無意味(例えば利用されていない)なものは削除されている
かも知れない。
やっぱり固定機能でなんて書いていられない。
シェーダの利点としてベクトルなんかは内部で4成分のレジスタとして表現してあるから
RGBであるとかRGBAであるとかあまり意識しなくて済むのは非常に楽。
というかOpenGLの固定機能は無駄に神経をすり減らされて疲れる。

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
// 頂点
glVertexPointer(3, GL_FLOAT, 0, position);
// 法線
glNormalPointer(GL_FLOAT, 0, normal);
// テクスチャ座標0
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texcoord0);
// テクスチャ座標1
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glClientActiveTexture(GL_TEXTURE1);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, texcoord1);

// 描画1
glUseProgram(gl2Program);
glPushMatrix();
glTranslatef(-1.0f, 1.0f, 0.0f);
glDrawElements(GL_TRIANGLES, ntri * 3, GL_UNSIGNED_INT, indices);
glPopMatrix();

// 描画2
glUseProgram(gl2Program2);
GLint texture0Idx = glGetUniformLocation(gl2Program2, "texture0");
glUniform1i(texture0Idx, 0);
GLint texture1Idx = glGetUniformLocation(gl2Program2, "texture1");
glUniform1i(texture1Idx, 1);
glPushMatrix();
glTranslatef( 1.0f,-1.0f, 0.0f);
glDrawElements(GL_TRIANGLES, ntri * 3, GL_UNSIGNED_INT, indices);
glPopMatrix();

// 後始末
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
glClientActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

glUseProgram(0);

マルチテクスチャではないが、シェーダを利用したついでに。
前回利用させて頂いたモデル。


て・・・アレ?
GLSLってJITコンパイルのみ!?
シェーダの手直しが面倒臭過ぎるんだけどどうしたものか。
ログ取れるからコンパイルだけするツールでも作るか・・・。
 

0 件のコメント :

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。