2015-05-17 16 views
7

Normalmente sto trovando con OpenGL, quando sto cercando di disegnare qualcosa su una texture e poi su un'altra superficie, usando glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA), invariabilmente finisco con un alone colorato (di solito una banda di colore scuro) in quelle che sono le parti semitrasparenti della mia immagine sorgente vicino ai suoi bordi. Ciò è evidentemente causato da problemi nel rendere ciò che è essenzialmente un alfa premoltiplicato causato da quello stile di fusione. Per le scene 3D, di solito uso un algoritmo di pittori e per il rendering di contenuti 2D, mi piace disegnare prima gli oggetti sul retro e sovrapporre oggetti aggiuntivi sopra di essi. Vale la pena notare che mentre faccio questo disegno 2D, non posso generalmente fare affidamento su funzionalità come az buffer come posso in 3d, motivo per cui è più un problema per il rendering di cose simili a quello che sarebbe per i grafici di scene 3dOscurità scura attorno alle parti trasparenti parzialmente trasparenti delle immagini in opengl

Penso che valga la pena notare che lo stile di fusione di cui sopra è in realtà perfetto quando il buffer di destinazione sembra già completamente opaco, ma se la destinazione è trasparente, allora davvero ciò che è effettivamente necessario in questo caso è glBlendFunc(GL_SRC,GL_ZERO) .. i pixel completamente bianchi che sono parzialmente trasparenti nella sorgente, per esempio, dovrebbero rimanere altrettanto saturi del colore e non essere "miscelati" con uno sfondo che in realtà non esiste ancora, perché l'uso di glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) renderebbe effettivamente un oggetto parzialmente trasparente e pixel completamente bianchi come un mix tra il primo piano e lo sfondo, che è ciò che voglio, ma non nella misura in cui l'informazione alfa viene persa, né nella misura in cui i colori sono effettivamente cambiati.

Mi viene, quindi, il tipo di funzione di blending che probabilmente sarebbe ideale sarebbe uno che fonde effettivamente tra quanto altrimenti causato da glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) e ciò è altrimenti causata da glBlendFunc(GL_SRC,GL_ZERO) seconda del valore di DST_ALPHA stessa.

Così, idealmente:

Cr = Cs * (1 - Ad) + (Cs * As + Cd * (1 - As)) * Ad 
Ar = As * (1 - Ad) + Ad * Ad 

questo modo, se la destinazione è già opaca, normale alfa moltiplicazione miscele opportunamente, mentre se la destinazione è trasparente o parzialmente trasparente, userà più della fonte il colore reale dell'immagine invece di usare una forma alpha-premoltiplicata di detti colori.

Tuttavia, non sembra esserci un modo apparente per descrivere un tale meccanismo di fusione per OpenGL. Sembra che tali questioni non dovrebbero essere uniche per la mia situazione, e inoltre mi sembra strano che non ci sia alcun modo per ottenere questo ... anche all'interno di una pipeline programmabile.

L'unica soluzione che ho trovato finora è di invertire l'ordine di disegno ogni volta che disegno a una trama che in seguito disegnerò altrove, e utilizzare glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_SRC_ALPHA, GL_DST_ALPHA).

Creare un caso speciale per l'ordine di disegno nei casi in cui sto disegnando qualcosa su una trama che verrà successivamente renderizzata normalmente è un compromesso, ma non mi piace perché non ha riusabilità, a meno che il codice che sta facendo il disegno essere sempre consapevoli di quale sia il tipo di destinazione in modo che possa invertire il suo solito ordine di disegno, che posso complicarlo inutilmente.

Infine, anche se l'inversione dell'intero ordine di disegno della scena non è necessariamente del tutto impossibile, richiede che venga determinato un elenco completo di oggetti che verranno visualizzati in ogni fotogramma di grafica prima ancora che venga disegnato il primo oggetto . Il problema principale che ho con questo è che sebbene questo possa essere sostenibile durante il rendering di scene 3D, quando si disegnano cose come 2d gui, la pura varietà di cose che vengono disegnate e il modo in cui sono disegnate è semplicemente così vasta che non c'è modo di generalizzarli in un unico elenco di oggetti che può sempre essere attraversato in ordine inverso in seguito.Mi sembra che richiederebbe una visione così radicalmente diversa su come costruire le scene 2d in questo ordine "all'indietro" da quello a cui sono abituato, che non sono attualmente in grado di comprendere nemmeno una soluzione manutenibile.

