blog

OpenGL-トンネルのケーススタディ

このケーススタディは、主にこのような効果を達成するためにアニメーションを変更するには、4つのテクスチャを描画する必要があり、左右の壁のテクスチャ、トンネルの上部とテクスチャの下部は、同じ全体の順序を準...

Jul 22, 2020 · 6 min. read
シェア

このケーススタディでは、主にアニメーションの変更を実施しています。



この効果を得るには、4つのテクスチャを描画する必要があります。左右の壁のテクスチャ、トンネルの上部のテクスチャ、そして下部のテクスチャです。

準備

ここでも全体的な順序は、ChangeSize関数→SetupRC関数→RenderScene関数、そしてビューを制御するSpecialKeys関数です。

ChangeSize

ChangeSize関数は、主にウィンドウと投影行列を設定し、投影行列をロードし、変換パイプラインを設定します。

void ChangeSize(int w,int h)
{
 if (h == 0) {
 h = 1;
 }
 glViewport(0,0, w, h);
 //投影行列を設定する
 viewFrustum.SetPerspective(100.0f, (float)w/(float)h, 1.0, 120.0);
 //投影行列をロードする
 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
 //変換パイプラインを設定する
 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

SetupRC

この関数内で処理される主なものは、背景色の設定、シェーダ管理の初期化、3つのテクスチャの処理、トンネル頂点へのテクスチャのマッピングの設定です。

背景の設定とシェーディング・マネージャーの初期化

//バックカラーを設定する
 glClearColor(0.0f,0.0f,0.0f,1.0f);
 //シェーディング・マネージャーを初期化する
 shaderManager.InitializeStockShaders();

テクスチャの加工

GLbyte *pBytes;
 GLint iWidth, iHeight, iComponents;
 GLenum eFormat;
 GLint iLoop;
 //テクスチャマーカーを生成する
 glGenTextures(TEXTURE_COUNT, textures);
 //forループでテクスチャを設定する
 for (int i = 0; i<TEXTURE_COUNT; i++) {
 //テクスチャをバインドする
 glBindTexture(GL_TEXTURE_2D, textures[i]);
 //tgaファイルを解析する
 pBytes = gltReadTGABits(szTextureFiles[i], &iWidth, &iHeight, &iComponents, &eFormat);
 //テクスチャフィルタを設定する
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);//ズームフィルター
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);//ズームフィルター
 //サラウンドモードを設定する
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
 //テクスチャを読み込む
 glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
 //完全なミップマップを生成する
 glGenerateMipmap(GL_TEXTURE_2D);
 
 //テクスチャデータを解放する
 free(pBytes);
 }

床のテクスチャと頂点のマッピング関係の処理

下図に示すように、フロアの頂点は主にz軸方向に変化しています。



//zはトンネルの深さを示し、zの値は、画面からの距離が小さいほど、より遠くにある
 GLfloat z;
 floorBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
 for (z = 70.0f; z >= 0.0f; z -= 10.0f) {
 floorBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
 floorBatch.Vertex3f(-10.0f, -10.0f, z);
 
 floorBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
 floorBatch.Vertex3f(10.0f, -10.0f, z);
 
 floorBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
 floorBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
 
 floorBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
 floorBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
 }
 floorBatch.End();

頂点に対するトップテクスチャの設定

下の図からも、頂点の変更がz軸のままであることがわかります。



//天井を描画する
 ceilingBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
 for(z = 70.0f; z >= 0.0f; z -=10.0f)
 {
 ceilingBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
 ceilingBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
 
 ceilingBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
 ceilingBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
 
 ceilingBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
 ceilingBatch.Vertex3f(-10.0f, 10.0f, z);
 
 ceilingBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
 ceilingBatch.Vertex3f(10.0f, 10.0f, z);
 }
 ceilingBatch.End();

左の壁のテクスチャの頂点へのマッピングの設定

下図



