20. ピッキングとセレクションの使い方

20.010 ユーザがマウスでどのプリミティブを選んだのかを知るには?

OpenGLは、GL_SELECTION与えるモードをこの目的に提供します。 しかし、他の方法を使うことができます。

個々のプリミティブをユニークな色に表現してもよく、そして、現在のマウス位置の下の単一のピクセルを読むために、glReadPixels()を使用します。 色を試験することにより、ユーザーが選んだプリミティブが決定されます。 ここには、個々のプリミティブを、glDrawPixels()を使うことについてのユニークな色情報に表現することについての情報があります

まだ、別の方法は、マウス位置を通して選りすぐり光線を撃ち、現在表示されたオブジェクトによって交差について試験を受けることに関係します。 OpenGLは、光線交差(どのようにするかのために、BSP FAQを見てください)について試験を受けないけれども、選りすぐり光線を発生させるように、OpenGLと対話する必要があります

選りすぐり光線を生成する一方の方法は、そしてマウス位置〈0.0(近い飛行機の)のwinzを持つ1番目〉のために1.0のwinzによってgluUnProject()を2回呼ぶことです(遠い飛行機において)。 光線のXYZ方向ベクトルを得るために、近い飛行機呼び出しの結果を遠い飛行機呼び出しの結果から取り去ってください。 光線起源はもちろん、眺め位置です。

別の方法は、目座標の光線を発生させて、ModelView行列の逆によってそれを変換することです。 目座標では、選りすぐり光線起源は単にそうです(0、0、および0)。 パースペクティブ投射パラメータから例えばパースペクティブ投射をこの方法で設定して選りすぐり光線ベクトルを築くことができます

面=(window_width)二倍になる/2倍(window_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-near_height*面、
   near_height*面、
   -near_height、near_height、zNear、zFar);

これのように選りすぐり光線ベクトルを築くことができます:

int window_y=(window_height-mouse_y)-window_height/2;
2倍のnorm_y=(window_y) 二倍になり/2倍 (window_height/2);
int window_x = mouse_x-window_width/2;
2倍のnorm_x=(window_x) 二倍になり/2倍 (window_width/2);

左下の代わりにほとんどのウィンドウシステムがマウス座標原点をウィンドウの左上に置く(注。 それはwindow_yが故意の理由です それが上記のコードにある方法 。 ウィンドウ高さとマッチしないglViewport()を使う時には、ビューポート高さとビューポートYは、window_ynorm_yのための価値を決定するために用いられます。)

変数norm_xnorm_yは、-1.0から1.0まで測量されます。 マウス位置を、zNearを切り取っている飛行機同類にそう見つけるために、それらを使用してください:

フロートy = near_height * norm_y;
フロートx = near_height*面*norm_x;

現在、選りすぐり光線ベクトルはそうです(x、y、-zNear)。

この目同等選りすぐり光線をオブジェクト座標に変換するためには、使用において、ModelView行列の逆を、場面がされた時に乗算してください。 この増加を実行する時には、選りすぐり光線がベクトルおよび1ポイントにより構成されて、ベクトルとポイントが別に変わることを覚えていてください。 ポイントを翻訳し、回転するかもしれないけれども、ベクトルは回転するだけです。 これが働いていることを保証するための方法は、正しく、以下の偽りコードが見えるのでポイントとベクトルを4要素配列と定義することです:

フロートray_pnt{4=0.f、0.f、0.f、1.f};
フロートray_vec[4]={x、y、-near_distance、0.f};

最後の要素の1と0は、ModelView行列の逆のため増加する時に配列が1ポイントまたはベクトルとして変わるかどうかを決定します。

20.020 セレクションを利用するためには何を知らなければなりませんか?

選択バッファを指定してください

GLuintバッファ[BUF_SIZE];
glSelectBuffer(BUF_SIZE、バッファ);

選択モードに入り いつものように与える 、そして、選択モードを終了してください

閃光ヒット;

