このケーススタディでは、主にアニメーションの変更を実施しています。
この効果を得るには、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;
}