Quindi ... c'è un altro modo per farlo? Mi sto perdendo qualcosa? O devo imparare un modo completamente diverso di costruire immagini 2D? Non posso essere l'unica persona ad avere questo problema, ma devo ancora trovare una soluzione buona e pulita.

Edit:

Se esiste qualsiasi estensione comunemente disponibili per OpenGL, da NVIDIA o in altro modo, che permette un metodo di fusione che può fare questo:

Cr = Cs * (1 - Ad) + (Cs * As + Cd * (1 - As)) * Ad 
Ar = As * (1 - Ad) + Ad * Ad 

(Dove Cs e Cd sono i colori di origine e di destinazione, As e Ad sono i valori alfa di origine e di destinazione e Cr e Ar sono i colori dei risultati e i valori alpha), mi piacerebbe davvero sapere quale sia l'estensione chiamata e come utilizzarla ... finché può essere prodotto su hardware di consumo.

risposta

1

ho scritto varie cose compositing sovrapposizioni 2D traslucido sul contenuto 3D traslucido e mai sentito OpenGL mancava qualcosa di fondamentale nel campo della glBlendFunc/glBlendFuncSeparate (beh, almeno non fino a quando si inizia a preoccuparsi di compositing gamma corretta della sRGB contenuto e framebuffers comunque).

Sono principalmente sospetto per l'utilizzo di glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) apparentemente con alfa premoltiplicato (scusate, mentre la tua domanda è lunga, non sono in realtà trovando che chiaro, alcune immagini di semplici casi di test potrebbe aiutare). Per il compositing di contenuti alfa premoltiplicati, mi aspetto di vedere uno GL_ONE come uno degli argomenti glBlendFunc (a seconda che si stiano facendo operazioni sovra/sotto).

C'è un ottimo mazzo di diapositive su miscelazione/compositing (compreso l'uso corretto di colori premoltipunti rispetto a "diritti") here (diapositive 20-35 il materiale pertinente).

(Nonostante la mia affermazione che ciò che è già disponibile è generalmente abbastanza buono ... vale anche la pena ricordare che NVidia ha aggiunto alcuni new features in questo area di recente).

+0

Ho menzionato 'glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)' perché in realtà funziona perfettamente per la fusione quando il pixel nel buffer di destinazione è già opaco. Mentre ho notato che 'glBlendFunc (GL_SRC, GL_ZERO)' funziona perfettamente per la fusione quando il pixel a destinazione è ancora trasparente, non sembra esserci alcun modo per passare da uno all'altro a seconda di quale destinazione in realtà lo è. Idealmente, ciò che sarebbe necessario IMO è una funzione di fusione che è una somma ponderata di questi due, in base alla trasparenza del buffer di destinazione. – markt1964

+0

Il problema che ho con l'uso di glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) è che i pixel parzialmente trasparenti non si sovrappongono correttamente su sfondi opachi più scuri rispetto al pixel sorgente .... ad esempio, un pixel sorgente rosso brillante con il 50% di trasparenza su un pixel nero opaco diventerebbe un opaco rosso brillante invece di un pixel rosso opaco più scuro, che è quello che dovrebbe essere quando lascia passare il 50% del nero. – markt1964

+0

La tua comprensione di qualcosa (premoltiplied alfa? Succede a tutti) è sbagliata da qualche parte; se hai semitrasparente rosso vivo (0.5, ..., 0.5) (R ... A, con alfa premoltiplicato), allora compositing che il nero opaco (0.0, ..., 1.0) dovrebbe darti (0.5 ,. .., 1.0) opaco rosso più scuro ... che è ciò che GL_ONE, GL_ONE_MINUS_SRC_ALPHA) ti dà. – timday