// // コンピュータグラフィックス特論II // 視点操作のサンプルプログラム // // GLUTヘッダファイルのインクルード #include // グローバル変数 // ウィンドウのサイズ int win_width, win_height; // 背景オブジェクトの位置 const int num_trees = 100; float tree_pos[ num_trees ][2]; // マウスのドラッグのための変数 int drag_mouse_r = 0; // 右ボタンがドラッグ中かどうかのフラグ(1:ドラッグ中, 0:非ドラッグ中) int drag_mouse_l = 0; // 左ボタンがドラッグ中かどうかのフラグ(1:ドラッグ中, 0:非ドラッグ中) int last_mouse_x, last_mouse_y; // 最後に記録されたマウスカーソルの座標 // 視点操作パラメタ float view_center_x; // 注視点の位置 float view_center_y; // 注視点の位置 float view_center_z; // 注視点の位置 float view_yaw; // 視点の方位角 float view_pitch; // 視点の仰角 float view_distance; // 視点と注視点の距離 // 視点操作モード enum ViewControlModeEnum { VIEW_DOLLY_PARAM, // Dollyモード(媒介変数) VIEW_DOLLY_DIRECT, // Dollyモード(直接更新) VIEW_SCROLL_PARAM, // Scrollモード(媒介変数) VIEW_SCROLL_DIRECT, // Scrollモード(直接更新) VIEW_WALKTHROUGH_PARAM, // Walkthroughモード(媒介変数) VIEW_WALKTHROUGH_DIRECT, // Walkthroughモード(直接更新) NUM_VIEW_CONTROL_MODES // 視点操作モードの種類数 }; // 視点操作モードの名前 const char * mode_name[] = { "Dolly Mode (Parameter)", "Dolly Mode (Direct)", "Scroll Mode (Parameter)", "Scroll Mode (Direct)", "Walkthrough Mode (Parameter)", "Walkthrough Mode (Direct)" }; // 現在の視点操作モード ViewControlModeEnum mode = VIEW_DOLLY_PARAM; // // 視点操作のための処理 // // // 視点の初期化 // (最初の初期化時と視点モードが切り替えられたときに呼ばれる) // void InitView() { // 視点パラメタを初期化 if ( mode == VIEW_DOLLY_PARAM ) { view_center_x = 0.0f; view_center_y = 0.0f; view_center_z = 0.0f; view_yaw = -30.0f; view_pitch = -30.0f; view_distance = 15.0f; } if ( mode == VIEW_SCROLL_PARAM ) { view_center_x = 0.0f; view_center_y = 0.0f; view_center_z = 0.0f; view_yaw = 0.0f; view_pitch = -30.0f; view_distance = 15.0f; } if ( mode == VIEW_WALKTHROUGH_PARAM ) { view_center_x = 0.0f; view_center_y = 0.5f; view_center_z = 0.0f; view_yaw = 0.0f; view_pitch = 0.0f; view_distance = 0.0f; } // 変換行列を初期化 if ( mode == VIEW_DOLLY_DIRECT ) { glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, -15.0 ); glRotatef( 30.0, 1.0, 0.0, 0.0 ); glRotatef( 30.0, 0.0, 1.0, 0.0 ); view_center_x = 0.0f; view_center_y = 0.0f; view_center_z = 0.0f; } if ( mode == VIEW_SCROLL_DIRECT ) { glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, -15.0 ); glRotatef( 30.0, 1.0, 0.0, 0.0 ); glRotatef( 0.0, 0.0, 1.0, 0.0 ); view_center_x = 0.0f; view_center_y = 0.0f; view_center_z = 0.0f; } if ( mode == VIEW_WALKTHROUGH_DIRECT ) { glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, -0.5, 0.0 ); glRotatef( 0.0, 1.0, 0.0, 0.0 ); glRotatef( 0.0, 0.0, 1.0, 0.0 ); } } // // 視点パラメタに応じて変換行列(カメラ座標系からワールド座標系への変換行列)を更新 // (画面描画時のコールバック関数 DisplayCallback() から呼ばれる) // void UpdateViewMatrix() { // 視点パラメタを使った操作時のみ変換行列を更新 if ( ( mode == VIEW_DOLLY_PARAM ) || ( mode == VIEW_SCROLL_PARAM ) || ( mode == VIEW_WALKTHROUGH_PARAM ) ) { glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, - view_distance ); glRotatef( - view_pitch, 1.0, 0.0, 0.0 ); glRotatef( - view_yaw, 0.0, 1.0, 0.0 ); glTranslatef( - view_center_x, - view_center_y, - view_center_z ); } } // // マウス操作に応じて視点パラメタ or 変換行列を更新 // (マウスドラッグ時のコールバック関数 MouseDragCallback() から呼ばれる) // void UpdateView( int delta_mouse_right_x, int delta_mouse_right_y, int delta_mouse_left_x, int delta_mouse_left_y ) { // 視点パラメタを更新(Dollyモード・媒介変数) if ( mode == VIEW_DOLLY_PARAM ) { // 横方向の右ボタンドラッグに応じて、視点を水平方向に回転 if ( delta_mouse_right_x != 0 ) { view_yaw -= delta_mouse_right_x * 1.0; // パラメタの値が所定の範囲を超えないように修正 if ( view_yaw < 0.0 ) view_yaw += 360.0; else if ( view_yaw > 360.0 ) view_yaw -= 360.0; } // 縦方向の右ボタンドラッグに応じて、視点を上下方向に回転 if ( delta_mouse_right_y != 0 ) { view_pitch -= delta_mouse_right_y * 1.0; // パラメタの値が所定の範囲を超えないように修正 if ( view_pitch < -90.0 ) view_pitch = -90.0; else if ( view_pitch > -2.0 ) view_pitch = -2.0; } // 縦方向の左ボタンドラッグに応じて、視点と注視点の距離を変更 if ( delta_mouse_left_y != 0 ) { view_distance += delta_mouse_left_y * 0.2; // パラメタの値が所定の範囲を超えないように修正 if ( view_distance < 5.0 ) view_distance = 5.0; } } // 視点パラメタを更新(Scrollモード・媒介変数) if ( mode == VIEW_SCROLL_PARAM ) { // 縦方向の右ボタンドラッグに応じて、視点を上下方向に回転 if ( delta_mouse_right_y != 0 ) { // ※レポート課題 } // 左ボタンドラッグに応じて、視点を前後左右に移動(ワールド座標系を基準とした前後左右) if ( ( delta_mouse_left_x != 0 ) || ( delta_mouse_left_y != 0 ) ) { // ※レポート課題 } } // 視点パラメタを更新(Walkthroughモード・媒介変数) if ( mode == VIEW_WALKTHROUGH_PARAM ) { // 横方向の右ボタンドラッグに応じて、視点を水平方向に回転 if ( delta_mouse_right_x != 0 ) { // ※レポート課題 } // 左ボタンドラッグに応じて、視点を前後左右に移動(カメラの向きを基準とした前後左右) if ( ( delta_mouse_left_x != 0 ) || ( delta_mouse_left_y != 0 ) ) { // ※レポート課題 } } // 変換行列を更新(Dollyモード・直接更新) if ( mode == VIEW_DOLLY_DIRECT ) { // 横方向の右ボタンドラッグに応じて、視点を水平方向に回転 if ( delta_mouse_right_x != 0 ) { // 視点の水平方向の回転量を計算 float delta_yaw = delta_mouse_right_x * 1.0; // 現在の変換行列の右側に、今回の回転変換をかける glMatrixMode( GL_MODELVIEW ); glRotatef( delta_yaw, 0.0, 1.0, 0.0 ); } // 縦方向の右ボタンドラッグに応じて、視点を上下方向に回転 if ( delta_mouse_right_y != 0 ) { // 視点の上下方向の回転量を計算 float delta_pitch = delta_mouse_right_y * 1.0; // 現在の変換行列を取得 float m[ 16 ]; float tx, ty, tz; glGetFloatv( GL_MODELVIEW_MATRIX, m ); // 現在の変換行列の平行移動成分を記録 tx = m[ 12 ]; ty = m[ 13 ]; tz = m[ 14 ]; // 現在の変換行列の平行移動成分を0にする m[ 12 ] = 0.0f; m[ 13 ] = 0.0f; m[ 14 ] = 0.0f; // 変換行列を初期化 glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // カメラの平行移動行列を設定 glTranslatef( tx, ty, tz ); // 右側に、今回の回転変換をかける glRotatef( delta_pitch, 1.0, 0.0, 0.0 ); // さらに、右側に、もとの変換行列から平行移動成分をとり除いたものをかける glMultMatrixf( m ); } // 縦方向の左ボタンドラッグに応じて、視点と注視点の距離を変更 if ( delta_mouse_left_y ) { // 視点と注視点の距離の変化量を計算 float delta_dist = delta_mouse_left_y * 1.0; // 現在の変換行列(カメラの向き)を取得 float m[ 16 ]; glGetFloatv( GL_MODELVIEW_MATRIX, m ); // 変換行列を初期化して、カメラ移動分の平行移動行列を設定 glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, - delta_dist ); // 右からこれまでの変換行列をかける glMultMatrixf( m ); } } // 視点パラメタを更新(Scrollモード・直接更新) if ( mode == VIEW_SCROLL_DIRECT ) { // 縦方向の右ボタンドラッグに応じて、視点を上下方向に回転 if ( delta_mouse_right_y != 0 ) { // ※レポート課題 } // 左ボタンドラッグに応じて、視点を前後左右に移動(ワールド座標系を基準として前後左右に移動) if ( ( delta_mouse_left_x != 0 ) || ( delta_mouse_left_y != 0 ) ) { // ※レポート課題 } } // 変換行列を更新(Walkthroughモード・直接更新) if ( mode == VIEW_WALKTHROUGH_DIRECT ) { // 横方向の右ボタンドラッグに応じて、視点を水平方向に回転 if ( delta_mouse_right_x != 0 ) { // ※レポート課題 } // 左ボタンドラッグに応じて、視点を前後左右に移動(カメラの向きを基準として前後左右に移動) if ( ( delta_mouse_left_x != 0 ) || ( delta_mouse_left_y != 0 ) ) { // ※レポート課題 } } } // // 以下、プログラムのメイン処理 // // // 木を描画 // void RenderTree() { static GLUquadricObj * quad_obj = NULL; if ( quad_obj == NULL ) quad_obj = gluNewQuadric(); glPushMatrix(); glRotatef( -90.0f, 1.0f, 0.0f, 0.0f ); glColor3f( 0.8, 0.7, 0.0 ); gluCylinder( quad_obj, 0.25f, 0.25f, 1.0f, 16, 1 ); glPopMatrix(); glPushMatrix(); glTranslatef( 0.0f, 0.5f, 0.0f ); glRotatef( -90.0f, 1.0f, 0.0f, 0.0f ); glColor3f( 0.3, 0.7, 0.3 ); gluCylinder( quad_obj, 0.5f, 0.0f, 1.0f, 16, 1 ); glPopMatrix(); glPushMatrix(); glTranslatef( 0.0f, 1.0f, 0.0f ); glRotatef( -90.0f, 1.0f, 0.0f, 0.0f ); glColor3f( 0.3, 0.7, 0.3 ); gluCylinder( quad_obj, 0.5f, 0.0f, 1.0f, 16, 1 ); glPopMatrix(); } // // 格子模様の床を描画 // void DrawFloor( int tile_size, int num_x, int num_z, float r0, float g0, float b0, float r1, float g1, float b1 ) { int x, z; float ox, oz; glBegin( GL_QUADS ); glNormal3d( 0.0, 1.0, 0.0 ); ox = - ( num_x * tile_size ) / 2; for ( x=0; x