1999年度卒業研究 -...
Transcript of 1999年度卒業研究 -...
1999年度卒業研究
OpenGLを用いた簡易プログラム作成
岡山理科大学理学部
応用数学科情報専攻
―澤見研究室―
学番:S96M501 氏名:荒木 優子学番:S96M596 氏名:波多江 学学番:S96M649 氏名:吉永 雄高
目 次
1 はじめに 3
2 OpenGLの歴史 4
3 OpenGLの特徴 5
4 OpenGLについて 6
OpenGlの機能について : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 6
グラフィックス機能および言語の意味解説 : : : : : : : : : : : : : : : : : : : : : 7
5 コンパイル方法 10
OpenGLの概念とライブラリ : : : : : : : : : : : : : : : : : : : : : : : : : : : : 10
Windows98でのコンパイル方法 : : : : : : : : : : : : : : : : : : : : : : : : : : : 11
コンパイル : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 11
6 描画までの仕組み 12
ビューポートの指定 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 13
射影行列の初期化 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 13
視体積の設定 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 13
透視法射影 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 15
モデルビュー行列の初期化と視点,参照点の位置の視点 : : : : : : : : : : : : : : 15
モデリング変換 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 16
7 プログラムの仕組み 17
コールバック関数を使用したプログラムの流れ : : : : : : : : : : : : : : : : : : 17
ウィンドウ作成 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 18
ディスプレイモード : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 18
ウィンドウの寸法 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 19
ウィンドウのタイトル : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 19
各種コールバック関数の指定 : : : : : : : : : : : : : : : : : : : : : : : : : : : : 20
ウィンドウのリシェイプ (サイズ変更,移動,アクティブ化)時 : : : : : : : : 20
マウスボタンのクリック時 : : : : : : : : : : : : : : : : : : : : : : : : : : : 21
キーボードのキーが押された場合 : : : : : : : : : : : : : : : : : : : : : : : 22
イベント処理ループ : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 23
8 色と法線 25
OpenGLにおける色の表現方法 : : : : : : : : : : : : : : : : : : : : : : : : : : : 25
背景色 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 25
異なる色の線形補間方法 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 25
法線の概念 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 26
シェーディング処理 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 26
1
1 はじめに
OpenGLは,グラフィックス・ハードウェアに対するソフトウェア・インターフェースであ
りオペレーティングシステムには依存しない.たとえばMicrosoft,Windows95,WindowsNT
などで使用することができる. このインターフェースは,多数のコマンドから成り立つライ
ブラリ形式になっており,それらを使用してオブジェクトやインタラクティブな3次元アプ
リケーションを作成するために必要な操作を指定することができる.本論文では,OpenGL
の解説とOpenGLを用いて作成したプログラムについて説明する.
3
2 OpenGLの歴史
OpenGLは 1980年代にアメリカのSGI(シリコングラフィクス社)が開発した IRIS GL
(Graphics Library)の後継となっている.SGIはグラフィックスワークステーションの分野で
は,主流となっているメーカーである.しかし IRIS GLはSGI社のマシンのみであり実行可
能であり,そのままでは業界標準にはなりえないので,新たにOpenGLをグラフィックスイン
ターフェースの標準として提案したものである.仕様の決定やライセンスの発行は,OpenGL
ARB(Architecture Review Bord)が行っている.現在,SGI,IBM,DEC,SONY,NEC,E&S,
Microsoft(WindowsNT),Integraphの各社がOpenGLを提供している.そしてWindows NT
version3.5,標準APIとして実装されてから広く普及するようになってきた.また,インター
ネットにおいては専門のサーバーが設けられており,普及活動を行っている.
4
3 OpenGLの特徴
OpenGLの特徴を大まかに分けると次の二つにまとめることができる.
1. OpenGLは,ウィンドウシステムから独立だということである.これに対し,X-Window
上の3次元グラフィックス機能を実現しているPEXは,X-Windowの拡張機能である
ためウィンドウシステムとは不可分の関係にある.UNIXワークステーションの世界
ではX-Windowが標準となっているが,パソコンの世界ではX-Windowが標準とい
うわけではなく,Xアプリケーションをパソコン上で動かすには特別なソフトウェア
(MS Windows用Xサーバー)が必要となる.しかし,OpenGLはウィンドウシステム
から独立しているので,ワークステーションでもパソコンでも使用することができる
.
2. OpenGLでは,1つのコマンドに対する引数は限られていて,長々と引数を指定しな
ければならないようなコマンドはあまり多くない.これらのことがOpenGLを用い
て作成したプログラムを簡潔なものとし,効率よくソフトウェア開発を行う上で大変
役に立っている.
5
4 OpenGLについて
OpenGlの機能について
OpenGLのグラフィックス機能について説明する. OpenGLが出現する前にも,複数の
ベンダー上でさまざまなグラフィックスライブラリが提供されてきた.しかし,そのほとん
どは2次元グラフィックスが中心であり,3次元グラフィックスを簡単に扱えるものは非
常に限られていた.また,各ベンダーごとに独自なものが大半を占め,そのほかのベンダー
への移植が非常に困難だった.しかしOpenGLの出現により,ベンダーに依存することな
くOpenGLによって提供されている2次元,3次元処理のライブラリを使用することで,非
常に高度なグラフィックスを簡単かつ手軽に実現することができるようになってきた.こ
のOpenGLでは約250個の関数群によって次のようなグラフィックス機能が提供されて
いる.
1. 2次元,3次元のグラブィックス機能のサポート
2. 陰面消去(Z-バッファ法:デプス・バッファとも呼ぶ)
3. 視界変換,モデリング変換(回転,移動,拡大,縮小)
4. 光源機能,シェーディング機能
5. 霧などの大気効果
6. ディスプレイリスト
7. アンチエイリアシング
8. アキュームレーションバッファ
9. ステンシル・バッファ
10. テクスチャマッピング
11. NURBUS(NON-UniformRational B-Splin)曲面
12. 環境マッピング
6
グラフィックス機能および言語の意味解説
以下に主なグラフィックスなどについて列記し,その解説をする.
²グラフィックス・ハードウェアグラフィックス・システムを構成する個々の機器,またはそれらの総称.
²インターフェース情報や信号の授受を行う2つ以上のものが接する接点,境界面,共有される部分をそ
の接続仕様や共有のためのルール.
²X-WindowUNIX上で動くウィンドウ・システム.
²Windows NTNTはnew technologyの略で,ウィンドウを使って操作環境を統一し,アプリケーシ
ョンの互換性を図る.
²ウィンドウ・システムマルチウィンドウ表示により,各ウィンドウごとに割り付けたアプリケーション・プ
ログラムを次々に切り替えて実行できるシステム.
²陰面消去(デプス・バッファ)デプス・バッファは,デプス(深度),または規点からの距離をウィンドウ上の各ピ
クセルに関連づけることにより動作する.
²視界変換カメラの配置や照準設定と同様のもの.
²モデリング変換モデルの配置,方向の決定を実行する.
²光源機能光の位置,色,減衰といった設定を行って光源を使用してレンダリングすることがで
きる.
²シェーディング機能面から発する光の色を決定する過程をシェーディング(陰影づけ)と呼ぶ.
²霧などの大気効果視界が制限された状況を表現することカ泌要な,視覚的シミュレーションのアプリケ
ーションには不可欠である.
²ディスプレイ・リスト後で実行させるために保存した一群のOpenGLコマンドを指すまた実行すると,そ
こに含まれるコマンドは順序に従って実行される.
7
²アンチエイリアシングOpenGLの描画する線にジャギー(ギザギザの縁)が顕著に現れる.このジャギーの
ある状態を”エイリアシング”と呼び,そのジャギーを軽減するための技法.
²シーン・アンチエイリアシング描画した線の縁がギザギザ(ジャギー)にならないようにする時に使う.
²アキュームレーション・バッファRGBAカラーデータを保存し,最終的な画像を合成するために幾つかの画像を累積
する場合に使う.
²カラー・バッファ各ピクセルがカラーの保存に必要な量のメモリを持っており,このピクセル・メモリ
を”カラー・バッファ”と呼ぶ.
²RGBAモードカラーデータ値を各ピクセルに保存する.
²RGBAモードの”A””A(アルファ)”の値は”1.0”では透過しない,”0,0”で完全透明.
²モーション・ブラー処理高速に動く物体を低速度のカメラで撮影した時に後ろににじみがでる.これを擬似
的に表現する方法のことであり,色を時間的にサンプリングするものがモーション・
ブラー(残像)と呼ばれる.
²ステンシル・バッファ画面の特定の部分への書き込みを規制する,
²テクスチャ・マッピング素材の表面の模様あるいは人の顔,風景といった2次元画像データを,多面体や円筒
面,自由曲面などの3次元物体の表面に張り付けることである,
²バンプマッピング物体表面に凹凸模様を擬似的に発生させて,材質感を表現しようとするテクスチャ・
マッピングの1手法である.
²NURBUS(Non-UniformRational B-Splin)曲面Bスプラインと呼ばれる曲線,曲面をさらに拡張したもの.
²環境マッピングされるオブジェクトが反射されているように描画され,そのオブジェクトの周辺がオ
ブジェクトに(画像として)映り込んでいるように表示されるマッピング方法のこ
とである,
8
²レイ・トレーシング個々のピクセルをそれぞれまったく独立したものとして考え,しばしばランダム抽出
のレンダリング技法と見なされる.レイ・トレーシングで絵を作成すると,光学的な
効果(反射,透過陛,影)の他に,静止画像の直接的にアンチエイリアシングやアニメ
ーションのモーション・ブラーなどを簡単に取り込める.
9
5 コンパイル方法
OpenGLの概念とライブラリ
OpenGLはグラフィックスプログラマが高品質なカラーイメージとして3Dオブジェク
トを創作するために作られたグラフィックスハードウェアのために用意されたソフトウェ
アインターフェースである.OpenGLはレンダリング処理のみを行い,ベンダに中立なAP
Iとして2Dと3Dのグラフィックス関数(モデリングを含めて,座標変換,色,光源処理
,スムースシェーディング機能や高度な機能であるテクスチャマッピング,ナーバス,フォ
グ,アルファー値ブレンドとモーションブラーも同じ様に提供される)を提供する.また
OpenGLは,イミディエートモードとディスプレイリストモードの両方のモードを提供し
ている(ここではこれらの詳細を省く).
OpenGLは,ウィンドウシステムに依存しない独立したライブラリのため,目的のプログラ
ムをOpenGLを使用することによってX Window System(UNIX)とWindows95(もし
くはWindow98とNT)の両方で動くプログラムソースを作ることが可能である.したがっ
て,異なるOSでもコンパイルすれば動作するプログラムが作成できる.OpenGLでは,単純
,かつ強カなレンダリング・コマンドを用意しており,上位レベルの描画はすべてこのコマ
ンドの実行が必要である.そのためにプログラミング作業を単純化し,作業効率を上げるた
めに,OpenGL上に独自のライブラリやルーチンがすでに作成されている.以下に使用する
代表的な三つのライブラリについて説明する.
²GLライブラリ:関数名が”gl”で始まる基本コマンド.
²GLUライブラリ:関数名が”glu”で始まるユーティリティ関数をまとめた有用なライブラリ.中身はGLライブラリ・関数の組合せ.
²AUXライブラリ:関数名が”aux”で始まるコマンド.これを使用することでウィンドウ管理や入カイベント操作などを簡単に行うことができる.
使用する時は,以下のようにしてプログラムの先頭部で各種使用ライブラリのヘッダファ
イルをインクルードしておく.
#include <GL/gl.h>
#include <GL/glu.h>
#include <aux.h> /* windowsでは<GL/glaux.h> */
また,これら以外も各種環境に依存するライブラリ群がある.
10
Windows98でのコンパイル方法
パソコンでOpenGLを動かしたいときや,どうしてもVisual C++でプログラミング
しなければならない場合の為に,ここにWindows98におけるOpenGLを用いたプログラム
のコンパイル方法を示す.
なお,コンパイルにはVisual C++を用いるが,Visual C++ Version6.0以前や他の開
発言語では,OpenGLのライブラリがインストールされていないため,自分で必要なライブ
ラリを入手し,インストールしなければならない.
コンパイル
コンパイルの方法について説明する(Visual C++ Version6.0の場合).
コンパイルの前に,Windowsでは次の様にインクルードファイルを追加修正する.
²#include <GL/gl.h> の前に#include <windows.h>を追加
²#include <GL/aux.h>を#include <GL/glaux.h> に修正
²コールバック関数はCALLBACK型で定義
その後,まず1度ビルドすることによって,ディフォルトのワークスペースを作成し,コン
パイラからの文句(警告やエラー)を聞いておく必要がある.(ビルドはメニュー [ビルド]
→ [ビルド]で行う.)
これより各種の設定ができるようになるので,メニュー [プロジェクト]の設定で,プロジェ
クトの設定を行う.
リンクの欄のライブラリの所に,Opengl32.lib Glu32.lib Glaux.libというライブラリ
ファイルの名前を加える.
そして,OKを押して,プロジェクトの設定を更新した後,もう1度リビルドすれば良い.
11
6 描画までの仕組み
3Dグラフィックスでは,コンピュータの2次元のディスプレイのどこに立体のプリミティ
ブを表現するかが問題となってくる.OpenGLでは,次に示す三つの処理を経て,オブジェク
トをディスプレイに表示する.
1. 視界,モデリング,射影演算を含む乗算で,変換を実行
2. 画像をウィンドウの枠内に表示 (レンダリング)するために枠外になるオブジェクト
(またはその 1部)のクリッピング (切り取り)
3. 変換した座標をスクリーン・ピクセルに対応させ,表示するビューポート変換を実行
したがって,オブジェクトを画面に表示するためには,以下のような順番でプログラムを作
成すればよい.
1. ビューポートの指定 : ウィンドウ内の表示位置
2. 射影行列の初期化 : 単位行列で初期化
3. 視体積の設定 : クリッピングを行うための射影の範囲を指定
4. 視点,参照点の位置の指定 : 視野の設定のためのモデリング変換
5. モデリング変換 : オブジェクトのためのモデリング変換
6. オブジェクトの描画
次にサンプルプログラムを用いて,これらの処理を順を追って説明していく.
glViewport(0,0,400,400); /*表示領域ビューポートを確保*/
glMatrixMode(GL_PROJECTION);glLoadIdentity(); /*射影行列初期化*/
glOrtho(-2.0, 2.0, -2.0, 2.0 -2.0, 2.0); /*正射影の視体積を確保*/
glMatrixMode(GL_MODELVIEW);glLoadIdentity(); /*モデリング行列初期化*/
glLookAt(0.0,0.0,2.0, 0.0,0.0,0.0, 0.0,1.0,0.0); /*視点参照の指定*/
12
ビューポートの指定
まず,最初にglViewport()でウィンドウのビューポートの指定を行う.
glViewport(0,0,400,400);
void glViewport(GLint x,GLint y,GLsizei w,GLsizei h)
ウィンドウのビューポートの指定を行う.開始点位置 (x,y),幅w,高さhである.開始点位置
は,左下が (0.0)となるので,注意しなければならない.
射影行列の初期化
続いて,射影行列の初期化と指定を行う.
glMatrixMode(GL PROJECTION);
glLoadIdentity();
まず,glMatrixMode()で射影行列のモード"GL PROJECTION"に設定して,glLoadIdentity()
にて,行列が単位行列になるよう初期化を行う.
void glMatrixMode(MODE)
行列のモード指定を行う.引数"MODE"で指定できるシンボル定数は,以下の三つであ
る.
GL PROJECTION 射影変換行列のモードに設定
GL MODELVIEW モデルビュー行列のモードに設定
GL TEXTURE テクスチャ行列のモードに設定
void glLoadIdentity(void)
行列を4 � 4の単位行列に設定する任意の行列を設定した場合は,glLoadMatrix()使用する.
視体積の設定
次に,射影の範囲,すなはち"視体積"設定する.視体積は,画面上にオブジェクトをどのよ
うに射影するかを決定し,最終画像からどこのオブジェクト (またはその一部)が枠外となっ
たかを調べて,クリッピング処理しなければならないかどうか決定する.
射影方法には大きく分けて,正射影と透視法射影の 2種類ある.今回は透視法射影を使用
したので,それについて述べる.
13
透視法射影
透視法射影とは,視点から遠くになるほど小さく表示されることから遠近感が得られや
すく,我々の眼 (またはカメラ)の特性に近い射影である.透視法射影の視体積の設定には
,glFrustum()で行うがこれはあまり実用的では無いので,通常gluライブラリの gluPerspec-
tive()を使用する.ここでは,gluPerspective()による指定方法のみを述べる.
void gluPerspective(GLdouble fv,GLoduble a,GLdouble n,GLdouble f)
透視法射影の視体積の指定を行う.引数"fv"は,xy平面における視界角度で,この値は0°
~180°の範囲内にある必要がある.引数"a"はアスペクト比で,通常ビューポートで指定し
た横と縦との比 (w/h)である.引数"n"と"f"は正射影とは違い,視点からの相対距離である
ことに注意する必要がある.またこれらの引数はすべて正である必要がある.
例として次のようにする.
gluPerspective(40.0,640.0/480.0,0.1,20.0);
/*透視法射影の視界角度40°,アスペクト比1.33…,視点から"n"~"f"までの距離の視体積
を確保*/
モデルビュー行列の初期化と視点,参照点の位置の視点
以下のようにして視点と参照点 (視点が見ている点)の位置の指定を行う.
glMatrixMode(GL_MODELVIEW);/* 現在の行列モードモデルビュー行列に設定 */
glLoadIdentity();/* モデルビュー行列を単位行列で初期化 */
gluLookAt(0.0,0.0,5.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
/* 視点(0,0,5), 参照点(0,0,0), Y軸の正の向きを上に設定 */
gluライブラリの gluLookAt()を使用して,視体積の位置を設定している.
通常何も設定していない状態で,視点と参照点 (視点が見ている点)の位置は原点であり
Z軸は負の方向をむいている.したがって,このままオブジェクトを初期位置に指定すると
原点に表示されるため,オブジェクトと視点が重なってしまう.これを避けるためにはオブ
ジェクトを奥に移動させればいいが,視点の位置を手前に移動させる手もある.実際には
,OpenGLではこの 2つの手段は同じ表示結果を生じ,視点を移動したい場合は通常,オブ
ジェクトの方を逆方向に移動させて実現する.
これでは,何かと不便な面もあるので,OpenGLでは gluLookAt()によって見かけ上視点
の位置を変化させるようにし,視点と参照点の位置を定義できるようになっっている.
したがってgluLookAt()が後述する 3D形状の位置移動 (モデリング変換)についての関
数となるため,射影行列には手を加えていないことから,これを使用する前には変換行列の
初期化が必要となる.そこでgluLookAt()の前にglMatrixMode()によりモデルビュー行列
を初期化しなければならない.
15
void gluLookAt(GLdouble Ex,GLdouble Ey ,GLdouble Ez,
GLdouble Cx,GLdouble Cy,GLdouble Cz,
GLdouble Ux,GLdouble Uy,GLdouble Uz)
次のようにして視点,参照点の視界指定を行う.引数は視点の位置 (Ex,Ey,Ez),参照点 (Cx,Cy,Cz)
となっている.また,この関数では座標系における"上"の指定を行うことができ,パラメー
タ (Ux,Uy,Uz)を使用してこの設定を行う.上になる座標系に"1.0"を入れ,他を"0.0"に設定
する.
以下にその例を示す.
glMatrixMode(GL_MODELVIEW);/* 現在の行列モードモデルビュー行列に設定 */
glloadIdentity();/* モデルビュー行列を単位行列で初期化 */
gluLookAt(0.0,0.0,5.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
/* 視点(0,0,5), 参照点(0,0,0), Y軸の正の向きを上に設定 */
モデリング変換
モデリング変換は,オブジェクトの配置と方向の決定を実行する.具体的には,オブジェ
クトの回転,移動,拡大縮小などのアフィン変換のことをいう.OpenGLにはこのモデリン
グ変換を間単に行うための関数群が用意されている.以下に今回使用したものとその使用
例を示す.
void glTranslate f f j d g (TYPE x,TYPE y,TYPE z)この関数により平行移動を行う.
void glRotate f f j d g (TYPE angle,TYPE x,TYPE y,TYPE z)この関数により回転変換を行う.引数"angle"により与えられる回転角度で"x","y","z"にて
指定された軸に関する回転変換をする.
以下にその使用例を示す.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(10.0,0.0,0.0);
glRotatef(30.0,0.0,1.0,0.0);
auxWireteapot(1.0);
この例では,まずX軸回りに30°回転行い,それからX軸の正の方向に 10.0移動した場所
にティーポットを描いている.ここで,glTranslate()とglRotate()の順番を入れ替えてみる
と描かれるオブジェクトの位置が変わってくる.このように回転と並行移動を行う場合に
は変換が可換ではないので,その順番に注意する必要がある.
16
7 プログラムの仕組み
コールバック関数を使用したプログラムの流れ
OpenGLは,ウィンドウ環境下で動作するように設計されている.したがって,目的のプ
リミティブを表示するためには,通常のウィンドウシステムでプログラムするのと同じく,
イベントドリブン方式 (イベント駆動型)でプログラムすることを必要としている.
このイベントドリブン方式というのは,逐次実行型のプログラムとは違い,ウィンドウの
サイズ変更,マウスの移動やボタンのオン・オフなどのイベントの発生を待って,発生した
イベントに応じた処理を行う機能を提供する方式である.
これらの処理は,各種ウィンドウシステムに依存するライブラリでも実現可能だが,ここ
ではOpenGLの補助ライブラリの1つ,AUXライブラリを使用してこれらの処理を実現す
る.
以下にプログラムによる処理の流れを示す.
ウィンドウ作成
↓
各種コールバック関数の指定
↓
イベント処理ループ
次にサンプルプログラムを示す.
#include "glos.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glaux.h>
void CALLBACK Key_space(void)
{
exit(-1);
}
void CALLBACK display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
auxWireTeapot(1.0);
glRotatef((GLdouble)roty,0.0,0.0,2.0);
glTranslatef (1.0,0.0,0.0);
glFlush();
auxSwapBuffers();
}
void CALLBACK Reshape(GLint w,GLint h)
17
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60,(GLfloat) w/(GLfloat) h,1.0,20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef (2.0,1.0,1.0);
gluLookAt(5.0,0.0,5.0, 1.0,0.0,0.0, 0.0,1.0,0.0);
}
int main(void)
{
/*ウィンドウ作成*/
auxInitDisplayMode(AUX_DOUBLE | AUX_RGBA |AUX_DEPTH);
auxInitPosition(0,0,600,600);
auxInitWindow("window name");
/*コールバック関数の定義*/
auxReshapeFunc(Reshape);
auxKeyFunc(AUX_SPACE,Key_space);
/*メインループ*/
auxMainLoop(display);
return(0);
}
ウィンドウ作成
まず最初に,描画領域を確保するために新規のウィンドウを作成しなければならない.
サンプルプログラムでは,まず新しく作るウィンドウのモード設定をし,次にウィンドウの
大きさを設定して,最後にウィンドウの実体を生成している.
サンプルプログラムの一部を以下に取り出し順を追って説明していく.
1 auxInitDisplayMode(AUX_DOUBLE|AUX_RGBA|AUX_DEPTH);
2 auxInitiPosition(0,0,400,400);
3 auxInitwindow("window name");
ディスプレイモード
auxDisplayMode(AUX DOUBLE j AUX RGBA j AUX DEPTH);
生成するウィンドウのディスプレイモードを指定する.OpenGLで使わない機能は指定
する必要がない.またこれらのシンボル定数は""j""で繋いで指定可能である.
18
カラーモードは色の指定の仕方を選択するモードで,マシンに依存する色しか使えないイ
ンデックスモード(AUX INDEX)か,汎用性がありイメージ表示をRGB各 8ビットのフ
ルカラー表示するためのRGBAモード(AUX RGBA)かのどちらかを指定する.
AUX SINGLEのシングルバッファモードでは,画面をオブジェクトのアニメーションの
ため再描画すると,画像がちらつくことがある.これは再描画時点のイメージが残像として
残るためである.そこで,描画中の画面を表示するために,裏画面で描画して表示画面と切
換えを行うAUX DOUBLEのダブルバッファモードを使用するとよい.
デプスバッファは,ワイヤーフレームではなく塗りつぶされたオブジェクトを描くとき
に使用する.このデプスバッファの指定を行わなければOpenGLが隠面処理を行うことが
できず,自然な表示結果が得られない.OpenGLではZ-bu�er法によるレンダリングを行っ
ている.この隠面処理はレイトレーシング法よりずっと高速で,その代わり処理に当たって
はデプスバッファという記憶領域が必要となる.auxInitDisplayModede()でデプスバッファ
の使用を指定すると,デプスバッファの記憶領域を openGLが自動的に確保するが,描画を
行う前に,前もってglEnable(GL DEPTHTEST)によって,描画時のデプスバッファによ
る処理を有効にしておかなければならない.
ステンシルバッファとアキュームレーションバッファは使用してないので説明を省く.
ウィンドウの寸法
auxInitPosition(int x,int y,int w,int h)
作成するウィンドウをウィンドウ左上位置 (x,y),幅w,高さhのウィンドウとする.
ウィンドウのタイトル
auxInitiWindow(char titlestring)
文字列 titlestringというタイトルのウィンドウの実体を作成する.
19
各種コールバック関数の指定
ウィンドウの作成が終わると,次にイベントドリブン方式の核となる,コールバック関数
を定義する.イベントドリブン方式プログラムを作成するために,これらの関数をイベント
処理ループ (AUXライブラリではauxMainLoop)に入る前に指定しておく必要がある.
AUXライブラリでは,コールバック関数で指定できるイベントに以下の四つがある.
²ウィンドウのリシェイプ (サイズ変更,移動,アクティブ化)時²マウスボタンのクリック時²キーボードのキーが押された場合²アイドリング状態時
これらのコールバック関数を前もって指定しておけば,そのイベントが起こった時にコー
ルバック関数で指定した関数が実行される.
前述のプログラム例では,この中のウィンドウがリシェイプされたときとキーボードの
キー (スペース)が押されたときのイベントの処理の指定を行っている.他のコールバック
関数は使用していないので,指定する必要がない.
この例では以下のように指定している.
auxReshapeFunc(Reshpe);
auxKeyFunc(AUX SPACE,Key dpace);
Windowsでは,コールバック関数で指定した関数は,次の例のようにCALLBACK型で
宣言する必要がある.
(例)
void CALLBACK Display(void)
fgvoid CALLBACK Resheape(int w,int h)
fg
次に三つのイベント処理に関する説明を行う.
ウィンドウのリシェイプ (サイズ変更,移動,アクティブ化)時
void CALLBACK auxReshapeFunc((function)(int w,int h))
ウィンドウの再描画のイベントが生じた場合に関数を指定する.ウィンドウの移動やア
20
イコンかやウィンドウサイズの変更などによって生ずる.また,別のウィンドウと重なって
いた場所の再描画も含む.指定される関数には,引数としてそのときのウィンドウサイズ
(w,h)が渡される.ウィンドウサイズが変化すると,画面の縦横比が変化するため,画像が伸
びたり縮んだりする.これを防ぐには,glviewport()を新しいサイズで再定義する必要があ
る.すなわち,ビューポートの設定,射影行列の初期化,視体積の設定,視点の設定をもう一
度やりなおさなければならない.
main関数内;
auxReshapeFunc(Reshape);
指定した関数;
void CALLBACK Reshape(int w, int h);
fウィンドウの移動,サイズの変更等の時の処理g
マウスボタンのクリック時
void CALLBACK auxMouseFunc(int button,int mode,
void(function)(AUX EVENTRIC))
マウスボタンによるイベントが生じた場合に起動する関数を指定する.引数"button"と
"mode"でイベントを起こすときのマウスボタンの状態を指定し,引数 (function)でそのイ
ベントが生じたときに実行される関数名を指定する.
指定先の関数の引数となるAUX EVENTRICは構造体で,イベントが起こったときに,ウ
ィンドウ内における現在のマウス座標が構造体内の data[AUX MOUSEX]data[AUX MOUSEY]
に渡される.
引数"button"(ボタンの種類)
引数"mode"(ボタンの押下状態)
以下にその使用例を示す.
main関数内;
auxMouseFunc(); 指定した関数;
void ;
f/* 構造体からマウスの座標獲得 */
/* マウスの左ボタンが押された時の処理 */
g
21
キーボードのキーが押された場合
void CALLBACK auxKeyFunc(Key,void (function)(void))
キーボードのキー (KEY)が押されたというイベントが生じたときに実行される関数を指
定する.
KEYで指定可能なシンボル定数は表7.1の通りである.
以下にその使用例を示す.
main関数内;
auxKeyFunc();
指定した関数;
void ;
今回,アイドリング状態時の設定をしてないので,これについての説明は省略する.
22
表7.1: 指定可能なシンボル定数
シンボル定数 対応キー シンボル定数 対応キー
AUX A "A" AUX LEFT ←...
... AUX RIGHT →
AUX Z "Z" AUX UP ↑
AUX a "a" AUX DOWN ↓...
... AUX SPACE SPACE
AUX Z "z" AUX ESCAPE ESC
AUX 0 "0" AUX RETURN RETURN...
...
AUX 9 "9"
イベント処理ループ
コールバック関数の指定が終わると,auxMainLoopを使用してイベント処理ループに入
る.
void auxMainLoop(void(displayfunction)(void))
ウィンドウの更新が必要な場合に実行される関数を指定する.以後,OpenGLはコールバッ
ク関数で指定したイベント処理ループに入り,この処理 (displayfunction)で指定した関数
をプログラムが終了するまで繰り返し呼び出す.
以下にその使用例を示す.
main関数内;
auxMainLoop(display);/* displayという関数をループ */
指定した関数;
void display(void);
ポリゴンの描画処理
基本的には,このauxMainLoop()により指定された関数displayの中でポリゴンを描画
するが,このポリゴンを描画する前と後にやっておくことがあるのでそれを以下に説明す
る.
まずポリゴンを描画する前に,glClear()を用いて各使用するバッファをクリアする必要
がある.
void glClear(MASK)
引数"MASK"で指定したバッファをクリアする.指定できるシンボル定数は以下の通り.複
数のバッファを同時にクリアする場合には記号"j"(OR)でつなぐ.
GL_COLOR_BUFFER_BIT カラーバッファ
23
GL_DEPTH_BUFFER_BIT デプスバッファ
GL_STENCIL_BUFFER_BIT ステンシルバッファ
GL_ACCUM_BUFFER_BIT アキュームバッファ
また,ポリゴンを描画した後に,描画の実行を完全にするために glFlush()を使用して描画
を強制的に行った後,AUXライブラリの関数であるauxSwapBu�er()により表示バッファ,
書き込みバッファの反転を行って,ダブルバッファを使って描画を実現することができる.
void auxSwapBu�er(void)
ダブルバッファモードが指定されているとき,表示バッファの反転,書き込みバッファの反
転を行い,描画を高速にさせる.
前述の通り,通常シングルバッファモードでは,アニメーションをさせる場合,ポリゴン
の描画している様子が見えて,画面のチラツキの原因となることがある.そこで,このダブ
ルバッファモードでは,画面を文字どおり表と裏の二つを使用して描画を行う.これにより
画面のチラツキは大幅に減少する.
最初に,ポリゴンの描画が終わるまでディスプレイにはもう一方の裏面を表示しておき,
ポリゴンを描き終えてから auxSwapBu�er()を用いて表と裏を切り替える.すると,最初か
ら描画済みの画面がディスプレイに表示される.
次に,同様にしてディスプレイには表示されていない裏面にポリゴンを描画する.描画し
終えたら,auxSwapBu�er()を用いて表と裏を切り替える.これを繰り返していく.すると,
ディスプレイに表示されているのは常に描画済の画像ということになり,スムースにポリ
ゴンをアニメーションさせることが可能となる.
24
8 色と法線
glBegin()と glEnd()の間には,glVertex()以外にも色や法線などに関する各種コマンドを
指定できる.これらを指定できる9種のコマンド群があるが,今回は glVertex()(頂点座標の
指定),glColor()(現在のカラー設定)のみしか使用していないので,他のコマンドに関する
説明は省略する.これら以外のコマンドを glBegin()とglEnd()の間に入れることはできな
い.この節では,この中の色や法線を設定するコマンドの利用方法について説明する.
OpenGLにおける色の表現方法
auxInitDisplayMode()で最初にウィンドウを作成する時は,使用するカラーバッファの
モードを選び指定しなければならない.OpenGLには,ウィンドウシステムに依存するイン
デックスモードと,色をRGBの3要素と不透明度で表したRGBAモードの 2種類のモード
がある.ここでは,RGBAモードのみを使用し,インデックスモードによる色の指定は汎用
性が少ないことから省略する.
RGBAモードでは色を"赤 (Red)","緑 (Green)","青 (Blue)","不透明度 (Alpha)"で表す.
不透明度は"0.0"~"1.0"の範囲で表し,RGBの値を組み合わせることによって様々な色を
表現する.OpenGLでは描画色を指定する関数に glColor()がある.このglColor()には幾つ
かの使用方法がある. glColor3f(R,G,B); としてR,G,Bの値を指定すれば良い. glColor3f()
では,無条件に"A"の値が"1.0"となる.
背景色
OpenGLで背景色を指定する関数はglClearColor()である.glClear()によりカラーバッ
ファの内容を消去した際に,この glClearColor()で指定した色を用いて消去される.以下の
ようにして用いる.
void glClearColor(GLclampf r,GLclampf g,GLclamp a)
RGBAモードでのカラーバッファの消去値の設定を行う.GLclampfにより指定できる値の
範囲は"0.0"~"1.0"までで,初期値はすべて"0.0"である.
異なる色の線形補間方法
さらに頂点ごとに色を指定するすることができる.頂点ごとに色を指定するには glVer-
tex()による頂点指定の直前で glColor()を使用して行う.次にその例を示す.
glBegin(GL\_POLYGON);
glColor3f(0.0,1.0,0.0);glVertex3f(-1.0,1.0,0.0);/*赤の頂点を指定*/
25
glColor3f(0.0,1.0,0.0);glVertex3f(-1.0,-1.0,0.0);/*緑の頂点を指定*/
glColor3f(0.0,0.0,1.0);glVertex3f(1.0,-1.0,0.0);/*青の頂点を指定*/
glColor3f(1.0,1.0,1.0);glVertex3f(1.0,-1.0,0.0);/*白の頂点を指定*/
glEnd();
この様にすることにより,異なる色を有する頂点間で自動的に色の線形補間が行われ,滑ら
かに色を変えていくことができる.ただし,これは後述するシェーディングモードがスムー
スシェーディングのとき行われる.
法線の概念
法線とは,ある面に対する垂直方向を表すベクトルで,OpenGLではこの法線を指定する
ことにより面の表と裏の区別をし,光源計算やシェーディング処理などを行う.
普通,法線は一つの面に対して,一つしか存在しないが,OpenGLでは面を構成する頂点
ごとに法線を指定できる.
この考え方はスムースシェーディング等を行う際に最も重要な概念で,頂点間を移り変
わるにつれて法線の向きを変化させてやることによって,実際は平面でも面に凹凸がある
ように見せたり,反対に面と面のつなぎ目が目立つポリゴンの分割数が少ない多面体を球
面のように滑らかに見せることができる.
NNv
Nv
NvNv
NvNv
NN N
N
(a)ポリゴン (b)曲面
図 6: 法線の補間
シェーディング処理
OpenGLでは二つのシェーディング処理を行うことができる.一つはフラットシェーディ
ングと呼ばれる単一のカラーでポリゴンを塗り潰す方法と,スムースシェーディング (また
はグローディング)と呼ばれる複数のカラーで塗り潰す方法である.
シェーディング処理によって,例えば前述のように面と面のつなぎ目が目立つ,分割数が
少ないポリゴンで表した球面を滑らかに見せることができる.
この処理の指定はvoid glShadeModel(MODE)である.次のように行うが,描画の前
に宣言しておく必要がある.
26
glShadeModel(GL_SMOOTH); スムースシェーディング行う
glShadeModel(GL_FLAT); フラットシェーディングを行う
また初期設定ではスムースシェーディングモードになっているが,頂点ごとの法線を正確
に設定しなければ正しく処理されない.
ここまで述べてきたことを用いて,プログラムを作成した.以降にプログラムとその説明を
する.
27
9 考察
今回は,テキストファイルに入力したデータをOpenGLを用いたプログラムとリンクさ
せ図形を出力できた.これは,プログラム上に書き込むよりも簡単でかつ速い.また,プログ
ラムをあまり理解していない人にでも簡単に図形を出力することが出来る良さがある.
28
11 参考文献
[1]三浦憲二郎,OpenGL プログラミング・ガイドブック,入門,朝倉書店, 1995年
[2]新C++言語入門, 林 晴比古, SOFTBANK BOOKS, 1998年
[3]C/C言語ハンドブック, エイチアイ著, ナツメ社, 1999年
[4]演習C言語入門, 宮地 功, 共立出版, 1996年
[5]C言語プログラミング, ハーベイ・M・ダイテル&ポール・J・ダイテル, プレンティ
スホール出版, 1998年
[6]ザ・C, 戸川 隼人, サイエンス社, 1987年
30