GL_LINESで入力順序を変更すると結果が異なるのはなぜですか?


8

コード:

#include <math.h>
#include <GL/glut.h>
#pragma comment(lib, "opengl32")
#include <gl/gl.h>
#include <gl/glu.h>

//Initialize OpenGL 
void init(void) {
    glClearColor(0, 0, 0, 0);

    glViewport(0, 0, 500, 500);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(0, 500, 0, 500, 1, -1);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
} 

void drawLines(void) {
    glClear(GL_COLOR_BUFFER_BIT);  
    glColor3f(1.0,1.0,1.0); 

    glBegin(GL_LINES);

    glVertex3d(0.5,         0.999,  0.0f);
    glVertex3d(499.501,     0.999,  0.0f);

    glEnd();

    glFlush();
} 


int _tmain(int argc, _TCHAR* argv[])
{
    glutInit(&argc, argv);  
    glutInitWindowPosition(10,10); 
    glutInitWindowSize(500,500); 
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 

    glutCreateWindow("Example"); 
    init(); 
    glutDisplayFunc(drawLines); 
    glutMainLoop();

    return 0;
}

問題の説明:

  • 上記のコードは、ウィンドウクライアント領域の一番下の行のピクセル全体を白にします。
  • 私は、コマンドの順序を入れ替える場合は、からglVertex3d(0.5, 0.999, 0.0f);glVertex3d(499.501, 0.999, 0.0f);glVertex3d(499.501, 0.999, 0.0f);glVertex3d(0.5, 0.999, 0.0f);、そして唯一の左下のピクセルは描画しません。

私の理解:

  • 2つの頂点は、最終的には(0.0、0.499)と(499.001、0.499)の2Dピクセル中心座標に変換されます。
  • 線描画アルゴリズムは、ピクセル中心の整数点のみを入力として受け入れます。
  • したがって、2つの頂点はint(x + 0.5)を使用し、(0、0)と(499、0)になります。これは最初の結果に適合しますが、入力順序が変更されたときの結果とは矛盾します。どうして?

回答:


10

頂点の順序に応じてカバーされるピクセルの違いは、ラスタライズルールに関連しています。これらは、GPUハードウェアがプリミティブでカバーされるピクセルを正確に決定するために使用するルールです。

ラスタライズルールは少し微妙です。彼らの目標の1つは、水密に接続された複数のプリミティブを描画するときは常に、ラスター化によってそれらの間に亀裂が発生したり、ピクセルが2回カバーされたりしないことを保証することです(これは、ブレンドにとって重要です)。これを実現するために、ルールには非常に特殊なエッジケースとコーナーケースがあります。文字通り...それらはプリミティブのエッジとコーナーに関係するケースです。:)

ラインの場合、次のように動作します。上記のリンク先のMSDN記事の図のこのスニペットに示すように、各ピクセルの中心の周りに菱形の領域があります。

ラインラスタライズのダイヤモンドルール

ルールは、ラインの始点から終点までトレースするときに、ラインダイヤモンドを出る場合、ピクセルがカバーされることです。線がダイヤモンドに入るが出ない場合、ピクセルはカバーされないことに注意してください。これにより、2つのラインセグメントが端と端で接続されている場合、それらの共有端点のピクセルはセグメントの1つにのみ属し、したがって2度ラスタ化されません。

上の図では、頂点の順序を変更すると、どのピクセルがカバーされるかに影響を与えることがわかります(これは、三角形では起こりません)。この図は、エンドポイントの順序を入れ替える以外は同一の2つのラインセグメントを示しており、どのピクセルがカバーされるかが異なることがわかります。

あなたのラインセグメントはこれにいくぶん類似しています。(0.5、0.999)の左端は(0、0)ピクセルのひし形の内側にあるため、2番目の頂点ではなく、最初の頂点(線はひし形の内側で始まり、そこから出る)のときに覆われます。頂点(線はひし形に入り、ひし形の内側で終わるため、出ることはありません)。実際、頂点はラスタライズの前に8サブピクセルビットの固定小数点にスナップされるため、これは最終的に(0.5、1.0)に丸められます。これは、ひし形の上隅に正確にあります。ラスタライズルールに応じて、これはダイヤモンド内で考慮される場合と考慮されない場合があります。GPUでは内部と見なされているように見えますが、GL仕様ではルールが完全に規定されていないため、これは実装によって異なる場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.