5

SharpGL ライブラリを使用して WPF で 2D グラフを実装しています。画面上にいくつかのプリミティブ オブジェクトを描画できたので、これらのオブジェクトでのマウス クリックを検出する必要があります。

グラフィックオブジェクトの選択とピッキングを実行する方法に関するOpenGLチュートリアルを見てきましたが、うまく機能しませんでした。私のテスト アプリケーションでは、画面上に 3 つの三角形を描画し、マウス クリックが発生するとGL_SELECT、三角形のいずれかがクリックされたかどうかを検出するモードで同じ 3 つの三角形を描画します。これが正しいアプローチかどうかはわかりません。ヒット テストは常に選択バッファからすべての要素を返します。

PickMatrix の幅と高さのパラメーターが正しくないことはわかっています。正しい値が何であるかはよくわかりません。ビュー全体の幅と高さですか?

private void OpenGLControl_OpenGLDraw(object sender, SharpGL.SceneGraph.OpenGLEventArgs args)
{
    ////  Get the OpenGL object.
    OpenGL gl = args.OpenGL;

    //set background to white
    gl.ClearColor(1.0f, 1.0f, 1.0f, 1.0f);

    ////  Clear the color and depth buffer.
    gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
    DrawScene();
    gl.Flush();
}

private void DrawScene()
{
    OpenGL gl = openGLControl.OpenGL;
    gl.Color(1.0, 0.0, 0.0);
    DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6);

    gl.Color(0.0, 1.0, 0.0);
    DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2);

    gl.Color(0.0, 0.0, 1.0);
    DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2);
}

private void SelectObjects(double mouseDownX, double mouseDownY)
{
    OpenGL gl = openGLControl.OpenGL;
    int BUFSIZE = 512;

    uint[] selectBuf = new uint[BUFSIZE];

    gl.SelectBuffer(BUFSIZE, selectBuf);
    gl.RenderMode(OpenGL.GL_SELECT);

    gl.InitNames();
    gl.PushName(0);

    int[] viewport = new int[4];
    gl.GetInteger(OpenGL.GL_VIEWPORT, viewport);
    
    //how to define the width and height of an element?
    gl.PickMatrix(mouseDownX, (double)(viewport[3] - mouseDownY), 50.0, 50.0, viewport);

    gl.LoadIdentity();

    gl.LoadName(1);
    gl.Color(1.0, 0.0, 0.0);
    DrawTriangle(-0.2, 0.6, 0.0, 0.8, 0.2, 0.6);

    gl.LoadName(2);
    gl.Color(0.0, 1.0, 0.0);
    DrawTriangle(-0.2, 0.2, 0.0, 0.4, 0.2, 0.2);

    gl.LoadName(3);
    gl.Color(0.0, 0.0, 1.0);
    DrawTriangle(-0.2, -0.2, 0.0, 0.0, 0.2, -0.2);

    gl.Flush(); 
    int hits = gl.RenderMode(OpenGL.GL_RENDER);
    processHits(hits, selectBuf);
}

private void processHits(int hits, uint[] buffer)
{
    uint bufferIterator = 0;
    for (uint i = 0; i < hits; i++)
    {
        uint numberOfNamesInHit = buffer[bufferIterator];
        Console.WriteLine("hit: " + i + " number of names in hit " + numberOfNamesInHit);

        uint lastNameIndex = bufferIterator + 2 + numberOfNamesInHit;
        for (uint j = bufferIterator + 3; j <= lastNameIndex; j++)
        {
            Console.WriteLine("Name is " + buffer[j]);
        }

        bufferIterator = bufferIterator + numberOfNamesInHit + 3;
    }
}

private void OnMouseClick(object sender, MouseEventArgs e)
{
    System.Windows.Point position = e.GetPosition(this);
    SelectObjects(position.X, position.Y); 
}

出力は常に同じです。

ヒット: 0 ヒット 1 の名前の数

名前は1

hit: 1 ヒット 1 の名前の数

名前は2

hit: 2 ヒット 1 の名前の数

名前は3

4

2 に答える 2

3

width と height は、ピッキング領域のサイズ (ピクセル単位) です。マウス ポインターの下にあるオブジェクトを検出するには、1x1 で十分です (1 ピクセル x 1 ピクセルの画面四角形の下にあるものを検出する必要があります)。

gluPickMatrix現在のマトリックスをピッキング マトリックスで更新 (乗算) します。現在のマトリックスをアイデンティティにリセットするため、PickMatrixその後に続くものLoadIdentityは意味がありません。glLoadIdentity

サンプルを機能させるには、レンダリングする前に、マトリックスをセットアップします。

glLoadIdentity();
setupMyProjMatrix();

選択する前に、同じ行列を設定し、事前に pick 行列を乗算します。

glLoadIdentity();
glPickMatrix();
setupMyProjMatrix();

あなたのサンプルでは、setupMyProjMatrix()​​何もしません。

とにかく、opengl で使用ピッキングを避ける必要があります。これは非推奨の機能であり (最新の gl では削除されています)、ベンダーによっては非常に遅く、信頼性が低い場合があります。ヒット テストは自分で計算する必要があります。

gl (glGet ファミリー) に対してクエリを実行しないでください。CPU ストールを引き起こします。

下手な英語でごめんなさい。

于 2014-09-08T08:07:40.793 に答える
2

Olivier が既に述べたように、非推奨の機能は避けてください。代わりに、2 つの異なる方法でピッキングを行うことができます。

  • 前面に面したすべてのポリゴンを光線テストで実行して選択します。ここでは、視点からピクセルの中心を通り (平面に近い距離で) 光線を、ポリゴンに当たるか、選択範囲を超えるまで発射します。このソリューションは、複雑なシーンにはそれほどうまくスケーリングしませんが、実装するのはかなり簡単で、透明度などを処理するためのある程度の柔軟性を提供します.

  • color-id を持つすべてのオブジェクトをオフスクリーン テクスチャにレンダリングすることで、ビュー空間でピッキングを行うこともできます。次に、選択した 2D 座標のピクセル値を読み取り、その選択座標の下にあるオブジェクトに color-id をマッピングするだけです。ここでの欠点は、複数のオブジェクトを選択するのが難しく、レンダリングされたバッチに適切なカリングとシェーディングの設定が必要なことです。利点は、このソリューションが解像度に依存し、シーンの複雑さにあまり依存しないことです。

于 2014-09-14T12:06:30.783 に答える