blog

OpenGLの場合 - トンネル

テクスチャの読み込み\n今回は3つのテクスチャを使用するので、forループを使って順番にテクスチャをバインドしてロードします。\n//テクスチャオブジェクトの割り当て\n;\nfor (iLoop...

Feb 8, 2020 · 4 min. read
シェア

前回はOpenGLのテクスチャのapiを紹介しましたが、今回はトンネルのケースを使ってテクスチャを適用してみます。効果は次のようになります:

テクスチャの読み込み

今回は3つのテクスチャが使われているので、forループを使って順番にテクスチャをバインドしてロードします。

//テクスチャオブジェクトを割り当てる
glGenTextures(TEXTURE_COUNT, textures);
for (iLoop=0; iLoop<TEXTURE_COUNT; iLoop++) {
 //テクスチャオブジェクトをバインドする
 glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
 
 //tgaファイルを読み込む
 pBytes = gltReadTGABits(szTextureFiles[iLoop], &iWidth, &iHeigth, &iComponents, &eFormat);
 
 //テクスチャの読み込み、フィルター、ラッピングモードの設定
 //GL_TEXTURE_MAG_FILTER(ズームフィルター),GL_NEAREST(最近傍フィルター)
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 //GL_TEXTURE_MIN_FILTER(ズームフィルター),GL_NEAREST(最近傍フィルター)
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 //GL_TEXTURE_WRAP_S(s軸サラウンド),GL_CLAMP_TO_EDGE(サラウンドモードでは、範囲外のテクスチャ座標は、法的なテクスチャユニットの最後の行または列に沿ってサンプリングされる)
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 //GL_TEXTURE_WRAP_T(t軸サラウンド)、GL_CLAMP_TO_EDGE(サラウンドモードでは、範囲外のテクスチャ座標は、法的なテクスチャユニットの最後の行または列に沿ってサンプリングされる)
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
 
 //テクスチャを読み込む
 glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iHeigth, iHeigth, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
 
 //テクスチャオブジェクトのミップマップ一式を生成する glGenerateMipmap
 glGenerateMipmap(GL_TEXTURE_2D);
 
 //元のテクスチャデータを解放し、テクスチャオリジナルデータをもう必要としない
 free(pBytes);
}

座標の決定

床の座標を例にします。床の頂点の座標は、GL_TRIANGLE_STRIPで三角形の形で描画され、2つの三角形は正方形を形成することができ、対応するテクスチャ座標は下図のように決定されます。

実現コード:
//ジオメトリの頂点を設定する
GLfloat z, x=10, y=10;
floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
//フロアzはトンネルの深さを示す
for (z=60; z>=0; z-=10) {
 floorBatch.MultiTexCoord2f(0, 0.0, 0.0);
 floorBatch.Vertex3f(-x, -y, z);
 
 floorBatch.MultiTexCoord2f(0, 1.0, 0);
 floorBatch.Vertex3f(x, -y, z);
 
 floorBatch.MultiTexCoord2f(0, 0, 1.0);
 floorBatch.Vertex3f(-x, -y, z-10);
 
 floorBatch.MultiTexCoord2f(0, 1.0, 1.0);
 floorBatch.Vertex3f(x, -y, z-10);
}
floorBatch.End();

残りの座標は、上記の設定を参照して決定することができます。

描画

描画は比較的簡単で、まず対応するテクスチャオブジェクトをバインドします。

modelViewMatrix.PushMatrix();
modelViewMatrix.Translate(0, 0, viewZ);
shaderManager.UseStockShader(GLT_SHADER_TEXTURE_REPLACE, transformPipeline.GetModelViewProjectionMatrix(), 0);
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_FLOOR]);
floorBatch.Draw();
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
leftWallBatch.Draw();
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
rightBatch.Draw();
glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_CEILING]);
ceilingBatch.Draw();
modelViewMatrix.PopMatrix();
glutSwapBuffers();

コードを実行すれば、望みの効果が得られます。

レンズの動き

上記は静的な効果しか表示できず、動かすことはできないので、特殊なキーメソッドにレスポンスを追加します。カメラを動かす最終的な効果は、上記の動画の効果と同じになります。

//矢印キーに反応してビューポートを前後に動かす
void SpecialKeys(int key, int x, int y)
{
 if (key == GLUT_KEY_UP) {
 viewZ += 0.5f;
 }
 if (key == GLUT_KEY_DOWN) {
 viewZ -= 0.5f;
 }
 glutPostRedisplay();
}

いくつかの効果を比較

最後に、右クリックリストを追加して、異なるパラメータを設定し、異なるパラメータ設定の異なる効果を比較することもできます。メニューエントリを追加します:

 glutCreateMenu(ProcessMenu);
 glutAddMenuEntry("GL_NEAREST", 0);
 glutAddMenuEntry("GL_LINEAR", 1);
 glutAddMenuEntry("GL_NEAREST_MIPMAP_NEAREST", 2);
 glutAddMenuEntry("GL_NEAREST_MIPMAP_LINEAR", 3);
 glutAddMenuEntry("GL_LINEAR_MIPMAP_NEAREST", 4);
 glutAddMenuEntry("GL_LINEAR_MIPMAP_LINEAR", 5);
 glutAddMenuEntry("Anisotropic Filter", 6);
 glutAddMenuEntry("Anisotropic Off", 7);
 glutAttachMenu(GLUT_RIGHT_BUTTON);

イベント処理:

//メニューバーの選択
void ProcessMenu(int value)
{
 GLuint iLoop;
 for (iLoop = 0; iLoop<TEXTURE_COUNT; iLoop++) {
 glBindTexture(GL_TEXTURE_2D, textures[iLoop]);
 
 switch (value) {
 case 0:
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 break;
 case 1:
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 break;
 case 2:
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
 break;
 case 3:
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR);
 break;
 case 4:
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
 case 5:
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 
 case 6:
 GLfloat fLargest;
 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
 default:
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
 break;
 }
 }
 glutPostRedisplay();
}
Read next

JavaScript反復プロトコル

反復プロトコルは、イテラブル・プロトコルとイテレータ・プロトコルの2つに分かれます。 1.反復可能プロトコルとは? オブジェクトが独自の反復動作を定義またはカスタマイズできるようにするプロトコルを反復可能プロトコルと呼びます。 イテレート可能なプロトコルを実装したオブジェクトは、イテレート可能なオブジェクトと呼ばれます。 2.イテレート可能なオブジェクトかどうかを見分ける方法は? オブジェクトには、 ... という名前のイテレータがなければなりません。

Feb 8, 2020 · 5 min read