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

Similar documents
コンピューターグラフィックスS

コンピューターグラフィックスS

コンピュータグラフィックスS 演習資料

コンピュータグラフィックス特論Ⅱ

コンピュータグラフィックス特論Ⅱ

コンピュータグラフィックスS 演習資料

スライド 1

演算増幅器

コンピュータグラフィックス基礎              No

コンピュータグラフィックス第8回

(1) プログラムの開始場所はいつでも main( ) メソッドから始まる 順番に実行され add( a,b) が実行される これは メソッドを呼び出す ともいう (2)add( ) メソッドに実行が移る この際 add( ) メソッド呼び出し時の a と b の値がそれぞれ add( ) メソッド

C#の基本

Microsoft PowerPoint - info_eng3_05ppt.pptx

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

コンピュータグラフィックス特論Ⅱ

演算増幅器

問 1 図 1 の図形を作るプログラムを作成せよ 但し ウィンドウの大きさは と し 座標の関係は図 2 に示すものとする 図 1 作成する図形 原点 (0,0) (280,0) (80,0) (180,0) (260,0) (380,0) (0,160) 図 2 座標関係 問 2

PowerPoint プレゼンテーション

コンピュータグラフィックス演習 I 2012 年 5 月 21 日 ( 月 )5 限 担当 : 桐村喬 第 7 回モデリングの仕上げ 1 カメラワークとアニメーション 今日の内容 1. カメラワーク 2. シーンの設定 3. アニメーション 前回のテクスチャの紹介 1 / 10

Microsoft Word - mediaJikkenCG_no2_2012.doc

医用工学概論  Medical Engineering (ME)   3年前期の医用工学概論実習と 合わせ、 医療の現場で使用されている 医用機器を正しく安全に使用するために必要な医用工学(ME)の 基礎知識を習得する。

Microsoft PowerPoint - 04.pptx

Microsoft Word - mediaJikkenCG_no2_2007.doc

謗域・ュ逕ィppt

pp2018-pp9base

プログラミング実習I

メソッドのまとめ

Microsoft PowerPoint - kougi4.ppt

数はファイル内のどの関数からでも参照できるので便利ではありますが 変数の衝突が起こったり ファイル内のどこで値が書き換えられたかわかりづらくなったりなどの欠点があります 複数の関数で変数を共有する時は出来るだけ引数を使うようにし グローバル変数は プログラムの全体の状態を表すものなど最低限のものに留

Prog1_10th

スライド 1

コンピュータグラフィックス第6回

4 正しい位置を持った 数値地図 25000( 空間データ基盤 ) の上に カラー空中写真 が読み込まれます この状態では カラー空中写真画像 は位置のデータを持っていないので 正しい位置に読み込まれていません ここから 画像位置合せ の作業を行います 地図画像は色調を変えることができます 薄くする

CG

コンピューターグラフィックスS

ToDo: 今回のタイトル

Microsoft PowerPoint - Borland C++ Compilerの使用方法(v1.1).ppt [互換モード]

コンピューターグラフィックスS

スライド 1

Windows用タブレットドライバー簡易ガイド

沼津工業高等専門学校

Microsoft Word - Training10_プリプロセッサ.docx

/*Source.cpp*/ #include<stdio.h> //printf はここでインクルードして初めて使えるようになる // ここで関数 average を定義 3 つの整数の平均値を返す double 型の関数です double average(int a,int b,int c){

vecrot

ゲームエンジンの構成要素

Microsoft PowerPoint Java基本技術PrintOut.ppt [互換モード]

Microsoft Word - povray.docx

pp2018-pp4base

ARToolKit プログラムの仕組み 1: ヘッダファイルのインクルード 2: Main 関数 3: Main Loop 関数 4: マウス入力処理関数 5: キーボード入力処理関数 6: 終了処理関数 3: Main Loop 関数 1カメラ画像の取得 2カメラ画像の描画 3マーカの検出と認識

PowerPoint Presentation

Windows用タブレットドライバー簡易ガイド Ver.5.06版

Microsoft Word - macマニュアル【 】.doc

7 ポインタ (P.61) ポインタを使うと, メモリ上のデータを直接操作することができる. 例えばデータの変更 やコピーなどが簡単にできる. また処理が高速になる. 7.1 ポインタの概念 変数を次のように宣言すると, int num; メモリにその領域が確保される. 仮にその開始のアドレスを 1

第2章 Macintoshの基本操作

JDK のインストール (2012 年 8 月時点でのバージョン ) Java の実行環境 開発環境は さまざまな企業 団体が開発 配布を行っているが 当テキストでは Java の生みの親である Sun MicroSystems 社 ( 現 Oracle 社 ) の実行環境 開発環境を使用する Ja

イントロダクション

Computer Graphics

インテル(R) Visual Fortran コンパイラ 10.0

今回のプログラミングの課題 ( 前回の課題で取り上げた )data.txt の要素をソートして sorted.txt というファイルに書出す ソート (sort) とは : 数の場合 小さいものから大きなもの ( 昇順 ) もしくは 大きなものから小さなもの ( 降順 ) になるよう 並び替えること

