1999 年度卒業研究 OpenGL を用いた簡易プログラム作成 岡山理科大学 理学部 応用数学科情報専攻 ―澤見研究室― 学番:S96M501 氏名:荒木 優子 学番:S96M596 氏名:波多江 学 学番:S96M649 氏名:吉永 雄高 目 次 1 はじめに 3 2 OpenGL の歴史 4 3 OpenGL の特徴 5 4 OpenGL について OpenGl の機能について : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : グラフィックス機能および言語の意味解説 : : : : : : : : : : : : : : : : : : : : : 6 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 色と法線 OpenGL における色の表現方法 背景色 : : : : : : : : : : : : : : 異なる色の線形補間方法 : : : : 法線の概念 : : : : : : : : : : : シェーディング処理 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 25 25 25 25 26 26 : : : : : : : : : : : : : : : : : : : : : : : : : 1 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 9 考察 28 10 今後の課題 29 11 参考文献 30 12 付録 31 13 謝辞 32 2 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-Window UNIX 上で動くウィンドウ・システム. ² Windows NT NT は 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 図 6.3 視体積の設定 14 透視法射影 透視法射影とは, 視点から遠くになるほど小さく表示されることから遠近感が得られや すく, 我々の眼 (またはカメラ) の特性に近い射影である. 透視法射影の視体積の設定には ,glFrustum() で行うがこれはあまり実用的では無いので, 通常 glu ライブラリの gluPerspective() を使用する. ここでは,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 #include #include #include "glos.h" <GL/gl.h> <GL/glu.h> <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) f g void CALLBACK Resheape(int w,int h) f g 次に三つのイベント処理に関する説明を行う. ウィンドウのリシェイプ (サイズ変更, 移動, アクティブ化) 時 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 Z AUX a .. . "Z" "a" .. . AUX Z AUX 0 .. . "z" "0" .. . AUX 9 "9" シンボル定数 AUX LEFT 対応キー ← AUX RIGHT AUX UP AUX DOWN → ↑ ↓ AUX SPACE AUX ESCAPE AUX RETURN SPACE ESC RETURN イベント処理ループ コールバック関数の指定が終わると,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"である. 異なる色の線形補間方法 さらに頂点ごとに色を指定するすることができる. 頂点ごとに色を指定するには glVertex() による頂点指定の直前で 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 では面を構成する頂点 ごとに法線を指定できる. この考え方はスムースシェーディング等を行う際に最も重要な概念で, 頂点間を移り変 わるにつれて法線の向きを変化させてやることによって, 実際は平面でも面に凹凸がある ように見せたり, 反対に面と面のつなぎ目が目立つポリゴンの分割数が少ない多面体を球 面のように滑らかに見せることができる. Nv Nv N Nv Nv N Nv N N (a) ポリゴン Nv N (b) 曲面 図 6: 法線の補間 シェーディング処理 OpenGL では二つのシェーディング処理を行うことができる. 一つはフラットシェーディ ングと呼ばれる単一のカラーでポリゴンを塗り潰す方法と, スムースシェーディング (また はグローディング) と呼ばれる複数のカラーで塗り潰す方法である. シェーディング処理によって, 例えば前述のように面と面のつなぎ目が目立つ, 分割数が 少ないポリゴンで表した球面を滑らかに見せることができる. この処理の指定は void glShadeModel(MODE) である. 次のように行うが, 描画の前 に宣言しておく必要がある. 26 glShadeModel(GL_SMOOTH); スムースシェーディング行う glShadeModel(GL_FLAT); フラットシェーディングを行う また初期設定ではスムースシェーディングモードになっているが, 頂点ごとの法線を正確 に設定しなければ正しく処理されない. ここまで述べてきたことを用いて, プログラムを作成した. 以降にプログラムとその説明を する. 27 9 考察 今回は, テキストファイルに入力したデータを OpenGL を用いたプログラムとリンクさ せ図形を出力できた. これは, プログラム上に書き込むよりも簡単でかつ速い. また, プログ ラムをあまり理解していない人にでも簡単に図形を出力することが出来る良さがある. 28 10 今後の課題 今回は,OpenGL を用いて簡単な 3 次元画像プログラムしか作成できなかったが, 今後の 課題としてより複雑な 3 次元画像プログラムを作成することを課題としたい. 29 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 12 謝辞 私達を 1 年間, 最後まで暖かい御指導を受け賜りました澤見先生に心より感謝いたします. また, 平成 11 年度澤見ゼミ生の方々に深く感謝いたします. 本当にありがとうございました. 31
© Copyright 2024 Paperzz