2

opengl ピッキングに関する多くのサンプル コードを読みました。それらのほとんどすべてが投影に gluPerspective 関数を使用しています。私は gluPerspective 関数の代わりに glOrtho を使用しています。

そして、私のSelection関数は以下の通りです(DrawBufferは私のペイントコードです):

void Selection( int x, int y )
{
    GLuint buffer[512];
    GLint hits;

    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);
    glSelectBuffer(512, buffer);

    (void)glRenderMode(GL_SELECT);

    glInitNames();
    glPushName(0);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();

    GLdouble w = (double)m_ClientRect.Width();
    GLdouble h = (double)m_ClientRect.Height();
    gluPickMatrix((GLdouble)x, (GLdouble)(viewport[3] - y), 500, 500, viewport);
    glOrtho(-w / 2, w / 2, -h / 2, h / 2, -1000000.0, 100000.0);
    glMatrixMode(GL_MODELVIEW);
    DrawBuffer();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    hits = glRenderMode(GL_RENDER);

    if (hits > 0)
    {
        TRACE(_T("%d %d %d %d %d\n"), hits, buffer[0], buffer[1], buffer[2], buffer[3]);
    }
}

しかし、それは機能しません、私はその理由を理解できませんか?もう 1 つの問題は、glDrawArrays 関数を使用して多数の線を描画する場合、glLoadName を呼び出して各線にフラグを付けるにはどうすればよいかということです。

私のレイトレーサーアルゴリズムは次のとおりです。

void CGraphicView::KDSearch( PICKING_VERTEX *root, CRay *pRay, PICKING_VERTEX **found, double *dCurSplit )
{
    if (NULL == root)
    {
        return;
    }
    SearchNode(root, m_pRay, m_globaltMin, m_globaltMax, found, dCurSplit);
}

void CGraphicView::SearchNode( PICKING_VERTEX *node, CRay *pRay, double tmin, double tmax, PICKING_VERTEX **found, double *dCurSplit )
{
    if (NULL == node)
    {
        return;
    }
    if (node->bLeaf)
    {
        SearchLeaf(node, pRay, tmin, tmax, found, dCurSplit);
    }
    else
    {
        SearchSplit(node, pRay, tmin, tmax, found, dCurSplit);
    }
}

void CGraphicView::SearchSplit( PICKING_VERTEX *split, CRay *pRay, double tmin, double tmax, PICKING_VERTEX **found, double *dCurSplit )
{
    if (NULL == split)
    {
        return;
    }
    int axis = split->axis;
    double thit = pRay->GetSplit(axis, split->coor[axis]);

    Point3D pSrc(split->coor[0], split->coor[1], split->coor[2]);
    double scale = m_pCam->GetScale();
    double disP2L = DistanceP2L(pSrc, m_RayStart, m_RayEnd);
    if (disP2L * scale < MAX_DISTANCE && thit < *dCurSplit)
    {
        *found = split;
        *dCurSplit = thit;
    }

    PICKING_VERTEX *first = NULL, *second = NULL;
    if (IS_EQUAL_FLOAT(pRay->m_direction[axis], 0.0))
    {
        first = (pRay->m_origin[axis] < split->coor[axis]) ? split->left : split->right;
    }
    else
    {
        first = (pRay->m_direction[axis] > 0.0) ? split->left: split->right;
        second = (pRay->m_direction[axis] < 0.0) ? split->left : split->right;
    }

    if ((thit >= tmax || thit < 0))
    {
        SearchNode(first, pRay, tmin, tmax, found, dCurSplit);
    }
    else if (thit <= tmin)
    {
        SearchNode(second, pRay, tmin, tmax, found, dCurSplit);
    }
    else
    {
        SearchNode(first, pRay, tmin, thit, found, dCurSplit);
    }
}

void CGraphicView::SearchLeaf( PICKING_VERTEX *leaf, CRay *pRay, double tmin, double tmax, PICKING_VERTEX **found, double *dCurSplit )
{
    if (NULL == leaf)
    {
        return;
    }

    int axis = leaf->axis;
    double thit = pRay->GetSplit(axis, leaf->coor[axis]);

    Point3D pSrc(leaf->coor[0], leaf->coor[1], leaf->coor[2]);
    double scale = m_pCam->GetScale();
    double disP2L = DistanceP2L(pSrc, m_RayStart, m_RayEnd);
    if (disP2L * scale < MAX_DISTANCE && thit < *dCurSplit)
    {
        *found = leaf;
        *dCurSplit = thit;
    }

    ContinueSearch(leaf, pRay, tmin, tmax, found, dCurSplit);
}

void CGraphicView::ContinueSearch( PICKING_VERTEX *leaf, CRay *pRay, double tmin, double tmax, PICKING_VERTEX **found, double *dCurSplit )
{
    if (IS_EQUAL_FLOAT(tmax, m_globaltMax))
    {
        return;
    }
    else
    {
        tmin = tmax;
        tmax = m_globaltMax;
        SearchNode(m_root, pRay, tmin, tmax, found, dCurSplit);
    }
}
4

2 に答える 2

1

glDrawArrays 関数を使用して多くの線を描画する場合、glLoadName を呼び出してそれぞれにフラグを付けるにはどうすればよいですか?

できません。率直に言って、そもそも OpenGL 選択モードを使用するべきではありません。遅く、現在サポートされているドライバーはなく (常にソフトウェア エミュレーション モードに戻ることになります)、シェーダーでは (うまく) 動作せず、使いにくいです。

はるかに優れた代替手段は、選択レイをシーンに逆投影するか、(最新の OpenGL が使用されている場合) バウンディング ボックス (または他の種類のバウンディング ボリューム) に適用される変換フィードバック バッファーを使用して、ジオメトリをスクリーン スペース Kd ツリーにソートすることです。クリックしたものをすばやく選択できます。

于 2013-05-21T11:21:56.860 に答える
0

まあ、メモリからヒット == 0 をデバッグする 1 つの方法は、通常のレンダリングにまったく同じピック マトリックスを使用するか、この場合は glRenderMode 呼び出しをコメント アウトすることでした。何も描画されていない場合は、シーンのどの部分もピック領域と交差しておらず、選択コードは指定したとおりに実行されています。

ただし、datenwolf は正しく、OpenGL 選択モードは避けるべきです。恐ろしいです。

レイキャスティングや Kd ツリーを必要としないピッキングを実装するかなり簡単な方法は、各オブジェクトを異なる色で描画することです。すべてのオブジェクトに一意の識別子番号 (とにかく glLoadName に必要) があると仮定して、それを 3 バイトの RGB カラー値に変換します。シーンをバック バッファーのみに描画し、マウス座標の下のピクセルを読み取ります。その RGB 値は、最前面のオブジェクトの識別子になります。

于 2013-05-22T02:52:24.963 に答える