03.ピックOpenGLビュークラスを作る



ピッキング(要素選択)に関する処理を担うピックOpenGLビュークラスを、トラックOpenGLビュークラスの派生クラスとして作成します。

解説

OpenGLにおける、ピック処理は、古くは、「セレクション」と呼ばれる、セレクションモード(glRenderMode(GL_SELECT))と、関連するルーチン(glSelectBuffer関数、glPushName関数、等)、を使用して、実現しました。

現在においても「セレクション」は使用可能ですが、「セレクション」の使用は推奨されていません。「セレクション」は、OpenGL3で、非推奨となりました。
また、最近のグラフィックボードの中には、「セレクション」について、ハードウェア・アクセラレーション(ハードウェア実装による実行速度向上)の効果が低いものも多くあるようです。

以上から、本「モデルビューワを作る」では、ピックを実現する方法として、「セレクション」ではなく、「オフスクリーンレンダリング」と呼ばれる方法を採用します。
「オフスクリーン」すなわち、(スクリーン上ではなく)メモリ上に描画します。モデルを表示用の色で描画するのではなく、それぞれの要素を識別する色で描画します。描画後、ピックしたピクセルの色を読み込み、ピクセルの色からピックした要素を識別します。

「オフスクリーンレンダリング」の実現方法として、「フレームバッファー」を使用します。
「フレームバッファー」は、OpenGLの拡張機能なので、OpenGLの拡張機能を使えるようにする必要があります。

プロジェクトの作成

「メニュー/新規作成/プロジェクト」を選択します。

プロジェクトの種類:MFC
テンプレート:MFC アプリケーション
プロジェクト名:OpenGLPick
場所:適当なフォルダを指定
ソリューションのディレクトリの作成:チェックしない
でOKボタンを押します。

以降、「01.ベースOpenGLビュークラスを作る」におけるプロジェクト作成と同じ設定でプロジェクトを作成します。

ビルドし、エラー、警告がないことを確認します。

ベースOpenGLビュークラスファイル、トラックOpenGLビュークラスファイルをプロジェクトに追加

「02.トラックOpenGLビュークラスを作る」で作成した
OpenGLBaseView.cpp
OpenGLBaseView.h
OpenGLTrackView.cpp
OpenGLTrackView.h
をOpenGLPickプロジェクトフォルダにコピーします。

「メニュー/プロジェクト/既存項目の追加」を選択します。
OpenGLBaseView.cpp
OpenGLBaseView.h
OpenGLTrackView.cpp
OpenGLTrackView.h
を追加します。

OpenGLTrackView.cppの
#include "OpenGLTrack.h"
#include "OpenGLTrackDoc.h"
をコメントアウトします。



OpenGLTrackView.cppおよびOpenGLTrackView.hの
「COpenGLTrackDoc」を「CDocument」に置換します。(「大文字と小文字を区別する」「単語単位」にチェックを入れます。)

ビルドし、エラー、警告がないことを確認します。

ピックOpenGLビュークラスの親クラスの変更

OpenGLPickView.h に
#include "OpenGLTrackView.h"
を追加します。



OpenGLPickView.cpp および OpenGLPickView.h の
「CView」を「COpenGLTrackView」に置換します。(「大文字と小文字を区別する」「単語単位」にチェックを入れます。)

ビルドし、エラー、警告がないことを確認します。

ピックOpenGLビュークラスのOnDraw関数の削除

ベースOpenGLビュークラスのOnDraw関数が呼ばれるように、ピックOpenGLビュークラスのOnDraw関数を削除します。
(オーバーライド関数の削除は、「クラスビュー」と「プロパティビュー」を使用します。
 まず、「クラスビュー」で、メッセージハンドラを削除するクラスを選択します。
 次に、「プロパティビュー」のツールバーの「オーバーライド」を選択します。削除するオーバーライド関数の右側のドロップダウンリストを用いてオーバーライド関数を削除します)

ビルドし、エラー、警告がないことを確認します。

実行し、OpenGLTrackプログラムと同じ結果になることを確認します。

OpenGL拡張機能の導入

OpenGL拡張機能の導入の方法

OpenGLの拡張機能を使えるようにするための方法としては、「GLEW」を利用する方法があります。
シェーダー機能を使用する場合など、多くの拡張機能の関数を使用する場合は、「GLEW」を利用するのが楽ですが、
この「モデルビューワを作る」では、全体で、OpenGLの拡張機能を3機能(FrameBuffer、RenderBuffer、VertexBuffer)、関数にして14個程の関数しか使用しないので、「GLEW」を利用する方法ではなく、よりプリミティブ(根源的)な方法である、「glext.hとwglGetProcAddress()」を利用する方法で、OpenGLの拡張機能を使えるようにします。

「GLEW」を利用する方法と、「glext.hとwglGetProcAddress()」を利用する方法とで、OpenGL機能拡張の導入の仕方は異なりますが、拡張機能の使い方は変わりません。

glext.hファイルのダウンロードと設置

Khronos OpenGL® Registry - The Khronos Group Inc」にアクセスし、
「API and Extension Header Files」の項から、
「<GL/glext.h>」と「<KHR/khrplatform.h>」を、「右クリック > 名前を付けて保存」により、
「glext.h」と「khrplatform.h」をダウンロードします。

glext.h ファイルを設置する場所を調べます。
VisualStudioにて、OpenGLBaseView.hを表示します。