//左の壁を描画する
 leftWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
 for(z = 70.0f; z >= 0.0f; z -=10.0f)
 {
 leftWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
 leftWallBatch.Vertex3f(-10.0f, -10.0f, z);
 
 leftWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
 leftWallBatch.Vertex3f(-10.0f, 10.0f, z);
 
 leftWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
 leftWallBatch.Vertex3f(-10.0f, -10.0f, z - 10.0f);
 
 leftWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
 leftWallBatch.Vertex3f(-10.0f, 10.0f, z - 10.0f);
 }
 leftWallBatch.End();

頂点にマッピングする正しい壁のテクスチャの設定



//右の壁を描画する
 rightWallBatch.Begin(GL_TRIANGLE_STRIP, 28, 1);
 for(z = 70.0f; z >= 0.0f; z -=10.0f)
 {
 rightWallBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
 rightWallBatch.Vertex3f(10.0f, -10.0f, z);
 
 rightWallBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
 rightWallBatch.Vertex3f(10.0f, 10.0f, z);
 
 rightWallBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
 rightWallBatch.Vertex3f(10.0f, -10.0f, z - 10.0f);
 
 rightWallBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
 rightWallBatch.Vertex3f(10.0f, 10.0f, z - 10.0f);
 }
 rightWallBatch.End();

RenderScene

主なことは、テクスチャーに従ってトンネルを描くことです。

void RenderScene(void)
{
 //特定のバッファまたは
 
 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
 
 //モデルビュースタック
 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_CEILING]);
 ceilingBatch.Draw();
 //左右の壁のテクスチャをバインドする
 glBindTexture(GL_TEXTURE_2D, textures[TEXTURE_BRICK]);
 //左の壁を描画する
 leftWallBatch.Draw();
 //右の壁を描画する
 rightWallBatch.Draw();
 
 modelViewMatrix.PopMatrix();
 //は、バックグラウンドバッファにレンダリングされ、その後、フォアグラウンドへの交換の終わりになる
 glutSwapBuffers();
}

SpecialKeys

主に上下左右のキー入力を引き継ぎ、トンネルを描き直します

//矢印キーに反応してビューポートを前後に動かす
void SpecialKeys(int key, int x, int y)
{
 if(key == GLUT_KEY_UP)
 //移動は深さの値、Z
 viewZ += 0.5f;
 
 if(key == GLUT_KEY_DOWN)
 viewZ -= 0.5f;
 
 //ウィンドウを更新すると、RenderScene関数にコールバックすることができる
 glutPostRedisplay();
}

main

プログラム入力

int main(int argc,char* argv[])
{
 gltSetWorkingDirectory(argv[0]);
 // 標準初期化
 glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
 glutInitWindowSize();
 glutCreateWindow("Tunnel");
 glutReshapeFunc(ChangeSize);
 glutSpecialFunc(SpecialKeys);
 glutDisplayFunc(RenderScene);
 
 // メニューエントリを追加し、フィルタを変更する
// 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);
 
 GLenum err = glewInit();
 if (GLEW_OK != err) {
 fprintf(stderr, "GLEW Error: %s
", glewGetErrorString(err));
 return 1;
 }
 
 
 // ループを開始し、テクスチャを閉じる
 SetupRC();
 glutMainLoop();
 ShutdownRC();
 
 return 0;
}



Read next

Flutterのアーキテクチャコンポーネント - Flutterの非連結アーキテクチャモデルとコンポーネント間の状態管理

1.LiveStateコンポーネント 2.ViewModelコンポーネント ViewModelは、UIが必要とする関連データを管理し、UIとモデル間のインタラクションを引き受け、ビジネスロジックを処理するために使用することができます。 例えば、AppBar はタイトルを変更するインターフェースを提供したり、AppBar の右側の Action にショッピングカートの数を表示する必要があります。典型的な...

Jul 22, 2020 · 8 min read