免許法認定公開講座: コンピュータグラフィックス

Slides:



Advertisements
Similar presentations
シミュレーション演習 G. 総合演習 ( Mathematica 演 習) システム創成情報工学科 テキスト作成: 藤尾 光彦 講義担当: 尾下 真樹.
Advertisements

Absolute Orientation. Absolute Orientation の問題 二つの座標系の間における剛体 (rigid body) 変換を復元す る問題である。 例えば: 2 台のステレオカメラから得られた3次元情報の間の関 係を推定する問題。 2 台のステレオカメラから得られた3次元情報の間の関.
初年次セミナー 第13回 2次元グラフィックス(1).
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第3回 配列(1) 情報・知能工学系 山本一公
情報処理演習 (9)グラフィックス システム科学領域 日浦 慎作.
初年次セミナー 第14回 2次元グラフィックス(2).
初年次セミナー 第8回 データの入力.
情報処理実習 第05回 Excelマクロ機能入門 操作マクロ入門.
今回の内容 前回の復習 演習環境 サンプルプログラムの解説 プログラミング演習 OpenGLとGLUTの概要 サンプルプログラムの概要
プログラミング演習3 李 亜民クラス 第2回 ラスタライズ.
情報処理 第7回.
本講義の目標: ・C言語とOpenGLを用いて,プログラミングによるコンピュータグラフィックス生成手法について学ぶ
プログラミング基礎I(再) 山元進.
初年次セミナー 第4回 整数と実数の取り扱い.
3DCGコンテンツの基礎 第5回授業:最終課題制作
今日の内容 前回の演習の復習 前回の復習 ポリゴンの描画方法(復習) 基本オブジェクトの描画 ポリゴンモデルの描画 演習課題.
HSPでのミニゲーム作成 早稲田実業学校PC班 Y氏.
今日の内容 前回の復習 前回の演習の復習 視点操作の実現方法(復習) 視点操作の拡張 変換行列によるアニメーション 演習課題.
平成23年8月 情報学群 岡田 守 このスライドは, 前川佳徳編著による「コンピュータグラフィックス」(オーム社)を基に作成されている.
Excelによる3-D/等高線グラフの描画 2変数関数の描画 Excel によるグレイスケールマップ風描画
Excelによる3-D/等高線グラフの描画 2変数関数の描画 Excel によるグレイスケールマップ風描画
問題 1 キーボードから入力した数の合計を計算するプログラムを 作成せよ。最初に、何個の数を入力するかその数を入力 するようにする。
今日の内容 前回の復習 モデリング 3次元オブジェクトの表現方法 3次元オブジェクトの作成方法 オブジェクトを計算機上でどのように表現するか
第3回:ボールを上下に動かそう! (オブジェクトの移動、一次元)
初年次セミナー 第2回 文字の出力.
コンピュータグラフィックスS 第6回 第6回 レンダリング・パイプライン システム創成情報工学科 尾下 真樹
精密工学科プログラミング基礎Ⅱ 第3回資料 今回の授業で習得してほしいこと: 2次元配列の使い方 (前回の1次元配列の復習もします.)
シミュレーション演習 G. 総合演習 (Mathematica演習) システム創成情報工学科
プログラミング演習3 第2回 GUIの復習.
CGと形状モデリング 授業資料 長井 超慧(東京大学)
C 言語について 補足資料 資料および授業の情報は :
コンピュータグラフィックスS 第13回 第13回 演習(4):シェーディング、マッピング システム創成情報工学科 尾下 真樹
DirectX勉強会 第5回.
第10回関数 Ⅱ (ローカル変数とスコープ).
電界中の電子の運動 シミュレータ作成 精密工学科プログラミング基礎 資料.
OpenGLを使ったプログラム作成 澤見研究室
第9回 卒業研究1
OpenGLライブラリを用いた3次元フラクタルの描画
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
実行時情報に基づく OSカーネルのコンフィグ最小化
プログラミング演習3 第2回 GUIの復習.
プログラミング基礎a 第10回 Javaによる図形処理入門(2) GUIの使い方
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
デジタル画像とC言語.
可視面・不可視面の判定方法と隠れ面(不可視面)の消去法について述べる.
プログラミング基礎a 第10回 Javaによる図形処理入門(2) GUIの使い方
プログラミング基礎a 第12回 Java言語による図形処理入門(3) アニメーション入門
プログラミング基礎a 第11回 Java言語による図形処理入門(3) アニメーション入門
プロジェクト演習Ⅱ インタラクティブゲーム制作
コンピュータグラフィックス 実習3: 光線追跡法
高度情報演習1A スクリーンセーバ作成 2016年4月13日 情報工学科 篠埜 功.
プロジェクト演習Ⅳ・Ⅵ インタラクティブゲーム制作
プログラミング入門2 第13回、14回 総合演習 情報工学科 篠埜 功.
Excelによる3-D/等高線グラフの描画 2変数関数の描画 Excel によるグレイスケールマップ風描画
プロジェクト演習III,V <インタラクティブ・ゲーム制作> プログラミングコース
第5回 プログラミングⅡ 第5回
バネモデルの シミュレータ作成 精密工学科プログラミング基礎 資料.
精密工学科プログラミング基礎 第7回資料 (11/27実施)
シミュレーション演習 G. 総合演習 (Mathematica演習) システム創成情報工学科
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
Cp-1. Microsoft Visual Studio 2019 C++ の使い方 (C プログラミング演習,Visual Studio 2019 対応) 金子邦彦.
精密工学科プログラミング基礎Ⅱ 第2回資料 今回の授業で習得してほしいこと: 配列の使い方 (今回は1次元,次回は2次元をやります.)
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
スライドの終わりまでテキストが繰り返しスクロールされます • スライドの終わりまでテキストが繰り返しスクロールされます •
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
情報処理Ⅱ 2005年11月25日(金).
プログラミング入門2 第5回 配列 変数宣言、初期化について
CGと形状モデリング 授業資料 1,2限: 大竹豊(東京大学) 3,4限: 俵 丈展(理化学研究所)
情報処理Ⅱ 小テスト 2005年2月1日(火).
計算機プログラミングI 第2回 2002年10月17日(木) 履習登録 複習 ライブラリの利用 (2.6-7) 式・値・代入 (2.6-8)
Presentation transcript:

免許法認定公開講座: コンピュータグラフィックス コンピュータグラフィックス 第6回 2005/12/11 免許法認定公開講座: コンピュータグラフィックス 第6回 3次元グラフィックス 演習 九州工業大学 情報工学部 システム創成情報工学科 尾下 真樹

演習内容 基本的な3次元グラフィックスのプログラムを作成 OpenGL を使ったポリゴン描画 視点操作 アニメーション

参考書 最低限の関数は資料で説明 OpenGLの定番の本(高い) 入門書 OpenGLプログラミングガイド(赤本), 12,000円 共に、ピアソン・エデュケーション出版 入門書 OpenGL入門, 3,000円 エドワード・エンジェル 著、 滝沢 徹・牧野 祐子 訳 ピアソン・エデュケーション出版 赤本の廉価版的位置づけ

演習環境 C言語 OpenGL + GLUT ライブラリ まずは、サンプルプログラムをコンパイルしてみましょう! 開発環境として Borland C++ を使用 プログラムの記述にはテキストエディタを使用 OpenGL + GLUT ライブラリ OpenGL Zバッファ法によるポリゴン描画 GLUT OpenGLを使ったプログラムを簡単に作成する補助ライブラリ まずは、サンプルプログラムをコンパイルしてみましょう!

サンプルプログラム・データ opengl.cpp bitmap.h, bitmap.cpp kyushu.bmp OpenGL&GLUTを使ったサンプルプログラム bitmap.h, bitmap.cpp BMP画像の読み書きのための関数のヘッダファイルとソースファイル (後で使用) kyushu.bmp サンプルのテクスチャ画像(後で使用)

サンプルプログラムのコンパイル コンパイル 動作確認 bcc32 -DWIN32 opengl.cpp コンパイルに成功すると、 opengl.exe が生成される 動作確認 opengl.exe を実行してみる 地面+1枚のポリゴンを描画 マウスの右ドラッグで視点回転

コンパイルの手順(1) サンプルプログラム一式を適当なフォルダに置く コマンド プロンプトを起動 ここでは、 仮に D:\opengl に置くとする コマンド プロンプトを起動 スタートメニューから、スタート → プログラム → アクセサリ → コマンド プロンプト を選択

コンパイルの手順(2) コマンドプロンプト上で、プログラムソースを置いたディレクトリに移動し、コンパイル ディレクトリ名は、適宜、自分がファイルを置いた位置に書き換える Dir と入力すると、ファイル一覧が確認できる ① プログラムソースを置いたディレ クトリに移動 1行目 Dドライブに移動 2行目 指定ディレクトリに移動 ② コンパイルを実行

プログラムの修正 テキストエディタを使って、プログラムを書き換える 「サクラエディタ」 を使った プログラムの書き換え opengl.cpp を右クリックし、 「SAKURAで開く」 プログラムを変更したら、再度コンパイルして実行 (再コンパイルを忘れないこと!)

OpenGL & GLUT入門

OpenGL OpenGL 現在、最も広く使われている3次元API ポリゴンの描画、Zバッファなどの3次元描画に必要な機能を提供 C言語を始め、いろんな言語から使える ポリゴンの描画、Zバッファなどの3次元描画に必要な機能を提供 ウィンドウ生成やマウス・キーボード入力などの処理の機能は持たない これらは、OSやウィンドウシステム固有の機能なので、各環境に応じたAPIを使って記述する必要がある 実装が大変、環境ごとに実装する必要がある

GLUT OpenGL Utility Toolkit (GLUT) OpenGL と GLUT を混同しないように注意 ウィンドウ生成やイベント処理などの環境依存の部分を共通化したライブラリ OpenGL標準ではないがかなり広く普及している 内部に各OS用のコードを含んでいるため、一度プログラムを作ればいろんな環境で動く 機能が限定されている代わりに非常にシンプル とりあえずOpenGLを使いたい場合に適している OpenGL と GLUT を混同しないように注意

ウィンドウシステムでのプログラミング ウィンドウシステムと協調して動作するプログラムを作成する必要がある ウィンドウシステム Windows などの、グラフィカルなインターフェースを持つシステム ウィンドウ管理やマウス操作などはシステムが処理 ユーザプログラムは、初期化処理を行った後は処理をウィンドウシステムに移す ウィンドウシステムは、画面の再描画やマウスの操作などのイベントが起こるたびにユーザプログラムに処理を一時的に戻す (イベントドリブン型)