関数の定義域を制限する 関数のコマンドを入力バーに打つことにより 関数の定義域を制限することが出来ます Function[ < 関数 >, <x の開始値 >, <x の終了値 > ] 例えば f(x) = x 2 2x + 1 ( 1 < x < 4) のグラフを描くには Function[ x^

プログラミング入門1

Microsoft PowerPoint - kougi2.ppt

イントロダクション

Word編2 宛先の氏名を入力する職人編宛名を入力するための画面が表示されます 姓と名の間にスペースを入れて氏名を入力します ボタンをクリックして敬称を選びます [ 連名 情報 ] タブをクリックします 必要に応じて [ 名前 ] 欄をクリックして連名を入力します 3 宛先の住所を入力する [ 自宅

0 21 カラー反射率 slope aspect 図 2.9: 復元結果例 2.4 画像生成技術としての計算フォトグラフィ 3 次元情報を復元することにより, 画像生成 ( レンダリング ) に応用することが可能である. 近年, コンピュータにより, カメラで直接得られない画像を生成する技術分野が生

PowerPoint2003基礎編

Field Logic, Inc. 標準モード 3D モデル作成 配置編 Field Logic, Inc. 第 1 版

Microsoft PowerPoint - CproNt02.ppt [互換モード]

Wordの学習

Fortran 勉強会 第 5 回 辻野智紀

目次 1. ログイン ログアウト デスクトップ ( 例 :Word Excel 起動中 ) Dock( 例 :Word Excel 起動中 ) Finder ウィンドウ メニューバー ( 例 :Word 起動中 )...

情報工学実験Ⅲ

Java Scriptプログラミング入門 3.6~ 茨城大学工学部情報工学科 08T4018Y 小幡智裕

Microsoft PowerPoint - VBA解説1.ppt [互換モード]

簡単な図面を書いてみよう 『 3D編 』

PowerPoint プレゼンテーション

Prog2_9th

「MT-3_2-ja

Microsoft PowerPoint P演習 第10回 関数.ppt [互換モード]

Microsoft PowerPoint - 11.pptx

プレサリオ ステップアップ

02: 変数と標準入出力

memo

書式に示すように表示したい文字列をダブルクォーテーション (") の間に書けば良い ダブルクォーテーションで囲まれた文字列は 文字列リテラル と呼ばれる プログラム中では以下のように用いる プログラム例 1 printf(" 情報処理基礎 "); printf("c 言語の練習 "); printf

ポインタ変数

Microsoft Word - no11.docx

PowerPoint Presentation

02: 変数と標準入出力

携帯電話を登録する 3 携帯電話で教員からのお知らせおよびレポート課題の情 報が得られます. 従来型携帯電話を利用するための情報登 録はパソコンを使って行います. スマートフォンユーザは スマートフォンユ ーザ向けガイド を参照してください. 携帯メールアドレスの登録 授業選択領域にて My Wor

Microsoft Word A02

Microsoft PowerPoint - [150421] CMP実習Ⅰ(2015) 橋本 CG編 第1回 幾何変換.pptx

ex05_2012.pptx

次の病院 薬局欄は 氏名 欄に入力された値によって入力すべき値が変わります 太郎の行く病院と花子の行く病院が必ずしも同じではないからです このような違いを 設定 シートで定義しておきましょう 太郎の行く病院のリストを 太郎 花子の行く病院のリストを 花子 として 2 つのリストが定義されています こ

モデリングとは

中綴じ3・4級.ren

OpenGL & GLUTの基本関数の説明

Prog1_12th

プログラミング入門1

第32回_プレゼン資料_菅原(Unityはじめるよ~上半身だけ動かす2~)

Microsoft Word - VisualBaseManual0.doc

Transcription:

演習内容 免許法認定公開講座 : コンピュータグラフィックス 第 6 回 3 次元グラフィックス演習 基本的な3 次元グラフィックスのプログラムを作成 OpenGL を使ったポリゴン描画 視点操作 アニメーション 九州工業大学情報工学部システム創成情報工学科尾下真樹 参考書 最低限の関数は資料で説明 OpenGLの定番の本 ( 高い ) OpenGLプログラミングガイド ( 赤本 ), 12,000 円 OpenGLリファレンスマニュアル ( 青本 ), 8,300 円 共に ピアソン エデュケーション出版 入門書 OpenGL 入門, 3,000 円 エドワード エンジェル著 滝沢徹 牧野祐子訳 ピアソン エデュケーション出版 赤本の廉価版的位置づけ 演習環境 C 言語 開発環境として Borland C++ を使用 プログラムの記述にはテキストエディタを使用 OpenGL + GLUT ライブラリ OpenGL Z バッファ法によるポリゴン描画 GLUT OpenGL を使ったプログラムを簡単に作成する補助ライブラリ まずは サンプルプログラムをコンパイルしてみましょう! サンプルプログラム データ opengl.cpp OpenGL&GLUT を使ったサンプルプログラム bitmap.h, bitmap.cpp BMP 画像の読み書きのための関数のヘッダファイルとソースファイル ( 後で使用 ) kushu.bmp サンプルのテクスチャ画像 ( 後で使用 ) サンプルプログラムのコンパイル コンパイル bcc32 -DWIN32 opengl.cpp コンパイルに成功すると opengl.ee が生成される 動作確認 opengl.ee を実行してみる 地面 +1 枚のポリゴンを描画 マウスの右ドラッグで視点回転 1

コンパイルの手順 (1) サンプルプログラム一式を適当なフォルダに置く ここでは 仮に D: opengl に置くとする コマンドプロンプトを起動 スタートメニューから スタート プログラム アクセサリ コマンドプロンプトを選択 コンパイルの手順 (2) コマンドプロンプト上で プログラムソースを置いたディレクトリに移動し コンパイル ディレクトリ名は 適宜 自分がファイルを置いた位置に書き換える Dir と入力すると ファイル一覧が確認できる 1 プログラムソースを置いたディレクトリに移動 1 行目 D ドライブに移動 2 行目指定ディレクトリに移動 2 コンパイルを実行 プログラムの修正 テキストエディタを使って プログラムを書き換える サクラエディタ を使ったプログラムの書き換え opengl.cpp を右クリックし SAKURAで開く OpenGL & GLUT 入門 プログラムを変更したら 再度コンパイルして実行 ( 再コンパイルを忘れないこと!) OpenGL OpenGL 現在 最も広く使われている 3 次元 API C 言語を始め いろんな言語から使える ポリゴンの描画 Zバッファなどの3 次元描画に必要な機能を提供 ウィンドウ生成やマウス キーボード入力などの処理の機能は持たない これらは OSやウィンドウシステム固有の機能なので 各環境に応じたAPIを使って記述する必要がある 実装が大変 環境ごとに実装する必要がある GLUT OpenGL Utilit Toolkit (GLUT) ウィンドウ生成やイベント処理などの環境依存の部分を共通化したライブラリ OpenGL 標準ではないがかなり広く普及している 内部に各 OS 用のコードを含んでいるため 一度プログラムを作ればいろんな環境で動く 機能が限定されている代わりに非常にシンプル とりあえず OpenGL を使いたい場合に適している OpenGL と GLUT を混同しないように注意 2

ウィンドウシステムでのプログラミング イベントドリブン型プログラム ウィンドウシステムと協調して動作するプログラムを作成する必要がある ウィンドウシステム Windows などの グラフィカルなインターフェースを持つシステム ウィンドウ管理やマウス操作などはシステムが処理 ユーザプログラムは 初期化処理を行った後は処理をウィンドウシステムに移す ウィンドウシステムは 画面の再描画やマウスの操作などのイベントが起こるたびにユーザプログラムに処理を一時的に戻す ( イベントドリブン型 ) コンソール プログラム 理の流れメイン処理処GLUTのイベントモデル ユーザ プログラム 初期化処理 終了処理 ウィンドウ プログラム ( イベントドリブン ) ユーザ プログラムウィンドウシステム初期化処理描画マウス処理入力待ち処理アニメーション処理終了処理 GLUT のイベントモデル イベントループとコールバック イベントが起こった時にそのイベントを処理する関数をあらかじめ登録しておく プログラムは初期化が終わったら GLUT に処理を移す マウス操作などのイベントが起こったらあらかじめ登録した関数が呼ばれる ( コールバック ) これらの処理をコールバック関数として GLUT に登録 ユーザ プログラム初期化処理描画マウス処理 GLUT 入力待ち処理 アニメーション処理 終了処理 OpenGL の関数名 gl~ で始まる関数 OpenGL の標準関数 glu~で始まる関数 OpenGL Utilit Librar の関数 OpenGLの関数を内部で呼んだり 引数を変換したりすることで 使いやすくした補助関数 glut~で始まる関数 GLUT(OpenGL Utilit Toolkit) の関数 正式にはOpenGL 標準ではない OpenGL の関数名 同じ機能で 微妙に違う名前の関数がある 例 : glverte3f(,, ), glverte3d(,, ) f は引数が float 型であることを表す d は引数が double 型であることを表す C 言語なので 関数のオーバーロード ( 同じ名前で引数が異なる関数 ) はサポートしていない 必要に応じて使い分ける 3

サンプルプログラムの構成 グローバル変数の定義 コールバック関数 displa() reshape() mouse() motion() idle() initenvironment() main() コールバック関数 displa() 再描画が必要な時に呼ばれる 地面と 1 枚のポリゴンを描画 reshape() ウィンドウサイズ変更時に呼ばれる ウィンドウサイズに応じて視界 ビューポート変換の設定 mouse() マウスのボタンが押されたとき 離されたときに呼ばれる 右ボタンの押下状態を記録 motion() マウスがウィンドウ上でドラッグされたときに呼ばれる 右ドラッグに応じて視点の回転角度を変更 idle() 処理が空いた時に定期的に呼ばれる サンプルプログラムの構成 GLUT の初期化 ( メイン関数 ) main() 関数 initenvironment() 関数 displa() 関数 mouse() 関数 motion() 関数 idle() 関数 ユーザ プログラム初期化処理描画マウス処理アニメーション処理 GLUT glutmainloop() 入力待ち処理 GLUT の初期化 glutinit() glutinitdisplamode() glutinitwindowsie() glutinitwindowposition() glutcreatewindow() glutmainloop() main() 関数 終了処理 各関数の説明は省略 コールバック関数の設定 ( メイン関数 ) コールバック関数の設定 関数の引数として関数を渡す ( 特殊な使い方 ) glutdisplafunc() glutreshapefunc() glutmousefunc() glutmotionfunc() glutidelfunc() 描画のための設定 ( 初期化関数 ) initenvironment() 関数 描画に必要な最低限の設定 光源情報の設定 機能の有効化 ( 色指定 隠面消去 背面消去 ) 背景色の設定 各関数の説明は省略 光源情報などは変更しなくても構わない 4

描画処理 dspla() 関数 画面のクリア (glclear() 関数 ) 変換行列の設定 ( ワールド座標系 カメラ座標系 ) 光源位置の設定 地面のポリゴンの描画 変換行列の設定 ( モデル座標系 カメラ座標系 ) ポリゴンの描画 描画画面を表示 (glswapbuffers() 関数 ) 変換行列の設定とポリゴン描画については 後で詳しく説明 ウィンドウサイズ変更時の処理 reshape() コールバック関数 ウィンドウ内の描画範囲を設定 glviewport() 関数 ここでは 画面全体に描画を行うように設定 射影行列の設定 gluperspective() 関数 ここでは 標準な射影になるよう設定 ( 視野角 45 ) どちらも 描画を行う上で欠かせない設定 マウス操作時の処理 マウス操作のコールバック関数 mouse() 関数 マウスのボタンが 押されたとき または 離されたときに呼ばれる motion() 関数 マウスのボタンが押された状態で マウスが動かされたときに定期的に呼ばれる ボタンが押されない状態で マウスが動かされたときに呼ばれる関数もある ( 今回は使用しない ) アイドル時の処理 描画やマウス入力を処理する必要がないときに定期的に呼ばれる関数 物体の位置 向きを少しずつ変化させるといった アニメーションを実現するために利用できる サンプルプログラムでは 何も処理を行っていない ( 今後処理を追加 ) サンプルプログラムの構成 ( 確認 ) 描画処理の詳しい説明 main() 関数 initenvironment() 関数 ユーザ プログラム初期化処理 GLUT glutmainloop() 描画関数 (displa() 関数 ) の詳しい説明 変換行列の設定 ポリゴンの描画 displa() 関数 描画 mouse() 関数 motion() 関数 マウス処理 入力待ち処理 idle() 関数 アニメーション処理 main() 関数 終了処理 5

変換行列の設定 OpenGL は 内部に変換行列を持っている モデルビュー変換行列 射影変換行列 両者は別に扱った方が便利なので 別々に設定できるようになっている プログラムから OpenGLの関数を呼び出すことで 変換行列を変更できる 座標変換 ( 復習 ) モデル座標系からスクリーン座標系への変換 モデル座標系 スクリーン座標系 ワールド座標系 カメラ座標系 変換行列の設定 設定を行う変換行列の指定 glmatrimode() どの変換行列を変更するのかを指定する 変換行列の設定 glloadidentit() gltranslate() glrotate() その他の設定関数 変換行列の指定 glmatrimode( mode ) 設定する変換行列を指定する GL_MODELVIE モデルビュー変換 ( モデル座標系からカメラ座標系への変換 ) GL_PROJECTION 射影変換 ( カメラ座標系からスクリーン座標系への変換 ) glloadidentit() 変換行列の変更 単位行列で初期化 gltranslate(,, ) 平行移動変換をかける glrotate( angle,,, ) 指定した軸周りの回転変換をかける angle は 1 回転を 360 として指定 変換行列の変更 変換行列は順番に右側にかけられていく プログラムで後から記述した変換行列の方が 実際には先に計算される A = 1 1 A= A A A A 1 2 3 n 6

サンプルプログラムの変換行列 サンプルプログラムのシーン設定 カメラと水平面の角度 ( 仰角 ) は camera_ptich カメラと中心の間の距離は 15 ポリゴンを (0,1,0) の位置に描画 サンプルプログラムの変換行列 モデル座標系 カメラ座標系への変換行列 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 cos( camera_pitch) sin( camera_pitch) 0 0 1 0 1 = 0 0 1 150 sin( camera_pitch) cos( camera_pitch) 00 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 15 camera_pitch (0,1,0) ワールド座標系 カメラ座標系 モデル座標系 ワールド座標系 軸周りの回転 2つの平行移動変換の位置に注意 中心から15 離れるということは 回転後の座標系でカメラを後方 ( 軸 ) に15 下げることと同じ 変換行列の変更のプログラム マウス入力処理 (motion() 関数 ) // 右ボタンのドラッグ中であれば マウスの移動量に応じて視点を回転 if ( drag_mouse_r ) // マウスの縦移動に応じてX 軸を中心に回転 camera_pitch -= ( m - last_mouse_ ) * 1.0; if ( camera_pitch < -90.0 ) camera_pitch = -90.0; else if ( camera_pitch > 0.0 ) camera_pitch = 0.0; // 今回のマウス座標を記録 last_mouse_ = m; last_mouse_ = m; // 再描画の指示を出す ( 描画のコールバック関数が呼ばれる ) glutpostredispla(); 変換行列の設定のプログラム 描画処理 (displa() 関数 ) // 変換行列を設定 ( ワールド座標系 カメラ座標系 ) glmatrimode( GL_MODELVIEW ); glloadidentit(); gltranslatef( 0.0, 0.0, - 15.0 ); glrotatef( - camera_pitch, 1.0, 0.0, 0.0 ); // 地面を描画 ( ワールド座標系で頂点位置を指定 ) // 変換行列を設定 ( モデル座標系 カメラ座標系 ) gltranslatef( 0.0, 1.0, 0.0 ); // ポリゴンを描画 ( モデル座標系で頂点位置を指定 ) その他の変換行列の設定方法 変換行列の設定関数 gllookat() カメラの位置と注視点の位置から変換行列を設定 glloadmatri(), glmustmatri() 配列を使って変換行列を設定 or かける 射影行列の設定関数 glperspective(), glfrustrum(), glorth() 1 つ目の関数はサンプルプログラムで使用 今回はこれらの関数の説明は省略 ポリゴンの描画 glbegin( tpe ) ~glend() を使用 glbegin( プリミティブの種類 ) この間にプリミティブを構成する頂点データを記述 glend() プリミティブの種類 GL_POINTS( 点 ) GL_LINES( 線分 ) GL_TRIANGLES( 三角面 ) GL_QUADS( 四角面 ) GL_POLYGON( ポリゴン ) 他 7

頂点データの指定 glcolor3f( r, g, b ) これ以降の頂点の色を設定 glnormal3f( n, n, n ) これ以降の頂点の法線を設定 glverte3f(,, ) 頂点座標を指定 色 法線は 最後に指定したものが使用される サンプルポリゴンの描画 (1) 地面のポリゴン ワールド座標系で頂点位置 法線を指定 真上 (0,1,0) を向き 水平方向の長さ 10 の四角形 // 地面を描画 glbegin( GL_POLYGON ); glnormal3f( 0.0, 1.0, 0.0 ); glcolor3f( 0.5, 0.8, 0.5 ); glverte3f( 5.0, 0.0, 5.0 ); glverte3f( 5.0, 0.0,-5.0 ); glverte3f(-5.0, 0.0,-5.0 ); glverte3f(-5.0, 0.0, 5.0 ); glend(); サンプルポリゴンの描画 (2) ポリゴン モデル座標系で頂点位置 法線を指定 glbegin( GL_TRIANGLES ); glcolor3f( 0.0, 0.0, 1.0 ); glnormal3f( 0.0, 0.0, 1.0 ); glverte3f(-1.0, 1.0, 0.0 ); glverte3f( 0.0,-1.0, 0.0 ); glverte3f( 1.0, 0.5, 0.0 ); glend(); (-1,1,0) (0,-1,0) (1,0.5,0) サンプルプログラムの座標系 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 cos( camera_pitch) sin( camera_pitch) 0 0 1 0 1 = 0 0 1 150 sin( camera_pitch) cos( camera_pitch) 00 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 ワールド座標系 カメラ座標系 モデル座標系 ワールド座標系 15 (0,1,0) camera_pitch サンプルプログラムのまとめ サンプルプログラムの構成 ( 確認 ) サンプルプログラムの構成 メイン関数と各コールバック関数 初期化処理 各コールバック関数の役割 変換行列の設定 (displa() 関数 ) ポリゴンの描画 (displa() 関数 ) main() 関数 initenvironment() 関数 displa() 関数 mouse() 関数 motion() 関数 ユーザ プログラム初期化処理描画マウス処理 GLUT glutmainloop() 入力待ち処理 idle() 関数 アニメーション処理 main() 関数 終了処理 8

サンプルプログラムの拡張 サンプルプログラムの拡張 資料に従って サンプルプログラムを少しずつ拡張しながら OpenGLの使い方を学習 サンプルプログラムを修正するときは 自分でわざわざ打ち込まなくとも コピー & ペースを活用すると早い ただし 各修正にどのような意味があるのか きちんと理解しながら進めることが重要 理解しないままただコピーすると 間違えて違うところを修正してしまう可能性が高い プログラム拡張の流れ 簡単なアニメーションの追加 より複雑なポリゴンモデルの描画 変換行列を使った視点操作 変換行列を使ったアニメーション テクスチャマッピング 簡単なアニメーション ポリゴンの回転の変換行列 1 枚のポリゴンを 軸を中心として回転させる 1 0 0 0 1 0 0 0 1 0 0 0 cos ( theta_ccle) 0 sin ( theta_ccle) 0 0 1 0 0 0 cos( camera_pitch) sin( camera_pitch) 0 0 1 0 1 0 1 1 0 0 0 1 150 sin( camera_pitch) cos( camera_pitch) = 00 0 1 0 sin ( theta_ ccle) 1 cos( theta_ccle) 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 ワールド座標系 カメラ座標系 モデル座標系 ワールド座標系 変換行列に 軸周りの回転を追加することで実現 (0,1,0) ポリゴンの回転のための変数 変数定義 ( 先頭 ) 変数の変化 (idle() 関数 ) // アニメーションのための変数 float theta_ccle = 0.0; void idle( void ) // theta_ccle を 0~360 まで繰り返し変化させる // (360 まで来たら 0 に戻る ) theta_ccle += 1.0; if ( theta_ccle > 360 ) theta_ccle -= 360; theta_ccle // 再描画の指示を出す ( 描画関数が呼ばれる ) glutpostredispla(); 9

ポリゴンの回転の追加 変換行列の設定 (displa() 関数 ) // 変換行列を設定 ( ワールド座標系 カメラ座標系 ) glmatrimode( GL_MODELVIEW ); glloadidentit(); 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_ccle, 0.0, 1.0, 0.0 ); // ポリゴンを描画 ( モデル座標系で頂点位置を指定 ) 裏面のポリゴンの描画 裏面が描画されない ( 背面消去のため ) ので 裏向きのポリゴンの描画を追加 glbegin( GL_TRIANGLES ); glcolor3f( 0.0, 0.0, 1.0 ); glnormal3f( 0.0, 0.0, 1.0 ); glverte3f(-1.0, 1.0, 0.0 ); glverte3f( 0.0,-1.0, 0.0 ); glverte3f( 1.0, 0.5, 0.0 ); glcolor3f( 1.0, 0.0, 0.0 ); glnormal3f( 0.0, 0.0,-1.0 ); glverte3f(-1.0, 1.0, 0.0 ); glverte3f( 1.0, 0.5, 0.0 ); glverte3f( 0.0,-1.0, 0.0 ); glend(); 頂点の順序 法線の向きが逆になる点に注目 修正箇所のまとめ 変数定義 ( 先頭 ) 変数の変化 (idle() 関数 ) 変換行列の設定 (displa() 関数 ) 裏向きのポリゴンの描画を追加 (displa() 関数 ) ポリゴンモデルの描画 より複雑なポリゴンモデルの描画 四角すいの描画 三角面の集合として描画 配列を使った四角すいの描画 ポリゴンデータを配列に格納 配列を使った直方体の描画 四角面の集合として描画 ポリゴンデータを配列に格納 四角すいの描画 四角すいを構成する頂点と三角面 V4 V3 三角面法線 V0, V3, V1 0.0, 0.53, 0.85 V0 (0.0, 0.8, 0.0) V0, V2, V4 0.0, 0.53, -0.85 V2 V0, V1, V2 0.85, 0.53, 0.0 V0, V4, V3-0.85, 0.53, 0.0 V1, V3, V2 0.0, -1.0, 0.0 V1 (1.0, -0.8, 1.0) V4, V2, V3 0.0, -1.0, 0.0 10

面の法線の計算方法 ポリゴンの 2 辺の外積から計算できる N V1 N=(V3 - V1) ( V2 - V1) 長さが 1 になるよう正規化 V3 V2 ポリゴンモデルの描画方法 いくつかの描画方法がある プログラムからOpenGLに頂点データを与えるのにいろいろなやり方がある 主な描画方法 ( 今回は簡単な2 通りのみを扱う ) glverte() 関数に直接頂点座標を記述 頂点データの配列を使う方法 頂点配列を使う方法 頂点データとインデックスの配列を使う方法 頂点配列とインデックス配列を使う方法 OpenGL の頂点配列の機能を使うことで より高速に描画できる ( 今回は扱わない ) 方法 1 最も基本的な描画方法 サンプルプログラムと同様の描画方法 glverte() 関数の引数に直接頂点座標を記述 ポリゴン数 各ポリゴンの頂点数の数だけ glverte() 関数を呼び出す 四角すいの描画 (1) 四角すいを描画する新たな関数を追加 void renderpramid() glbegin( GL_TRIANGLES ); // +Z 方向の面 glnormal3f( 0.0, 0.53, 0.85 ); glverte3f( 0.0, 1.0, 0.0 ); glverte3f(-1.0,-0.8, 1.0 ); glverte3f( 1.0,-0.8, 1.0 ); glend(); 四角すいの描画 (2) 描画関数から四角すいの描画関数を呼び出し 修正の場所を間違えないように注意 renderpramid() 関数では色は使用されていないので 呼び出す前に色を設定している void displa( void ) // 中心に四角すいを描画 ((0,1,0) に移動 ) gltranslatef( 0.0, 1.0, 0.0 ); glcolor3f( 1.0, 0.0, 0.0 ); renderpramid(); この描画方法の問題点 問題点 同じ頂点が共通して使われている プログラムが長くなる モデルデータの修正がしにくい モデルデータがプログラムとして記述されているので ファイルから動的に読み込んだりするようなことができない 解決方法 モデルデータを配列に格納する 11

方法 2 配列を使った描画方法 頂点 ポリゴンのデータを配列に格納 描画関数では 配列のデータを順に参照しながら描画 必要な配列 ( サンプルプログラムの例 ) 頂点座標 (,,) 頂点数 三角面を構成する頂点番号 (v0,v1,v2) 三角面数 三角面の法線 (,,) 三角面数 三角面インデックス 頂点データの配列と 三角面インデックスの配列に分けて管理する 面 1 面 2 面 3 面 4 面 5 面 6 面 1 面 2 面 3 面 4 面 5 面 6 頂点データ ( 座標, 法線, 色など ) 頂点の重複がある 三角面インデックス 何番目の頂点データを使うかという情報 頂点の重複がなくなる 頂点データ ( 座標, 法線, 色など ) 配列を使った四角すいの描画 (1) 配列データの定義 const int num_pramid_vertices = 5; // 頂点数 const int num_pramid_triangles = 6; // 三角面数 // 角すいの頂点座標の配列 float pramid_vertices[ num_pramid_vertices ][ 3 ] = 0.0, 1.0, 0.0, 1.0,-0.8, 1.0, 1.0,-0.8,-1.0, ; // 三角面インデックス ( 各三角面を構成する頂点の頂点番号 ) の配列 int pramid_tri_inde[ num_pramid_triangles ][ 3 ] = 0,3,1, 0,2,4, 0,1,2, 0,4,3, 1,3,2, 4,2,3 ; // 三角面の法線ベクトルの配列 ( 三角面を構成する頂点座標から計算 ) float pramid_tri_normals[ num_pramid_triangles ][ 3 ] = 0.00, 0.53, 0.85, // +Z 方向の面 配列を使った四角すいの描画 (2) 配列データを参照しながら三角面を描画 void renderpramid() int i, j, v_no; glbegin( GL_TRIANGLES ); for ( i=0; i<num_pramid_triangles; i++ ) glnormal3f( pramid_tri_normals[i][0], [i][1], [i][2] ); for ( j=0; j<3; j++ ) v_no = pramid_tri_inde[ i ][ j ]; glverte3f( pramid_vertices[ v_no ][0], [ v_no ][1], glend(); 直方体の描画 別のポリゴンモデル ( 直方体 ) の描画 1 枚は空欄にしているので 各自 適切な頂点番号を考えて追加する (-0.4, 1.0, -0.2) V7 V3 V1 V5 V6 V2(0.4, 1.0, 0.2) V4 V0(0.4, 0.0, 0.2) 四角面法線 V2, V3, V1, V0 0.0, 0.0, 1.0 V7, V6, V4, V5 0.0, 0.0, -1.0 V2, V0, V4, V6 1.0, 0.0, 0.0 V3, V7, V5, V1-1.0, 0.0, 0.0 V3, V2,? V6, V7 0.0, 1.0, 0.0 V0, V1, V5, V4 0.0, -1.0, 0.0 配列を使った直方体の描画 (1) 配列データの定義 四角面を使うので 各面の頂点数が 4 個になる 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_inde[ 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 ; 12

配列を使った直方体の描画 (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_inde[ i ][ j ]; glverte3f( cube_vertices[v_no][0], [v_no][1], [v_no][2] ); glend(); 配列を使った直方体の描画 (4) 描画関数から直方体の描画関数を呼び出し 適切な位置 ( 移動の変換行列 ) を設定 色の指定は不要 void displa( void ) // 中心に直方体を描画 gltranslatef( 0.0, 0.0,? 0.0 ); glcolor3f( 1.0, 0.0, 0.0 ); rendercube(); 変換行列を使った視点操作 視点操作の拡張 左ドラッグで距離を操作できるように拡張 1 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 0 cos( camera_pitch) sin( camera_pitch) 0 0 1 0 1 = 0 0 1 camera_distance 0 sin( camera_pitch) cos( camera_pitch) 00 0 1 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 ワールド座標系 カメラ座標系モデル座標系 ワールド座標系 camera_distance (0,1,0) camera_pitch 視点操作の拡張 プログラムの修正箇所 ( 多いので注意 ) 左ボタンの押下状態を記録する変数を追加 カメラと原点の距離を記録する変数を追加 mouse() 関数に 左ボタンの押下状態を更新する処理を追加 motion() 関数に 左ドラッグに応じて camera_distance を変更する処理を追加 一定値以上は近づかないように制限 displa() 関数を camera_distance に応じて変換行列を設定するように変更 13

変換行列によるアニメーション 変換行列によるアニメーション 変換行列を組み合わせることで さまざまな運動を実現できる idle() 関数 運動を表す媒介変数の変化を記述 dspla() 関数 媒介変数の値に応じて 回転角度や移動距離を設定 アニメーションに使用する変数 資料に従って いくつかの媒介変数を追加 theta_ccle 0~360 へ単調増加 360 になったら 0 に戻る theta_repeat 0~180 の間を往復 180 になったら減少を始める theta_ccle から計算できる move 0~1 の間を加速度つきで往復 1 に近づくと速度が減少 theta_ccle2, theta_repeat2 アニメーションの例 一定速度で回転運動 一定位置で回転運動 一定速度で回転運動 ( 常に正面を向く ) 一定速度で往復回転運動 一定速度で上下に往復移動運動 加速度つきで上下に往復移動運動 複数の物体の運動の組み合わせ 例 1: 一定速度で回転運動 移動 回転の順に適用 移動にも回転が適用されるので 半径 1.5 で回転 cos( theta_ccle) 0 sin ( theta_ccle) 0 1 0 0 0 0 1 1 0 0 1 0 0 M = sin ( theta_ccle) 1 cos( theta_ccle) 00 0 1 1.5 0 0 0 1 0 0 0 1 1 1 ワールド座標系 カメラ座標系 モデル座標系 ワールド座標系 例 2: 一定位置で回転運動 回転 移動の順に適用 ( 順序を逆 ) 常に同じ位置に移動するので その場で回転 1 0 0 0 cos( theta_ccle) 0 sin ( theta_ccle) 0 0 1 0 0 0 1 1 0 M = 0 0 1 1.5 sin ( theta_ccle) 1 cos( theta_ccle) 0 0 0 0 1 0 0 0 1 1 1 14

例 3: 一定速度で回転運動 2 常に正面を向くようにするためには? 最初に逆方向に回転しておくことで 次の回転をキャンセル ( 移動にのみ回転がかかる ) cos ( theta_ccle) 0 sin ( theta_ccle) 0 1 0 0 0 cos( theta_ccle) 0 sin ( theta_ccle) 0 0 1 1 0 1 0 0 0 1 1 0 M = sin ( theta_ccle) 1 cos ( theta_ccle) 00 0 1 1.5 sin ( theta_ccle) 1 cos( theta_ccle) 0 0 0 0 1 0 0 0 1 0 0 0 1 1 1 例 4: 一定速度で往復回転運動 変換行列は例 1と同じ 異なる変数を使用 変数の変化 (idle() 関数 ) と変換行列の設定 (displa() 関数 ) の組み合わせが重要 cos ( theta_repeat ) 0 sin ( theta_repeat) 0 1 0 0 0 0 1 1 0 0 1 0 0 M = sin ( theta_repeat) 1 cos( theta_repeat ) 00 0 1 1.5 0 0 0 1 0 0 0 1 1 1 例 5: 一定速度で上下に往復移動 回転だけではなく 位置に変数を使用することもできる めり込みを避けるために 座標値を +1 している 1 0 0 0 0 1 0 theta_repeat /180 1 + M = 0 0 1 0 0 0 0 1 1 1 例 6: 加速度つきで上下に往復運動 変数の変化を工夫することで 移動速度を変化させるようなこともできる ここでは三角関数の絶対値を利用 0~360 を 0~2π に変換している void idle( void ) // move を 0~1 の間で反復変化させる //( 三角関数を用いることで 一定速度でなはなく // 0 の近くで速度が小さく // 180 の近くで速度が大きくなるように変化させる ) move = fabs( sin( theta_ccle * 3.1415926 / 180.0 ) ); 例 7: 複数の物体の運動 それぞれ異なる変換行列を使用して描画 M = 1 1 cos( theta_ccle) 0 sin ( theta_ccle) 0 1 0 0 0 0 1 1 0 0 1 0 0 = M sin ( theta_ccle) 1 cos( theta_ccle) 00 0 1 1.5 0 0 0 1 0 0 0 1 1 1 cos( theta_ccle2) 0 sin ( theta_ccle2) 0 1 0 0 0 0 1 1 0 0 1 0 0 = M sin ( theta_ccle2) 1 cos( theta_ccle2) 00 0 1 3 0 0 0 1 0 0 0 1 1 1 変換行列の退避 復元 現在の変換行列を記録しておき 後から復元することができる 記録した変換行列はスタックに記録される glpushmatri() 現在の変換行列の退避 スタックに積む glpopmatri() 最後に退避した変換行列の回復 スタックから取り出す 15

変換行列の退避 復元の例 ワールド座標系からカメラ座標系への変換行列を設定 地面を描画 行列を退避 物体 1からワールド座標系への変換行列 物体 1を描画 行列を回復 物体 2からワールド座標系への変換行列 物体 2を描画 World Camera World Camera Obj1 World World Camera World Obj2 Camera World 変換行列の退避 復元の例 プログラムの例 void displa( void ) // ここまででワールド座標系からカメラ座標系への変換設定 // 地面を描画 // 例 7:2 つの物体を描画 ( 異なる周期で往復回転運動 ) glpushmatri(); glrotatef( theta_ccle2, 0.0, 1.0, 0.0 ); gltranslatef( 0.0, 0.0, 3.0 ); rendercube(); glpopmatri(); glrotatef( theta_ccle, 0.0f, 1.0f, 0.0f ); gltranslatef( 0.0f, 0.0f, 1.5f ); rendercube(); テクスチャマッピング テクスチャマッピング 地面にテクスチャマッピングを適用して描画 各頂点に テクスチャ座標 (u,v) を指定 v (0.0, 1.0) (1.0, 1.0) u (0.0, 0.0) (1.0, 0.0) テクスチャマッピングのための修正 プログラムの修正箇所 テクスチャ画像を格納する変数を追加 テクスチャ画像の読み込み処理 テクスチャマッピングの設定処理 を追加 画像の読み込みには bitmap.cpp の関数を使用 地面にテクスチャマッピングを行う処理を追加 テクスチャマッピングの有効化 各頂点にテクスチャ座標を設定 コンパイル方法 (bitmap.cpp を一緒にコンパイル ) bcc32 -DWIN32 opengl.cpp bitmap.cpp レポート課題 課題 1 ポリゴンモデルの描画 課題 2 視点操作の拡張 課題 3 アニメーションの追加 作成したプログラムのソースファイルを提出 締め切り 12 月 16 日 ( 土 )17:00 基本的には今日中に終わらせて提出することを想定 レポート ( 文章 ) は提出しなくとも良い bitmap.cpp, bitmap.h やテクスチャ画像はつけなくて良い ファイル名を st??.cpp ( 自分のアカウント名 ) として提出 16

課題 1 ポリゴンモデルの描画 矢印 ( 初心者マーク ) の描画するプログラムを作成せよ V4 V10 V11 V5 V0 V1 V6 V7 V2 V3 V8 V9 課題 1 ポリゴンモデルの描画 矢印 ( 初心者マーク ) のポリゴンデータ 三角面 or 四角面の配列 描画関数を作成 頂点の順番は変えても良い V10 V8 V6 V4 V2 V0 V11 V9 V7 V5 V1 V3 頂点座標 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 課題 1 のヒント (1) 直方体と同様に頂点 四角面の配列を定義 const int num_leaf_vertices =? ; // 頂点数 const int num_leaf_quads =? ; // 四角面数 // 頂点座標の配列 float leaf_vertices[ num_leaf_vertices ][ 3 ] =? ; // 三角面インデックス ( 各三角面を構成する頂点の頂点番号 ) の配列 int cube_inde[ 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_inde[ i ][ j ]; glverte3f( cube_vertices[v_no][0], [v_no][1], [v_no][2] ); glend(); 課題 2 視点操作の拡張 左右に右ドラッグすると 視点が横に回転する ( 方位角が変化する ) 機能を追加せよ 変数を追加 (camera_aw) 変数の操作を追加 (motion() 関数 ) 変換行列の計算を追加 (displa() 関数 ) 課題 2 のヒント 先に変換行列を考えてからプログラム作成 1 0 0 0 1 0 0 0 0 1 0 0 0 cos( camera_pitch) sin( camera_pitch) 0 0 0 1 camera_distance 0 sin ( camera_pitch) cos( camera_pitch) 0 W = 0 0 0 1 0 0 0 1 1 1 ワールド座標系 カメラ座標系 軸周りの回転をどこかに追加 ( camera_aw) ( camera_aw) ( camera_aw) ( camera_aw) cos 0 sin 0 0 1 0 0 sin 0 cos 0 0 0 0 1 追加する場所が違うと 正しく動作しないので注意! camera_pitch camera_aw モデル座標系 ワールド座標系 camera_distance 17

課題 3 アニメーションの追加 指定されたアニメーションを実現 物体 1~ 物体 6 の運動を実現 サンプルプログラムを参照 opengl_report.ee 変数にはサンプルプログラムと同じものを使って良い まずは各物体の変換行列を考えてから プログラムを作成すると良い 課題 3 アニメーションの追加 1. 中心で移動しないまま 一定速度で回転運動 2. 物体 1の周囲を一定速度で回転運動 物体 1と同じ方向を向いている 3. 物体 2の真上で上下に放物反復移動 常に正面を向いている 4. 物体 3の真上で左右に反復回転運動 物体 3と同じ方向を向いている 5. 物体 1の正面で前後に等速反復移動 常に正面を向いている 18