16

編集:ご存じのとおり、私はまだこの問題を完全に解決していません。現在、0.5pxのオフセットを使用していますが、うまくいくようですが、他の人が言ったように、それは「適切な」解決策ではありません. だから私は本当の取引を探しています.ダイヤモンド出口ルールソリューションはまったく機能しませんでした.

おそらくグラフィックカードのバグだと思いますが、もしそうなら、プロのプログラマーなら誰でもこれに対する防弾ソリューションを持っているはずですよね?

編集:新しい nvidia カード (以前は ATI カードを使用していました) を購入しましたが、まだこの問題が発生しています。また、非常に多くのゲームで同じバグが見られます。だから、きれいな方法で修正することは不可能だと思いますか?

バグの画像は次のとおりです。

ここに画像の説明を入力

この問題をどのように克服しますか?可能であれば、非シェーダー ソリューションが望ましいです。ワイヤーフレーム モードを使用する代わりに、自分で 4 本の線を描いたときに最初の線にオフセットを設定しようとしましたが、うまくいきませんでした: 四角形のサイズが変更された場合、完全な四角形に見えることもあれば、修正前よりもさらに悪化することもありました.

これは私がクワッドをレンダリングする方法です:

glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBegin(GL_QUADS);
    glVertex2f(...);
    glVertex2f(...);
    glVertex2f(...);
    glVertex2f(...);
glEnd();
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

はい、頂点配列または VBO を使用できることはわかっていますが、それはここでは重要ではありません。

も試しGL_LINE_LOOPましたが、バグは修正されませんでした。

編集:これまでのところ機能する1つのソリューションがあります: Lie RyanによるOpenglピクセルパーフェクト2D描画:

OpenGL 座標空間には整数の概念がないことに注意してください。すべてが float であり、OpenGL ピクセルの「中心」は実際には左上隅ではなく 0.5,0.5 にあります。したがって、0,0 から 10,10 までの 1 ピクセル幅の線が必要な場合は、実際には 0.5,0.5 から 10.5,10.5 までの線を引く必要がありました。

これは、アンチエイリアシングをオンにすると特に顕著になります。アンチエイリアシングがあり、50,0 から 50,100 まで描画しようとすると、線が 2 つのピクセルの間にあるため、2 ピクセル幅のぼやけた線が表示されることがあります。

4

4 に答える 4

10

ポイントを 0.5 ずらすと問題が解決することがわかりましたが、それはあなたが考える理由によるものではありません。

答えは確かに、OpenGL ピクセル パーフェクト 2D 描画に対する正しく受け入れられた答えの中心でもあるダイヤモンドの出口規則にあります。

以下の図は、それぞれにダイヤモンドが刻まれた 4 つのフラグメント/ピクセルを示しています。4 つの色付きのスポットは、クワッド/ライン ループの可能な開始点、つまり最初の頂点のウィンドウ座標を表します。

フラグメントのダイヤモンドの外側にある可能性のある頂点

クワッドをどちらの方向に描いたかは言いませんでしたが、それは問題ではありません。議論のために、時計回りに描いていると仮定します。問題は、表示されている 4 つのフラグメントの左上が、最初または最後の行のいずれかをラスタライズすることによって生成されるかどうかです (両方であってはなりません)。

  1. 黄色の頂点から開始すると、最初の線はひし形を通過し、右に水平に通過するときに終了します。したがって、フラグメントは最初の行のラスタライズの結果として生成されます。

  2. 緑の頂点から開始すると、最初の行はひし形を通過せずにフラグメントを終了するため、ひし形を決して終了しません。ただし、最後の線はそれを垂直に通過し、緑色の頂点に戻るときに終了します。したがって、フラグメントは最後の行のラスタライズの結果として生成されます。

  3. 青色の頂点から開始すると、最初の線はひし形を通過し、右に水平に通過するときに外に出ます。したがって、フラグメントは最初の行のラスタライズの結果として生成されます。

  4. 赤い頂点から開始すると、最初の行はひし形を通過せずにフラグメントを終了するため、ひし形を終了することはありません。最後の線もひし形を通過しないため、赤の頂点に戻るときに出ません。したがって、フラグメントはどちらのラインのラスタライズの結果としても生成されません。

最初の線がひし形を出る必要があるため、ひし形の内側にある頂点によって自動的にフラグメントが生成されることに注意してください (もちろん、クワッドが実際にひし形を離れるのに十分な大きさである場合)。

于 2012-04-26T21:44:01.803 に答える
10

これはバグではなく、仕様に正確に従っています。線の最後のピクセルは、後続の線セグメントでオーバードローされるのを防ぐために描画されません。これにより、ブレンドで問題が発生する可能性があります。解決策: 最後の頂点を 2 回送信します。

コードの更新

// don't use glPolygonMode, it doesn't
// do what you think it does
glBegin(GL_LINE_STRIP);
    glVertex2f(a);
    glVertex2f(b);
    glVertex2f(c);
    glVertex2f(d);
    glVertex2f(a);
    glVertex2f(a); // resend last vertex another time, to close the loop
glEnd();

ところで: 頂点配列の使用方法を学ぶ必要があります。即時モード (glBegin、glEnd、glVertex 呼び出し) は、OpenGL-3.x コア以降から削除されました。

于 2012-04-25T22:10:31.367 に答える
4

@Troubadourは問題を完全に説明しました。ドライバーのバグではありません。GLは指定どおりに動作しています。これは、デバイス空間内のワールドスペースオブジェクトをサブピクセルで正確に表現するために設計されています。それがやっているのです。解決策は、1)アンチエイリアスであるため、デバイススペースはより忠実になり、2)変換されたすべての頂点がデバイスピクセルの中央に位置するワールド座標系を調整します。これはあなたが探している「一般的な」解決策です。

すべての場合において、2)入力ポイントを移動することで達成できます。各ポイントを十分にシフトして、デバイスピクセルの中央に変換します。

一部の(変更されていない)ポイントセットの場合、ビュー変換をわずかに変更することでそれを行うことができます。1/2ピクセルシフトは一例です。たとえば、ワールド空間がデバイス空間の整数スケールの変換であり、その後に整数による変換が続く場合に機能します。ここで、ワールド座標も整数です。ただし、他の多くの条件下では、+1/2は機能しません。

** 編集 **

注意:先ほど述べたように、均一なシフト(1/2またはその他)をビュー変換に組み込むことができます。頂点座標をいじる理由はありません。翻訳を追加するだけです。例:glTranslatef(0.5f, 0.5f, 0.0f);

于 2012-08-25T00:47:01.620 に答える
-1

0.5 をどこでも使われている奇数のマジック ナンバー 0.375 に変更してみてください。opengl、X11などで使用されていました。

前述のダイヤモンド ルールと、ピクセルの不必要なオーバードローを回避するためのグラフィックカードの描画方法のためです。

リンクをいくつか提供しますが、それらはたくさんあります。さらに情報が必要な場合は、キーワード opengl 0.375 ダイヤモンド ルールを検索してください。それは、アウトラインと塗りつぶしが opengl でアルゴリズム的にどのように扱われるかについてです。これは、2D スプライトなどのテクスチャのピクセル パーフェクト レンダリングにも必要です。

これを見てください。

何かを追加したい; したがって、コードで実装されたダイヤモンド ルールを実装することは、単に 1 つのライナーになります。このように 0.5 を 0.375 に変更します。そして、適切にレンダリングする必要があります。

glTranslatef(0.375, 0.375, 0.0);
于 2013-03-14T10:25:40.553 に答える