イベントドリブン型プログラム コンソール・プログラム ウィンドウ・プログラム(イベントドリブン) 初期化処理 ユーザ・プログラム 入力待ち処理 終了処理 描画 マウス処理 ウィンドウシステム アニメーション処理 ウィンドウ・プログラム(イベントドリブン) ユーザ・プログラム 初期化処理 メイン処理 処理の流れ 終了処理

GLUTのイベントモデル イベントループとコールバック イベントが起こった時にそのイベントを処理する関数をあらかじめ登録しておく マウス操作などのイベントが起こったらあらかじめ登録した関数が呼ばれる(コールバック)

GLUTのイベントモデル これらの処理をコールバック関数としてGLUTに登録 ユーザ・プログラム GLUT 初期化処理 入力待ち処理 描画 マウス処理 アニメーション処理 終了処理

OpenGLの関数名 gl~ で始まる関数 glu~ で始まる関数 glut~ で始まる関数 OpenGLの標準関数 OpenGL Utility Library の関数 OpenGLの関数を内部で呼んだり、引数を変換したりすることで、使いやすくした補助関数 glut~ で始まる関数 GLUT(OpenGL Utility Toolkit)の関数 正式にはOpenGL標準ではない

OpenGLの関数名 同じ機能で、微妙に違う名前の関数がある 例: glVertex3f(x, y, z), glVertex3d(x, y, z) f は引数が float 型であることを表す d は引数が double 型であることを表す C言語なので、関数のオーバーロード(同じ名前で引数が異なる関数)はサポートしていない 必要に応じて使い分ける

サンプルプログラムの構成 グローバル変数の定義 コールバック関数 initEnvironment() main() display() reshape() mouse() motion() idle() initEnvironment() main()

コールバック関数 display() reshape() mouse() motion() idle() 再描画が必要な時に呼ばれる 地面と 1枚のポリゴンを描画 reshape() ウィンドウサイズ変更時に呼ばれる ウィンドウサイズに応じて視界、ビューポート変換の設定 mouse() マウスのボタンが押されたとき、離されたときに呼ばれる 右ボタンの押下状態を記録 motion() マウスがウィンドウ上でドラッグされたときに呼ばれる 右ドラッグに応じて視点の回転角度を変更 idle() 処理が空いた時に定期的に呼ばれる

サンプルプログラムの構成 ユーザ・プログラム GLUT main()関数initEnvironment()関数 初期化処理 glutMainLoop() 入力待ち処理 display()関数 描画 mouse()関数motion()関数 マウス処理 アニメーション処理 idle()関数 終了処理 main()関数

GLUTの初期化(メイン関数) GLUTの初期化 glutInit() glutInitDisplayMode() glutInitWindowSize() glutInitWindowPosition() glutCreateWindow() glutMainLoop() 各関数の説明は省略

コールバック関数の設定(メイン関数) コールバック関数の設定 関数の引数として関数を渡す(特殊な使い方) glutDisplayFunc() glutReshapeFunc() glutMouseFunc() glutMotionFunc() glutIdelFunc()

描画のための設定(初期化関数) initEnvironment()関数 描画に必要な最低限の設定 光源情報の設定 機能の有効化 (色指定、隠面消去、背面消去) 背景色の設定 各関数の説明は省略 光源情報などは変更しなくても構わない

描画処理 dysplay()関数 変換行列の設定とポリゴン描画については、後で詳しく説明 画面のクリア(glClear()関数) 変換行列の設定(ワールド座標系→カメラ座標系) 光源位置の設定 地面のポリゴンの描画 変換行列の設定(モデル座標系→カメラ座標系) ポリゴンの描画 描画画面を表示(glSwapBuffers()関数) 変換行列の設定とポリゴン描画については、後で詳しく説明

ウィンドウサイズ変更時の処理 reshape() コールバック関数 ウィンドウ内の描画範囲を設定 射影行列の設定 glViewport()関数 ここでは、画面全体に描画を行うように設定 射影行列の設定 gluPerspective()関数 ここでは、標準な射影になるよう設定 (視野角 45°) どちらも、描画を行う上で欠かせない設定

マウス操作時の処理 マウス操作のコールバック関数 mouse()関数 motion()関数 マウスのボタンが、押されたとき、または、離されたときに呼ばれる motion()関数 マウスのボタンが押された状態で、マウスが動かされたときに定期的に呼ばれる ボタンが押されない状態で、マウスが動かされたときに呼ばれる関数もある(今回は使用しない)

アイドル時の処理 描画やマウス入力を処理する必要がないときに定期的に呼ばれる関数 物体の位置・向きを少しずつ変化させるといった、アニメーションを実現するために利用できる サンプルプログラムでは、何も処理を行っていない(今後処理を追加)

サンプルプログラムの構成(確認) ユーザ・プログラム GLUT main()関数initEnvironment()関数 初期化処理 glutMainLoop() 入力待ち処理 display()関数 描画 mouse()関数motion()関数 マウス処理 アニメーション処理 idle()関数 終了処理 main()関数

描画処理の詳しい説明 描画関数(display()関数)の詳しい説明 変換行列の設定 ポリゴンの描画

