7

私はglScissor()自分のアプリケーションで使用しており、正常に動作しますが、問題が発生Windowしました。描画領域が指定されたオブジェクトがありglScissor()、この領域内ListViewにあり、描画領域も指定する必要があるオブジェクトを描画していますglScissor()全部描きたくないので。

コードでは、次のように表すことができます。

Window::draw() 
{
   glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw some components...
        mListView.draw(); // mListView is an object of ListView type
   glDisable(GL_SCISSOR_TEST);
}

ListView::draw()
{
  glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw a chosen part of ListView here
   glDisable(GL_SCISSOR_TEST);
}

しかしもちろん、この状況では有効化/無効化の呼び出しは間違っています:

glEnable(GL_SCISSOR_TEST);
   glEnable(GL_SCISSOR_TEST);
   glDisable(GL_SCISSOR_TEST);
glDisable(GL_SCISSOR_TEST);

これらの内部 glEnable/glDisable 呼び出し (ListView のもの) を削除すると、やはり間違っているように見える 2 つの glScissor() 呼び出しが発生します。

編集

私はどうにかして両方のシザー効果を達成したいと思います。つまり、ウィンドウはシザー領域でのみ描画し、内部 ListView もシザー領域でのみ描画する必要があります。

画像でわかるように、赤い四角形Windowで WORKS のはさみ領域をマークし、青い四角形で を描きたい領域をマークしましたListView。そのため、入れ子式のはさみを使用しようとしていましたが、役に立たなかったことがわかりました。基本的に私の質問は、これを達成するための最良のアプローチは何でしょうか?

ここに画像の説明を入力

4

3 に答える 3

8

OpenGL はステート マシンであり、シザー四角形は他のステートと同様にglScissor、次回の呼び出し時に上書きされるため、リスト ビューの描画後にウィンドウのシザー四角形を適切に復元する必要があります。これは、ウィンドウに管理させるだけで実行できます。

Window::draw() 
{
    // draw some components with their own scissors
    mListView.draw(); // mListView is an object of ListView type

    glScissor(x, y, width, height);
    glEnable(GL_SCISSOR_TEST);
        // draw other stuff using window's scissor
    glDisable(GL_SCISSOR_TEST);
}

ただし、特にこのような階層的な方法で使用される場合は、個々のコンポーネントがシザーの状態自体を復元できるようにする方が柔軟な場合があります。このために、非推奨のglPush/PopAttrib関数を使用して、シザー四角形を保存および復元できます。

ListView::draw()
{
    glPushAttrib(GL_SCISSOR_BIT);
    glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw a chosen part of ListView here
    glDisable(GL_SCISSOR_TEST);
    glPopAttrib();
}

または、シザーの状態を自分で保存して復元します。

ListView::draw()
{
    // save
    int rect[4];
    bool on = glIsEnabled(GL_SCISSOR_TEST);
    glGetIntegerv(GL_SCISSOR_BOX, rect);

    glEnable(GL_SCISSOR_TEST);
    glScissor(x, y, width, height);
        // Draw a chosen part of ListView here

    // restore
    glScissor(rect[0], rect[1], rect[2], rect[3]);
    if(!on)
        glDisable(GL_SCISSOR_TEST);
}

もちろん、これは素敵な RAII ラッパーを使用して自動化できますが、それは自由に実行できます。

于 2013-02-01T12:14:51.517 に答える
4

編集済み: 一般的なケース。

でシザー状態を設定するたびに、シザー状態をglScissor設定します。ネストもスタックもしないため、 へのネストされた呼び出しで「サブシザー」することはできませんglScissor。あなたListViewとあなたのWindow境界四角形の長方形の交点を手動で計算し、描画するときにそれをはさむ必要がありますListView

一般的なケースでは、はさみ長方形のスタックを手動で維持します。各サブ要素を描画するとき、スタックの現在の上部に対してサブ要素の境界四角形を交差させ、それをそのサブ要素のはさみとして使用します。子をペイントするときに新しいサブレクトをスタックにプッシュし、階層に戻るときにポップします。

他のコンテンツを にペイントする場合はWindow、オーバードローを正しく処理することも確認する必要があります。Z 順序を設定して深度バッファリングを有効にするか、深度バッファリングを無効にしてコンテンツを前後にペイントします。はさみは長方形の領域にしかできないため、はさみはWindowの背後にあるコンテンツをマスクするのに役立ちません。ListView

于 2013-02-01T11:33:46.133 に答える
1

OpenGL はステート マシンです。glScissor、glEnable、glDisable は何度でも呼び出すことができます。これらは、一致する必要がある開き括弧と閉じ括弧のようには機能しません。通話がこのように「フォールド」しても問題ありません。一方のはさみがもう一方のはさみと合体するとは思わないでください。以前の設定を変更/上書きするだけです。

于 2013-02-01T11:30:52.507 に答える