glRenderMode(GL_SELECT);
いつものようにの// ...render…
ヒット=glRenderMode(GL_RENDER);

glRenderMode(GL_RENDER)への呼び出しは、選択モードを終了し、選択バッファに蓄えられたヒットレコードの数を戻します。 個々のヒットレコードは、表示ボリュームの中にあったプリミティブについての情報を含んでいます(ModelViewと投射行列によってコントロールされます)。

それは基本的概念です。 実際の場で、眺めボリュームを限定したいかもしれません。 gluPickMatrix()機能は、現在のマウスやカーソル位置などの与えられた(X、Y)ポジションから向こうのピクセルのセット数内の眺めボリュームサイズを限定する便利な方法です。

興味のプリミティブについてのユニークな名前を指定するために、名前スタックを使用したい。 スタックが1回押された後に、種々の名前のどのような数でもスタックに負わされえます。 一般に、名前をロードし、そして、プリミティブまたはグループのプリミティブをしてください。 名前スタックは、heirarchicalなデータベースに存在するように、選択を可能にします。

GL_RENDER与えるモードに戻った後に、選択バッファを構文解析する必要があります。 それは0以上のヒットレコードを含みます。 ヒットレコードの数は呼び出しによりglRenderModeに戻されます(GL_RENDER)。 個々のヒットレコードは、未契約のintsとして蓄えられた以下の情報を含んでいます:

もし選ばれたプリミティブのオブジェクト同等位置を決定すると知られていて(マウスクリックからのたぶん)ならば、機器同等XとYによって最小のおよび最大のZ値を使うことができるでしょう。 0.0から1.0までの範囲までZ価値を削り落とし、呼び出しにおいてgluUnProject()にそれらを使うことができます

20.030 なぜセレクションが機能しないのでしょうか?

これは通常2つの物のうちの1つにより起こされます

逆にされたY 同等である を説明しましたか? ほとんどのウィンドウシステム(マイクロソフトWindows、Xウィンドウ、他?)は、ウィンドウのトップで通常Y=0によってマウス座標をプログラムに戻す一方、OpenGLは、Y=0がウィンドウの底にあると想定します。 もしデフォルトビューポートを使っているならば、ウィンドウシステム座標からOpenGL座標 として にY値を変換してください(windowHeight-y)。

変化を正しく設定しましたか? もしgluPickMatrix()を使っているならば、それは呼び出しのすぐ後に投射行列に負わされるべきです glLoadIdentity()に、および投射変化を増加させる (glFrustum()を使うこと、() gluPerspectiveであること、glOrthoなど())。 まるで正常に与えているかのようにModelView変化は同じであるはずです。

20.040 セレクションコードのデバッグするには?

選択または選択コードから虫を取り除くのに良いテクニックは、glRenderModeを呼ぶ必要がありません(GL_SELECT)。 単に、このファンクションコールをコードにコメントアウトしてください。 結果は、選択を実行する代わりにであり、コードは選りすぐりボックスの内容をウィンドウに与えます。 これは、何が選りすぐりボックスの中にあるかを視覚的にわかることを可能にします。

この方法とともに、それは、一般に、選りすぐりボックスを拡大するのに良いアイデアです。従って、ウィンドウにおいてもっと見ることができます

20.050 PHIGS や PEX と同じようなピッキングのハイライトを行うには?

これをするために、上品な方法が全然なく、それはOpenGL implementersとしてであり 理由 多くの元のPHIGS 、PEX implementersは 現在幸福です。 OpenGLはこれをアプリケーションに上げて放置します。

プリミティブを識別した後に、選択によって強調表示する必要がある どのようにそれを強調するかについて上にアプリケーションです。 違う色セットによって、プリミティブを、前のバッファの表示されたイメージに表現してさしつかえありません。 この仕事をするために、ポリゴンオフセットを用いる必要があるかもしれないか、またはglDepthFuncを少なくとも設定します(GL_EQUAL)。 アウトラインをするだけか、または発火効果を作成するために、原始的な連続的な時を種々の色に表現することができます。