変換行列の設定 OpenGLは、内部に変換行列を持っている プログラムから OpenGLの関数を呼び出すことで、変換行列を変更できる モデルビュー変換行列 射影変換行列 両者は別に扱った方が便利なので、別々に設定できるようになっている プログラムから OpenGLの関数を呼び出すことで、変換行列を変更できる

座標変換(復習) モデル座標系からスクリーン座標系への変換 y y z x x z y y x z x z ワールド座標系 モデル座標系 スクリーン 座標系 カメラ座標系 z z x

変換行列の設定 設定を行う変換行列の指定 変換行列の設定 glMatrixMode() どの変換行列を変更するのかを指定する glLoadIdentity() glTranslate()、glRotate() その他の設定関数

変換行列の指定 glMatrixMode( mode ) 設定する変換行列を指定する GL_MODELVIE GL_PROJECTION モデルビュー変換 (モデル座標系からカメラ座標系への変換) GL_PROJECTION 射影変換 (カメラ座標系からスクリーン座標系への変換)

変換行列の変更 glLoadIdentity() glTranslate( x, y, z ) 単位行列で初期化 glTranslate( x, y, z ) 平行移動変換をかける glRotate( angle, x, y, z ) 指定した軸周りの回転変換をかける angle は、1回転を360として指定

変換行列の変更 変換行列は順番に右側にかけられていく プログラムで後から記述した変換行列の方が、実際には先に計算される

サンプルプログラムの変換行列 サンプルプログラムのシーン設定 カメラと水平面の角度(仰角)は camera_ptich カメラと中心の間の距離は 15 ポリゴンを(0,1,0)の位置に描画 y z y x 15 (0,1,0) camera_pitch z x

サンプルプログラムの変換行列 モデル座標系 → カメラ座標系 への変換行列 x軸周りの回転 2つの平行移動変換の位置に注意 中心から15離れるということは、回転後の座標系で カメラを後方(z軸)に15下げることと同じ ワールド座標系→カメラ座標系 モデル座標系→ワールド座標系

変換行列の変更のプログラム マウス入力処理(motion()関数) // 右ボタンのドラッグ中であれば、マウスの移動量に応じて視点を回転 if ( drag_mouse_r ) { // マウスの縦移動に応じてX軸を中心に回転 camera_pitch -= ( my - last_mouse_y ) * 1.0; if ( camera_pitch < -90.0 ) camera_pitch = -90.0; else if ( camera_pitch > 0.0 ) camera_pitch = 0.0; } // 今回のマウス座標を記録 last_mouse_x = mx; last_mouse_y = my; // 再描画の指示を出す(描画のコールバック関数が呼ばれる) glutPostRedisplay();

変換行列の設定のプログラム 描画処理(display()関数) // 変換行列を設定(ワールド座標系→カメラ座標系) glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, - 15.0 ); glRotatef( - camera_pitch, 1.0, 0.0, 0.0 ); // 地面を描画(ワールド座標系で頂点位置を指定) ・・・・・・ // 変換行列を設定(モデル座標系→カメラ座標系) glTranslatef( 0.0, 1.0, 0.0 ); // ポリゴンを描画(モデル座標系で頂点位置を指定)

その他の変換行列の設定方法 変換行列の設定関数 射影行列の設定関数 今回はこれらの関数の説明は省略 glLookAt() カメラの位置と注視点の位置から変換行列を設定 glLoadMatrix(), glMustMatrix() 配列を使って変換行列を設定 or かける 射影行列の設定関数 glPerspective(), glFrustrum(), glOrth() 1つ目の関数はサンプルプログラムで使用 今回はこれらの関数の説明は省略

ポリゴンの描画 glBegin( type ) ~ glEnd() を使用 プリミティブの種類 glBegin( プリミティブの種類 ) この間にプリミティブを構成する頂点データを記述 glEnd() プリミティブの種類 GL_POINTS(点)、GL_LINES(線分)、GL_TRIANGLES(三角面)、GL_QUADS(四角面)、GL_POLYGON(ポリゴン)、他

頂点データの指定 glColor3f( r, g, b ) glNormal3f( nx, ny, nz ) これ以降の頂点の色を設定 glNormal3f( nx, ny, nz ) これ以降の頂点の法線を設定 glVertex3f( x, y, z ) 頂点座標を指定 色・法線は、最後に指定したものが使用される

サンプルポリゴンの描画(1) 地面のポリゴン ワールド座標系で頂点位置・法線を指定 真上(0,1,0)を向き、水平方向の長さ10の四角形 // 地面を描画 glBegin( GL_POLYGON ); glNormal3f( 0.0, 1.0, 0.0 ); glColor3f( 0.5, 0.8, 0.5 ); glVertex3f( 5.0, 0.0, 5.0 ); glVertex3f( 5.0, 0.0,-5.0 ); glVertex3f(-5.0, 0.0,-5.0 ); glVertex3f(-5.0, 0.0, 5.0 ); glEnd();

