2010-02-17 2 views
13

Come si modifica lo spessore delle linee quando si disegnano elenchi di linee usando Direct3D?Diretto3D Spessore linea

This post indica che la larghezza della linea non è supportata e continua a fornire una soluzione alternativa. Altre opzioni?

Mentre siamo su questo argomento, gli shader consentono di disegnare linee con trattini?

risposta

14

È possibile utilizzare uno shader di geometria che prende come input un segmento della linea e genera un quadruplo (una striscia triangolare composta da due triangoli) in modo che la larghezza del quad sia costante nello spazio dello schermo e corrisponda al desiderio spessore della linea. Funziona perfettamente (per averlo implementato in un motore CAD 3D).

Se lo shader della geometria non è un'opzione, una soluzione potrebbe essere quella di utilizzare un vertex shader, ma richiederà alcuni rielaborazione del VB. Tieni presente che il VS deve quindi avere conoscenza del segmento di linea nel suo insieme in modo da finire per memorizzare p e p + 1 per ciascuno dei tuoi elementi VB, oltre al costo della duplicazione di indici/vertici (a seconda della topologia utilizzata e se rendi la tua linea come una primitiva indicizzata o meno).

Se le prestazioni non sono un problema, fare l'espansione sulla CPU è forse la strada da percorrere.

EDIT:

A proposito di modelli del precipitare: è possibile utilizzare un geometry shader troppo per emulare glLineStipple comportamento. Se si ha una topologia GL_LINES, cioè linee isolate, il modello si riavvia in corrispondenza di ogni nuovo segmento di linea. Quindi devi calcolare nello shader della geometria l'inizio orizzontale dello spazio dello schermo (o l'inizio verticale, a seconda dell'orientamento) del tuo segmento di linea e passare queste informazioni extra al pixel shader. Il pixel shader sarà quindi responsabile dell'eliminazione dei frammenti in base al fattore e del modello (le istruzioni DirectX 10/11 Integer e Bitwise lo rendono semplice).

Anche in questo caso funziona bene e puoi combinarlo con linee di larghezza emulate (con la prima tecnica sopra menzionata).

Ora se si dispone della topologia GL_LINE_STRIP, il motivo si riavvia ad ogni nuova primitiva (quindi per ogni nuova chiamata di disegno). La situazione diventa un po 'più complicata dal momento che è necessario avere la conoscenza del numero di pixel che sono stati renderizzati prima, e questo per ogni segmento di linea.

È possibile ottenere ciò con il rendering della striscia di linea in un VB temporaneo utilizzando la funzionalità di streaming DirectX 10 (ogni elemento di questo VB corrisponde alla lunghezza dello spazio dello schermo di ciascun segmento). Quindi devi fare un Sum Parallel Prefix (aka Scan) di questo VB (per accumulare ogni valore della lunghezza del segmento di linea).

Infine, si esegue il rendering della striscia di linea come per GL_LINES ma si utilizzano queste informazioni aggiuntive di Scan VB nel PS.

13

Lo spessore della linea non è supportato solo da Direct3D, ma non è supportato da alcuna GPU attualmente esistente. Non c'è GPU di cui sia a conoscenza che possa persino disegnare linee appropriate (tutte le linee false utilizzano i poligoni degenerati - cioè, il secondo e il terzo vertice si trovano nella stessa posizione, quindi il triangolo essenzialmente collassa su una singola riga).

Mentre è possibile impostare una larghezza di riga in OpenGL, il driver OpenGL crea quad estrusi (che non sono supportati da GPU corrente e sono emulati usando due triangoli per ciascun quad) per disegnare le "linee" sul schermo.

Quindi non c'è probabilmente modo di creare quad estrusi a tale scopo. Ci sono diversi modi per riuscirci, come spiegò Stringer Bell nella sua risposta.

Il modo più semplice che funziona per me è quello di creare un vertex buffer che contiene ogni vertice per due volte, con delle normali che "destra" o "sinistra", a seconda che essi sono il bordo destro o sinistro della linea. Quindi un vertex shader molto semplice può eseguire l'estrusione (cambiando la posizione del vertice di un multiplo del suo vettore normale). In questo modo è possibile modificare rapidamente la larghezza della linea, senza dover ricalcolare la geometria sulla CPU. Questo può essere utile se si desidera regolare la larghezza della linea in base alla dimensione o alla distanza dell'oggetto.

+0

Questa è una soluzione interessante. Hai ottenuto di ottenere gli stessi risultati rispetto a una chiamata glLineWidth (su base per pixel)? – Stringer

+0

Non l'ho controllato per pixel, ma per linee non testate, con antialiasing i risultati dovrebbero essere sufficientemente simili. Usare una texture (per simulare i modelli di stipple di OpenGL, per esempio) è abbastanza sicuro per farti entrare in un mondo di dolore, con interpolazione non lineare di coordinate di texture (che i quadratini NVidia gestiscono sorprendentemente male, anche rispetto alla parte Geforce per lo più identica). Lo shader deve eseguire un sacco di lavoro aggiuntivo per ottenere i texcoords corretti. – Pepor

+0

Puoi provarlo tu stesso, basta usare una sorta di "lunghezza della linea in pixel dello schermo" per le coordinate della trama e tracciare le linee con una trama che ha un modello di punteggiatura su di essa. Sarai sorpreso di quanto sia irregolare lo schema. Almeno lo ero. ;-) – Pepor

0

Per quanto riguarda il vostro modello trattino (punteggiatura) domanda, la cosa migliore è probabilmente per rendere la linea come un quad sottile e applicare una texture ad esso nel pixel shader, in cui la texture contiene il motivo di tratteggio. Sarà necessario impostare la modalità dell'indirizzo del campionatore per avvolgere, qualcosa del tipo:

SamplerState wrapTriLinear { 
    AddressU = WRAP; 
    AddressV = WRAP; 
}