前回までで3Dグラフィックスを書く準備が出来、xyz軸を使った[「お試し」も完了しました。
さて、今回は前回のお約束通り、GLSamplerの正三角錐と直方体を描いてみましょう。プログラムは末尾に【TestGLUT02.cpp】として貼っておきます。(なお、今回からプログラム全てに色付けするのではなく、ハイライト部分のみを色付けするようにします。従って、色付けされていない所は既に前のプログラムで書かれているところだとご理解されてよいと思います。)
前回と今回のプログラムの違いは以下の通りです。
(1)前回始点の設定、投影方法の設定を色々と試すためにマウス処理とキーボード処理を併用したが、今回はマウス処理に纏め、キーボード処理は終了のみとしました。
(2)前回はxyz軸のみでしたが、今回は正三角錐と直方体を色付きのソリッド画像で、モデル空間(ローカル空間)で(=「モデルビュー行列」を使った座標処理で)平行移動(正三角錐を右へ、直方体を左へ)、縮小(視野空間からはみ出すので、共にxyz軸に1/2縮小させた)、回転させました。
(3)モデルビュー座標とプロジェクション座標を保護するために、平行移動、縮小、回転(注)の前にglPushMatrix()で描画前の座標を保護し、平行移動、縮小、回転の為に座標をいじくった後、元に戻すためにglPopMatrix()を使いました。
注:前に紹介したこれ(スライド3~6参照)の通り、拡大・縮小、平行移動、回転は現在の座標にそれぞれの変換行列を乗じて座標を変換します。
実際にプログラムを起動すると、
平行投影画面になるので、マウスを左クリックしてやると、
視点座標(1.0, 1.0, 1.0)から1.0~100.0までの視野空間で見た回転する正三角錐と直方体が見られます。又、右クリックすると、
視点を(-1.0, 1.0, 1.0)に移した画面になります。なお、中ボタンを押すと起動時の平行投影画面に戻ります。
さて次回はどうしましょうか?
あっ、直方体のワイアーフレームを入れるのを忘れていました!
ということで、直方体は勿論、正三角錐のワイアーフレームも用意しましょう。乞ご期待。
【TestGLUT02.cpp】
#include <stdio.h> //C言語ベースなのでprintf等を使う場合必要
#include <GL\freeglut.h> //Embarcadero C++ コンパイラーの"BCC102\include\windows\sdk\GL"に入れる
//外部変数
int g_w, g_h; //クライアント領域幅、高さ
GLdouble eyex = 0.0, eyey = 0.0, eyez = 0.9; //視点座標
bool Ortho_Perspect = TRUE; //平行投影か否か
//解説:あっさりとさせるために前回よりも少なくなっていますね。
//投影設定
void SetProjection(void) {
//変換行列の初期化(座標変換行列に単位行列を設定)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//透視投射範囲の設定
if(Ortho_Perspect)
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); //平行投射範囲の設定
else {
if(!g_h) g_h = 1; //高さが0の場合は1に設定
gluPerspective(60.0, (double)g_w /(double)g_h, 1.0, 100.0); //透視投射範囲の設定
}
//モデルビュー変換行列を指定
glMatrixMode(GL_MODELVIEW);
}
//解説:ここも変数を使った可動式にせず、平行投影、透視投影共にあっさりと定数でまとめています。
void DrawAxes(void) {
glPushMatrix();
glBegin(GL_LINES);
//X軸(青)
glColor3d(0.0, 0.0, 1.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.95, 0.0, 0.0);
glVertex3d(0.95, 0.0, 0.0);
glVertex3d(0.90, 0.03, 0.0);
glVertex3d(0.95, 0.0, 0.0);
glVertex3d(0.90, -0.03, 0.0);
//Y軸(緑)
glColor3d(0.0, 1.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.95, 0.0);
glVertex3d(0.0, 0.95, 0.0);
glVertex3d(0.03, 0.90, 0.0);
glVertex3d(0.0, 0.95, 0.0);
glVertex3d(-0.03, 0.90, 0.0);
//Z軸(赤)
glColor3d(1.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, 0.95);
glVertex3d(0.0, 0.0, 0.95);
glVertex3d(0.0, 0.03, 0.90);
glVertex3d(0.0, 0.0, 0.95);
glVertex3d(0.0, -0.03, 0.90);
glEnd();
glPopMatrix();
}
void DrawPolygon() {
static float theta = 0.0f; //シータ値
//ポリゴン描画
//正三角錐の描画処理(正三角形の面を4つ描く)
glPushMatrix();
//図形の平行移動(x軸方向に0.5移動)
glTranslated(0.5, 0.0, 0.0);
//図形の縮小(xyz軸全方向で1/2)
glScaled(0.5, 0.5, 0.5);
//図形の回転(Y軸を中心に)
glRotated(theta, 0.0, 1.0, 0.0);
theta += 0.05;
glBegin(GL_TRIANGLES);
//奥の面
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(-0.500f, -0.272f, -0.289f); glVertex3f(0.500f, -0.272f, -0.289f); glVertex3f(0.000f, 0.544f, 0.000f);
//右手前面
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.500f, -0.272f, -0.289f); glVertex3f(0.000f, -0.272f, 0.577f); glVertex3f(0.000f, 0.544f, 0.000f);
//左手前面
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.000f, -0.272f, 0.577f); glVertex3f(-0.500f, -0.272f, -0.289f); glVertex3f(0.000f, 0.544f, 0.000f);
//底面
glColor3f(1.0f, 1.0f, 1.0f);
glVertex3f(0.500f, -0.272f, -0.289f); glVertex3f(0.500f, -0.272f, -0.289f); glVertex3f(0.000f, -0.272f, 0.577f); //解説:2024年6月4日修正
glEnd();
glPopMatrix();
//直方体の描画処理(正方形の面を6つ描く)
glPushMatrix();
//図形の平行移動(x軸方向に-0.5移動)
glTranslated(-0.5, 0.0, 0.0);
//図形の縮小(xyz軸全方向で1/2)
glScaled(0.5, 0.5, 0.5);
//図形の回転(Y軸を中心に)
glRotated(theta, 0.0, 1.0, 0.0);
//更に図形の回転(X軸を中心に)
glRotated(theta, 1.0, 0.0, 0.0);
glBegin(GL_QUADS);
//手前正面
glColor3d(0.0, 0.0, 1.0); //解説:青
glVertex3d(-0.5, -0.5, 0.5);
glVertex3d(0.5, -0.5, 0.5);
glVertex3d(0.5, 0.5, 0.5);
glVertex3d(-0.5, 0.5, 0.5);
//右側面
glColor3d(0.0, 1.0, 1.0); //解説:シアン
glVertex3d(0.5, -0.5, -0.5);
glVertex3d(0.5,- 0.5, 0.5);
glVertex3d(0.5, 0.5, 0.5);
glVertex3d(0.5, 0.5, -0.5);
//奥正面
glColor3d(1.0, 0.0, 0.0); //解説:赤
glVertex3d(-0.5, -0.5, -0.5);
glVertex3d(0.5, -0.5, -0.5);
glVertex3d(0.5, 0.5, -0.5);
glVertex3d(-0.5, 0.5, -0.5);
//左側面
glColor3d(0.0, 1.0, 0.0); //解説:緑
glVertex3d(-0.5, -0.5, -0.5);
glVertex3d(-0.5, 0.5, -0.5);
glVertex3d(-0.5, 0.5, 0.5);
glVertex3d(-0.5, -0.5, 0.5);
//天面
glColor3d(1.0, 0.0, 1.0); //解説:マジェンダ
glVertex3d(-0.5, 0.5, -0.5);
glVertex3d(-0.5, 0.5, 0.5);
glVertex3d(0.5, 0.5, 0.5);
glVertex3d(0.5, 0.5, -0.5);
//底面
glColor3d(1.0, 1.0, 0.0); //解説:黄
glVertex3d(-0.5, -0.5, -0.5);
glVertex3d(-0.5, -0.5, 0.5);
glVertex3d(0.5, -0.5, 0.5);
glVertex3d(0.5, -0.5, -0.5);
glEnd();
theta += 0.1;
glPopMatrix();
}
//アイドル時処理関数
void idle(void) {
glutPostRedisplay(); //再描画関数
}
//描画関数
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //色とZ(深度)バッファを初期化
glLoadIdentity(); //変換行列を初期化
gluLookAt( eyex, eyey, eyez, //eyex, eyey, eyez
0.0, 0.0, 0.0, //targetx, targety, targetz
0.0, 1.0, 0.0); //アップベクター(上方向)
DrawAxes(); //x, y, z軸を描画
DrawPolygon(); //三角錐と直方体を描画
glFlush(); //glutSwapBuffersで行われるので不要かも
glutSwapBuffers(); //glutInitDisplayMode(GLUT_DOUBLE)でダブルバッファリングを利用可
}
//ウィンドウサイズ変更時関数
static void resize(int width, int height)
{
//クライアントエリアサイズを記録
g_w = width; g_h = height;
//クライアントエリア全体に表示
glViewport(0, 0, g_w, g_h);
//投影設定
SetProjection();
gluLookAt( eyex, eyey, eyez, //eyex, eyey, eyez
0.0, 0.0, 0.0, //targetx, targety, targetz
0.0, 1.0, 0.0); //アップベクター(上方向)
}
//マウス入力処理関数
void mouse(int button, int state, int x, int y) {
switch(button) {
case GLUT_LEFT_BUTTON:
//視点位置と視線方向の設定
eyex = 1.0; eyey = 1.0; eyez = 1.0;
Ortho_Perspect = FALSE;
break;
case GLUT_MIDDLE_BUTTON:
//視点位置と視線方向の設定
eyex = 0.0; eyey = 0.0; eyez = 0.9;
Ortho_Perspect = TRUE;
break;
case GLUT_RIGHT_BUTTON:
//視点位置と視線方向の設定
eyex = -1.0; eyey = 1.0; eyez = 1.0;
Ortho_Perspect = FALSE;
break;
default:
break;
}
//投影設定
SetProjection();
display();
} //解説:前回はマウスは視点座標の設定だけでしたが、今回は前回のキーボードでやった投影方法の選択と視点位置を変えて投影処理を行わせています。
//キーボード入力処理関数
void keyboard(unsigned char key, int x, int y) {
//ESC か q をタイプしたら終了
if(key == '\033' || key == 'q') {
exit(0);
}
} //解説:今回はキーボード処理を簡素化しています。
//メイン(エントリーポイント)関数
int main(int argc, char *argv[]) {
glutInit(&argc, argv); //GLUTの初期化
glutInitDisplayMode(GLUT_RGBA | //ディスプレーの初期化
GLUT_DOUBLE |
GLUT_DEPTH);
glutInitWindowPosition(100, 100); //ウィンドウ位置指定
glutInitWindowSize(640, 640); //ウィンドウサイズ指定
//ファイル名だけを表示する
char* fn;
for(char* pt = argv[0]; *pt; pt++) {
if(*pt == '\\')
fn = ++pt;
}
glutCreateWindow(fn); //タイトル付ウィンドウ生成
glShadeModel(GL_SMOOTH); //既定値の滑らかな網かけ
glEnable(GL_DEPTH_TEST); //深度テストを有効にする
glClearColor(0.0, 0.0, 0.0, 1.0); //画面消去色(黒)
glutDisplayFunc(display); //描画関数の指定
glutReshapeFunc(resize); //ウィンドウサイズ変更時関数の指定
glutIdleFunc(idle); //アイドル時処理関数の指定
glutMouseFunc(mouse); //マウス入力処理関数
glutKeyboardFunc(keyboard); //キーボード入力処理関数
glutMainLoop(); //メインループ関数
return 0;
}