サンプルポリゴンの描画(2) ポリゴン モデル座標系で頂点位置・法線を指定 y x z glBegin( GL_TRIANGLES ); glColor3f( 0.0, 0.0, 1.0 ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f(-1.0, 1.0, 0.0 ); glVertex3f( 0.0,-1.0, 0.0 ); glVertex3f( 1.0, 0.5, 0.0 ); glEnd(); y (-1,1,0) (1,0.5,0) x z (0,-1,0)

サンプルプログラムの座標系 y z y x z x ワールド座標系→カメラ座標系 モデル座標系→ワールド座標系 15 (0,1,0) camera_pitch z x

サンプルプログラムのまとめ サンプルプログラムの構成 変換行列の設定 (display()関数) ポリゴンの描画 (display()関数) メイン関数と各コールバック関数 初期化処理 各コールバック関数の役割 変換行列の設定 (display()関数) ポリゴンの描画 (display()関数)

サンプルプログラムの構成(確認) ユーザ・プログラム GLUT main()関数initEnvironment()関数 初期化処理 glutMainLoop() 入力待ち処理 display()関数 描画 mouse()関数motion()関数 マウス処理 アニメーション処理 idle()関数 終了処理 main()関数

サンプルプログラムの拡張

サンプルプログラムの拡張 資料に従って、サンプルプログラムを少しずつ拡張しながら、OpenGLの使い方を学習 サンプルプログラムを修正するときは、自分でわざわざ打ち込まなくとも、コピー&ペースを活用すると早い ただし、各修正にどのような意味があるのか、きちんと理解しながら進めることが重要 理解しないままただコピーすると、間違えて違うところを修正してしまう可能性が高い

プログラム拡張の流れ 簡単なアニメーションの追加 より複雑なポリゴンモデルの描画 変換行列を使った視点操作 変換行列を使ったアニメーション テクスチャマッピング

簡単なアニメーション

ポリゴンの回転の変換行列 1枚のポリゴンを y軸を中心として回転させる 変換行列に y軸周りの回転を追加することで実現 y z x ワールド座標系→カメラ座標系 モデル座標系→ワールド座標系 y (0,1,0) theta_cycle z x

ポリゴンの回転のための変数 変数定義(先頭)、変数の変化(idle()関数) // アニメーションのための変数 float theta_cycle = 0.0; void idle( void ) { // theta_cycle を 0~360 まで繰り返し変化させる // (360まで来たら0に戻る) theta_cycle += 1.0; if ( theta_cycle > 360 ) theta_cycle -= 360; // 再描画の指示を出す(描画関数が呼ばれる) glutPostRedisplay(); }

ポリゴンの回転の追加 変換行列の設定(display()関数) // 変換行列を設定(ワールド座標系→カメラ座標系) glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, - 15.0 ); glRotatef( - camera_pitch, 1.0, 0.0, 0.0 ); // 地面を描画(ワールド座標系で頂点位置を指定) ・・・・・・ // 変換行列を設定(モデル座標系→カメラ座標系) glTranslatef( 0.0, 1.0, 0.0 ); glRotatef( theta_cycle, 0.0, 1.0, 0.0 ); // ポリゴンを描画(モデル座標系で頂点位置を指定)

裏面のポリゴンの描画 裏面が描画されない(背面消去のため)ので、 裏向きのポリゴンの描画を追加 glBegin( GL_TRIANGLES ); glColor3f( 0.0, 0.0, 1.0 ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f(-1.0, 1.0, 0.0 ); glVertex3f( 0.0,-1.0, 0.0 ); glVertex3f( 1.0, 0.5, 0.0 ); glColor3f( 1.0, 0.0, 0.0 ); glNormal3f( 0.0, 0.0,-1.0 ); glEnd(); 頂点の順序、法線の向きが 逆になる点に注目

修正箇所のまとめ 変数定義(先頭) 変数の変化(idle()関数) 変換行列の設定(display()関数)

ポリゴンモデルの描画

より複雑なポリゴンモデルの描画 四角すいの描画 配列を使った四角すいの描画 配列を使った直方体の描画 三角面の集合として描画 ポリゴンデータを配列に格納 配列を使った直方体の描画 四角面の集合として描画

四角すいの描画 四角すいを構成する頂点と三角面 y x z 三角面 { V0, V3, V1 } { V0, V2, V4 } 法線 { 0.0, 0.53, 0.85 } { 0.0, 0.53, -0.85 } { 0.85, 0.53, 0.0 } { -0.85, 0.53, 0.0 } { 0.0, -1.0, 0.0 } y V0 (0.0, 0.8, 0.0) x V4 V2 V3 V1 (1.0, -0.8, 1.0) z

面の法線の計算方法 ポリゴンの2辺の外積から計算できる N N=(V3 - V1)×( V2 - V1) V1 長さが 1 になるよう正規化

ポリゴンモデルの描画方法 いくつかの描画方法がある 主な描画方法 (今回は簡単な2通りのみを扱う) プログラムからOpenGLに頂点データを与えるのにいろいろなやり方がある 主な描画方法 (今回は簡単な2通りのみを扱う) glVertex() 関数に直接頂点座標を記述 頂点データの配列を使う方法 頂点配列を使う方法 頂点データとインデックスの配列を使う方法 頂点配列とインデックス配列を使う方法 OpenGLの頂点配列の機能を使うことで、より高速に描画できる(今回は扱わない)

方法1 最も基本的な描画方法 サンプルプログラムと同様の描画方法 glVertex() 関数の引数に直接頂点座標を記述

四角すいの描画(1) 四角すいを描画する新たな関数を追加 void renderPyramid() { glBegin( GL_TRIANGLES ); // +Z方向の面 glNormal3f( 0.0, 0.53, 0.85 ); glVertex3f( 0.0, 1.0, 0.0 ); glVertex3f(-1.0,-0.8, 1.0 ); glVertex3f( 1.0,-0.8, 1.0 ); ・・・・・・ glEnd(); }

四角すいの描画(2) 描画関数から四角すいの描画関数を呼び出し 修正の場所を間違えないように注意 renderPyramid()関数では色は使用されていないので、呼び出す前に色を設定している void display( void ) { ・・・・・・ // 中心に四角すいを描画((0,1,0) に移動) glTranslatef( 0.0, 1.0, 0.0 ); glColor3f( 1.0, 0.0, 0.0 ); renderPyramid(); }

この描画方法の問題点 問題点 解決方法 同じ頂点が共通して使われている プログラムが長くなる モデルデータの修正がしにくい モデルデータがプログラムとして記述されているので、ファイルから動的に読み込んだりするようなことができない 解決方法 モデルデータを配列に格納する

方法2 配列を使った描画方法 頂点・ポリゴンのデータを配列に格納 描画関数では、配列のデータを順に参照しながら描画 必要な配列(サンプルプログラムの例) 頂点座標(x,y,z)×頂点数 三角面を構成する頂点番号(v0,v1,v2)×三角面数 三角面の法線(x,y,z)×三角面数

三角面インデックス 頂点データの配列と、三角面インデックスの配列に分けて管理する 三角面インデックス 面1 面2 面3 面4 面5 面6 面1 面2 面3 面4 面5 面6 面1 面2 面3 面4 面5 面6 何番目の頂点データを使うかという情報 頂点データ(座標, 法線, 色など) ※ 頂点の重複がなくなる ※ 頂点の重複がある 頂点データ(座標, 法線, 色など)

配列を使った四角すいの描画(1) 配列データの定義 const int num_pyramid_vertices = 5; // 頂点数 const int num_pyramid_triangles = 6; // 三角面数 // 角すいの頂点座標の配列 float pyramid_vertices[ num_pyramid_vertices ][ 3 ] = { { 0.0, 1.0, 0.0 }, { 1.0,-0.8, 1.0 }, { 1.0,-0.8,-1.0 }, ・・・・・・ }; // 三角面インデックス(各三角面を構成する頂点の頂点番号)の配列 int pyramid_tri_index[ num_pyramid_triangles ][ 3 ] = { { 0,3,1 }, { 0,2,4 }, { 0,1,2 }, { 0,4,3 }, { 1,3,2 }, { 4,2,3 } // 三角面の法線ベクトルの配列(三角面を構成する頂点座標から計算) float pyramid_tri_normals[ num_pyramid_triangles ][ 3 ] = { { 0.00, 0.53, 0.85 }, // +Z方向の面 ・・・・・・

配列を使った四角すいの描画(2) 配列データを参照しながら三角面を描画 void renderPyramid() { int i, j, v_no; glBegin( GL_TRIANGLES ); for ( i=0; i<num_pyramid_triangles; i++ ) glNormal3f( pyramid_tri_normals[i][0],・・[i][1],・・ [i][2] ); for ( j=0; j<3; j++ ) v_no = pyramid_tri_index[ i ][ j ]; glVertex3f( pyramid_vertices[ v_no ][0], ・・・[ v_no ][1], ・・・ } glEnd();

直方体の描画 別のポリゴンモデル(直方体)の描画 1枚は空欄にしているので、各自、適切な頂点番号を考えて追加する y ? x z 四角面 { V2, V3, V1 , V0 } { V7, V6, V4 , V5 } { V2, V0, V4 , V6 } { V3, V7, V5 , V1 } { V3, V2, V6 , V7 } { V0, V1, V5 , V4 } 法線 { 0.0, 0.0, 1.0 } { 0.0, 0.0, -1.0 } { 1.0, 0.0, 0.0 } { -1.0, 0.0, 0.0 } { 0.0, 1.0, 0.0 } { 0.0, -1.0, 0.0 } (-0.4, 1.0, -0.2) V7 V6 y V3 V2 (0.4, 1.0, 0.2) V5 ? x V4 V1 V0 (0.4, 0.0, 0.2) z

配列を使った直方体の描画(1) 配列データの定義 四角面を使うので、各面の頂点数が4個になる { 0.4, 0.0, 0.2 }, // 0 const int num_cube_vertices = 8; // 頂点数 const int num_cube_quads = 6; // 四角面数 // 頂点座標の配列 float cube_vertices[ num_cube_vertices ][ 3 ] = { { 0.4, 0.0, 0.2 }, // 0 ・・・・・・ {-0.4, 1.0,-0.2 }, // 7 }; // 四角面インデックス(各四角面を構成する頂点の頂点番号)の配列 int cube_index[ num_cube_quads ][ 4 ] = { { 2,3,1,0 }, { 7,6,4,5 }, { 2,0,4,6 }, { 3,7,5,1 }, { 3,2,6,7 }, { 0,1,5,4 }

配列を使った直方体の描画(2) 配列データの定義(続き) 今回は各面の色も指定する // 四角面の法線ベクトルの配列(四角面を構成する頂点座標から計算) float cube_normals[ num_cube_quads ][ 3 ] = { { 0.00, 0.00, 1.00 }, { 0.00, 0.00,-1.00 }, ・・・・・・ { 0.00,-1.00, 0.00 } }; // 四角面のカラーの配列 float cube_colors[ num_cube_quads ][ 3 ] = { { 0.00, 1.00, 0.00 }, { 1.00, 0.00, 1.00 }, { 1.00, 1.00, 0.00 } };

配列を使った直方体の描画(3) 配列データを参照しながら四角面を描画 void renderCube() { int i, j, v_no; glBegin( GL_QUADS ); for ( i=0; i<num_cube_quads; i++ ) glNormal3f( cube_normals[i][0],・・[i][1],・・ [i][2] ); glColor3f( cube_colors[i][0], ・・・[i][1], ・・・[i][2] ); for ( j=0; j<4; j++ ) v_no = cube_index[ i ][ j ]; glVertex3f( cube_vertices[v_no][0], ・・[v_no][1], ・・[v_no][2] ); } glEnd();

配列を使った直方体の描画(4) 描画関数から直方体の描画関数を呼び出し 適切な位置(移動の変換行列)を設定 色の指定は不要 ? void display( void ) { ・・・・・・ // 中心に直方体を描画 glTranslatef( 0.0, 0.0, 0.0 ); glColor3f( 1.0, 0.0, 0.0 ); renderCube(); } ?

変換行列を使った視点操作

視点操作の拡張 左ドラッグで距離を操作できるように拡張 y z y x z x ワールド座標系→カメラ座標系 モデル座標系→ワールド座標系 camera_distance y x (0,1,0) camera_pitch z x

視点操作の拡張 プログラムの修正箇所(多いので注意) 左ボタンの押下状態を記録する変数を追加 カメラと原点の距離を記録する変数を追加 mouse()関数に、左ボタンの押下状態を更新する処理を追加 motion()関数に、左ドラッグに応じて camera_distance を変更する処理を追加 一定値以上は近づかないように制限 display()関数を、camera_distance に応じて変換行列を設定するように変更

変換行列によるアニメーション

変換行列によるアニメーション 変換行列を組み合わせることで、さまざまな運動を実現できる idle()関数 dysplay()関数 運動を表す媒介変数の変化を記述 dysplay()関数 媒介変数の値に応じて、回転角度や移動距離を設定

アニメーションに使用する変数 資料に従って、いくつかの媒介変数を追加 theta_cycle theta_repeat move 0~360 へ単調増加、360 になったら 0 に戻る theta_repeat 0~180 の間を往復、180 になったら減少を始める theta_cycle から計算できる move 0~1 の間を加速度つきで往復 1に近づくと速度が減少 theta_cycle2, theta_repeat2

アニメーションの例 一定速度で回転運動 一定位置で回転運動 一定速度で回転運動(常に正面を向く) 一定速度で往復回転運動 一定速度で上下に往復移動運動 加速度つきで上下に往復移動運動 複数の物体の運動の組み合わせ

例1:一定速度で回転運動 移動→回転の順に適用 移動にも回転が適用されるので、半径1.5で回転 y z x ワールド座標系→カメラ座標系 モデル座標系→ワールド座標系 y z x

例2:一定位置で回転運動 回転→移動の順に適用(順序を逆) 常に同じ位置に移動するので、その場で回転 y z x

例3:一定速度で回転運動2 常に正面を向くようにするためには? 最初に逆方向に回転しておくことで、次の回転をキャンセル (移動にのみ回転がかかる) y z x

例4:一定速度で往復回転運動 変換行列は例1と同じ、異なる変数を使用 変数の変化(idle()関数) と 変換行列の設定(display()関数)の組み合わせが重要 y z x

例5:一定速度で上下に往復移動 回転だけではなく、位置に変数を使用することもできる めり込みを避けるために y座標値を +1 している y z x

例6:加速度つきで上下に往復運動 変数の変化を工夫することで、移動速度を変化させるようなこともできる ここでは三角関数の絶対値を利用 0~360 を 0~2πに変換している void idle( void ) { // move を 0~1 の間で反復変化させる //(三角関数を用いることで、一定速度でなはなく、 // 0 の近くで速度が小さく // 180 の近くで速度が大きくなるように変化させる) move = fabs( sin( theta_cycle * 3.1415926 / 180.0 ) ); }

例7:複数の物体の運動 それぞれ異なる変換行列を使用して描画

変換行列の退避・復元 現在の変換行列を記録しておき、後から復元することができる glPushMatrix() glPopMatrix() 記録した変換行列はスタックに記録される glPushMatrix() 現在の変換行列の退避 スタックに積む glPopMatrix() 最後に退避した変換行列の回復 スタックから取り出す

変換行列の退避・復元の例 ワールド座標系からカメラ座標系への 変換行列を設定 地面を描画 行列を退避 物体1からワールド座標系への変換行列 コンピュータグラフィックス 第6回 2005/12/11 変換行列の退避・復元の例 ワールド座標系からカメラ座標系への 変換行列を設定 地面を描画 行列を退避 物体1からワールド座標系への変換行列 物体1を描画 行列を回復 物体2からワールド座標系への変換行列 物体2を描画 World → Camera World → Camera Obj1 → World World → Camera World → Camera Obj2 → World

変換行列の退避・復元の例 プログラムの例 void display( void ) { コンピュータグラフィックス 第6回 2005/12/11 変換行列の退避・復元の例 プログラムの例 void display( void ) { // ここまででワールド座標系からカメラ座標系への変換設定 // 地面を描画 // 例7:2つの物体を描画(異なる周期で往復回転運動) glPushMatrix(); glRotatef( theta_cycle2, 0.0, 1.0, 0.0 ); glTranslatef( 0.0, 0.0, 3.0 ); renderCube(); glPopMatrix(); glRotatef( theta_cycle, 0.0f, 1.0f, 0.0f ); glTranslatef( 0.0f, 0.0f, 1.5f ); }

テクスチャマッピング

テクスチャマッピング 地面にテクスチャマッピングを適用して描画 各頂点に、テクスチャ座標(u,v)を指定 v (0.0, 1.0) (1.0, 1.0) (0.0, 0.0) (1.0, 0.0) u

テクスチャマッピングのための修正 プログラムの修正箇所 コンパイル方法(bitmap.cppを一緒にコンパイル) テクスチャ画像を格納する変数を追加 テクスチャ画像の読み込み処理、テクスチャマッピングの設定処理、を追加 画像の読み込みには bitmap.cpp の関数を使用 地面にテクスチャマッピングを行う処理を追加 テクスチャマッピングの有効化 各頂点にテクスチャ座標を設定 コンパイル方法(bitmap.cppを一緒にコンパイル) bcc32 -DWIN32 opengl.cpp bitmap.cpp

レポート課題 課題1 ポリゴンモデルの描画 課題2 視点操作の拡張 課題3 アニメーションの追加 作成したプログラムのソースファイルを提出 締め切り 12月16日(土)17:00 基本的には今日中に終わらせて提出することを想定 レポート(文章)は提出しなくとも良い bitmap.cpp, bitmap.h やテクスチャ画像はつけなくて良い ファイル名を st??.cpp (自分のアカウント名) として提出

課題1 ポリゴンモデルの描画 矢印(初心者マーク)の描画するプログラムを作成せよ y x z V10 V8 V6 V4 V2 V0 V11

課題1 ポリゴンモデルの描画 矢印(初心者マーク)のポリゴンデータ 三角面 or 四角面の配列、描画関数を作成 頂点の順番は変えても良い y 頂点座標 V0 { 0.0, 0.8, 0.2 } V1 { 0.0, 0.0, 0.2 } V2 { 0.4, 1.0, 0.2 } V3 { 0.4, 0.2, 0.2 } V4 {-0.4, 1.0, 0.2 } V5 {-0.4, 0.2, 0.2 } V6 { 0.0, 0.8,-0.2 } V7 { 0.0, 0.0,-0.2 } V8 {-0.4, 1.0,-0.2 } V9 {-0.4, 0.2,-0.2 } V10 { 0.4, 1.0,-0.2 } V11 { 0.4, 0.2,-0.2 } V10 V8 y V6 V4 V2 V0 V11 V9 V7 x V5 V3 V1 z

課題1のヒント(1) 直方体と同様に頂点・四角面の配列を定義 ? ? ? ? ? ? const int num_leaf_vertices = ; // 頂点数 const int num_leaf_quads = ; // 四角面数 // 頂点座標の配列 float leaf_vertices[ num_leaf_vertices ][ 3 ] = { }; // 三角面インデックス(各三角面を構成する頂点の頂点番号)の配列 int cube_index[ num_leaf_quads ][ 4 ] = { }; // 四角面の法線ベクトルの配列(四角面を構成する頂点座標から計算) float cube_normals[ num_cube_quads ][ 3 ] = { }; // 四角面のカラーの配列 float cube_colors[ num_cube_quads ][ 3 ] = { }; ? ? ? ? ? ?

課題1のヒント(2) 描画関数も直方体と同じ(変数名を変更) void renderLeaf() { int i, j, v_no; glBegin( GL_QUADS ); for ( i=0; i<num_leaf_quads; i++ ) glNormal3f( cube_normals[i][0],・・[i][1],・・ [i][2] ); glColor3f( cube_colors[i][0], ・・・[i][1], ・・・[i][2] ); for ( j=0; j<4; j++ ) v_no = cube_index[ i ][ j ]; glVertex3f( cube_vertices[v_no][0], ・・[v_no][1], ・・[v_no][2] ); } glEnd();

課題2 視点操作の拡張 左右に右ドラッグすると、視点が横に回転する(方位角が変化する)機能を追加せよ 変数を追加(camera_yaw) 変数の操作を追加(motion()関数) 変換行列の計算を追加(display()関数)

課題2のヒント 先に変換行列を考えてからプログラム作成 y z y x z x ワールド座標系→カメラ座標系 モデル座標系→ワールド座標系 camera_distance y x camera_pitch 追加する場所が違うと、正しく動作しないので注意! z camera_yaw x

課題3 アニメーションの追加 指定されたアニメーションを実現 物体1~物体6 の運動を実現 サンプルプログラムを参照 opengl_report.exe 変数にはサンプルプログラム と同じものを使って良い まずは各物体の変換行列を 考えてから、プログラムを作 成すると良い

課題3 アニメーションの追加 中心で移動しないまま、一定速度で回転運動 物体1の周囲を一定速度で回転運動、物体1と同じ方向を向いている 物体2の真上で上下に放物反復移動、常に正面を向いている 物体3の真上で左右に反復回転運動、物体3と同じ方向を向いている 物体1の正面で前後に等速反復移動、常に正面を向いている