マウスカーソルを「<gl\gl.h>」の上に置き、「右クリック > ドキュメント <gl\gl.h> を開く」で、「gl.h」を開きます。
マウスカーソルを「GL.h」タブの上に置くと、「gl.h」のフルパスが表示されます。
(例えば、「C:\Program Files (x86)\Windows Kits\8.1\Include\um\gl\gl.h」と表示されます。)

「gl.h」のあるフォルダにダウンロードした「glext.h」を設置し、
「gl.h」のあるフォルダの親フォルダ(「gl」フォルダのあるフォルダ)に「KHR」フォルダを作成し、作成した「KHR」フォルダに、ダウンロードした「khrplatform.h」を設置します。
(例えば、「C:\Program Files (x86)\Windows Kits\8.1\Include\um\gl\」に「glext.h」ファイルを設置し、
 「C:\Program Files (x86)\Windows Kits\8.1\Include\um\」に「KHR」フォルダを作成し、
 「C:\Program Files (x86)\Windows Kits\8.1\Include\um\KHR」に「khrplatform.h」を設置します。)

glext.hの設置例


khrplatform.hの設置例

wglGetProcAddress()による関数アドレスの取得

「メニュー/プロジェクト/新しい項目の追加」で
「OpenGLExtFuncs.h」
「OpenGLExtFuncs.cpp」
という2つのファイルを作成します。

それぞれ、内容を以下のようにします。

OpenGLExtFuncs.h


OpenGLExtFuncs.cpp


ビルドし、エラー、警告がないことを確認します。

OpenGL拡張機能を使えるようにするためのヘッダーファイルのインクルード

OpenGLBaseView.h に以下のOpenGL拡張機能を使えるようにするためのヘッダーファイルのインクルードを追加します。
#include "OpenGLExtFuncs.h"



ビルドし、エラー、警告がないことを確認します。

OpenGL初期化処理の編集

OpenGLBaseView.cpp にOpenGL初期化処理に、OpenGL拡張機能をつけるようにするための初期化処理の呼び出しを追加します。

メンバ変数、メンバ関数の宣言の追加

OpenGLPickView.h のピックOpenGLビュークラス定義の前に
名前列の大きさの定義
列挙型ERENDERMODEの定義
を追加します。
OpenGLPickView.h のピックOpenGLビュークラス定義の最初にメンバ変数、メンバ関数の宣言を追加します。



ビルドし、エラー、警告がないことを確認します。

メンバ変数の初期化

OpenGLPickView.cpp のピックOpenGLビュークラスのコンストラクタにメンバ変数の初期化を追加します。



ビルドし、エラー、警告がないことを確認します。

フレームバッファの構築、破棄

OpenGLPickView.cpp にフレームバッファの構築、破棄にに関するメンバ関数の定義を追加します。



OpenGLBaseView.h のベースOpenGLビュークラスのメンバ関数
UninitializeOpenGL
をprotected関数、さらにvirtual関数とします。



ビルドし、エラー、警告がないことを確認します。

OnSize関数の追加、編集

ピックOpenGLビュークラスにWM_SIZEメッセージに対応するメッセージハンドラOnSize関数を追加します。
(メッセージハンドラの追加は、「クラスビュー」と「プロパティビュー」を使用します。
 まず、「クラスビュー」で、メッセージハンドラを追加するクラスを選択します。
 次に、「プロパティビュー」のツールバーの「メッセージ」を選択します。追加するメッセージ「WM_XXX」の右側のドロップダウンリストを用いてメッセージハンドラを追加します)

フレームバッファの構築処理関数の呼び出しを追加します。



ビルドし、エラー、警告がないことを確認します。

RenderScene関数のオーバーライド

ベースOpenGLビュークラスの描画処理は要素ピックを考慮していません。
ピックOpenGLビュークラスに要素ピックを考慮した描画処理 RenderScene関数 をオーバーライドします。

OpenGLPickView.cpp にRenderScene関数の定義を追加します。さらにRenderScene関数で呼び出されるメンバ関数RenderModel関数の定義を追加します。



OpenGLBaseView.h のベースOpenGLビュークラスのメンバ関数
RenderScene
をprotected関数、さらにvirtual関数とします。



ビルドし、エラー、警告がないことを確認します。

DoPicking関数の追加、編集

OpenGLPickView.cpp に要素選択操作に関するメンバ関数の定義を追加します。



ビルドし、エラー、警告がないことを確認します。

マウス操作イベントハンドラの追加、編集

以下のマウス操作メッセージハンドラをピックOpenGLビュークラスに追加します。
(メッセージハンドラの追加は、「クラスビュー」と「プロパティビュー」を使用します。
 まず、「クラスビュー」で、メッセージハンドラを追加するクラスを選択します。
 次に、「プロパティビュー」のツールバーの「メッセージ」を選択します。追加するメッセージ「WM_XXX」の右側のドロップダウンリストを用いてメッセージハンドラを追加します)

ウィンドウメッセージ名 メッセージハンドラ名
WM_RBUTTONUP OnRButtonUp

メッセージハンドラにメンバ関数の呼び出しを追加します。



ビルドし、エラー、警告がないことを確認します。

実行

右クリックにより要素をピックできること
点をピックすると、ピックした点の色がピンク色になり点の大きさが少し大きくなること
線をピックすると、ピックした線の色が水色になり線の太さが少し太くなること
面をピックすると、ピックした面の色が黄色になること
を確認します。

実行結果

ダウンロード

ソースファイルダウンロード (ModelViewerOpenGLMFC2015_03_pick.zip)

関連ページ

前項目:02.トラックOpenGLビュークラスを作る

次項目:04.モデルビューワを作る