Perché risultati diversi quando si cambia l'ordine di input in GL_LINES?


8

Codice:

#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;
}

Descrizione del problema:

  • Il codice sopra renderà bianchi i pixel dell'intera riga inferiore dell'area client della finestra.
  • Se cambio l'ordine dei comandi, da glVertex3d(0.5, 0.999, 0.0f);glVertex3d(499.501, 0.999, 0.0f);a glVertex3d(499.501, 0.999, 0.0f);glVertex3d(0.5, 0.999, 0.0f);, non verrà disegnato solo il pixel in basso a sinistra.

Le mie comprensioni:

  • I due vertici verranno infine trasformati in coordinate centrali pixel 2D che sono (0,0, 0,499) e (499,001, 0,499).
  • L'algoritmo di disegno al tratto accetta solo punti interi al centro dei pixel come input.
  • Quindi i due vertici useranno int (x + 0,5) e saranno (0, 0) e (499, 0). Ciò è conforme al primo risultato ma contraddice al risultato quando l'ordine di input è cambiato. Perché?

Risposte:


10

La differenza in cui i pixel sono coperti in base all'ordine dei vertici è correlata alle regole di rasterizzazione . Sono le regole che l'hardware della GPU usa per determinare esattamente quali pixel sono coperti da una primitiva.

Le regole di rasterizzazione sono un po 'sottili. Uno dei loro obiettivi è quello di garantire che ogni volta che disegni più primitivi collegati a tenuta stagna, la rasterizzazione non produca mai crepe tra loro, né i pixel siano coperti due volte (è importante per la fusione). Per raggiungere questo obiettivo, le regole hanno alcuni casi molto specifici. Letteralmente ... sono casi che hanno a che fare con bordi e angoli primitivi. :)

Nel caso delle linee, funziona come segue. C'è una regione a forma di diamante attorno a ciascun centro di pixel, come mostrato in questo frammento del diagramma dall'articolo MSDN collegato sopra.

regola del diamante per la rasterizzazione delle linee

La regola è che un pixel è coperto se la linea esce dal diamante, quando si traccia dall'inizio alla fine della linea. Nota che un pixel non viene coperto se la linea entra, ma non esce, il diamante. Ciò garantisce che se si hanno due segmenti di linea collegati da un capo all'altro, il pixel nel loro endpoint condiviso appartiene solo a uno dei segmenti e quindi non viene rasterizzato due volte.

Nel diagramma sopra puoi anche vedere come cambiare l'ordine dei vertici può influenzare quali pixel sono coperti (cosa che non accade con triangoli, BTW). Il diagramma mostra due segmenti di linea identici ad eccezione dello scambio dell'ordine degli endpoint e puoi vedere che fa la differenza quale pixel viene coperto.

Il segmento di linea è in qualche modo analogo a questo. L'estremità sinistra, in (0,5, 0,999) è all'interno del diamante del (0, 0) pixel, quindi viene coperta quando è il primo vertice (la linea inizia all'interno del diamante, quindi lo esce) e non quando è il secondo vertice (la linea entra nel diamante e termina al suo interno, quindi non esce mai). In realtà, i vertici sono fissati al punto fisso con 8 bit subpixel prima della rasterizzazione, quindi questo finisce arrotondato a (0,5, 1,0), che è esattamente sull'angolo superiore del diamante. A seconda delle regole di rasterizzazione, questo potrebbe o non potrebbe essere considerato all'interno del diamante; sembra che la tua GPU sia considerata all'interno, ma questo può variare tra le implementazioni, poiché le specifiche GL non definiscono completamente le regole.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.