Modalità di fusione "normale" con problemi OpenGL


8

Ho avuto molti problemi a provare a far funzionare una funzione di fusione OpenGL come mi aspetterei con quello che mi aspetto (o da qualsiasi programma di editing di immagini sensato). Ad esempio, userò queste due immagini per fondere (un po 'difficile da vedere su sfondi bianchi in modo che i colori siano etichettati):

Immagini da miscelare

Immagini di prova

Questo è quello che mi aspetto che accada (e cosa succede in paint.net):

Risultato atteso

Paint.Net Image Test

Ovviamente la funzione di fusione predefinita di opengl la fa apparire così (molto sbagliata):

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

Test di miscelazione normale OpenGL

Dopo un sacco di test, questo è il più vicino che potrei arrivare a creare una "buona" funzione di fusione:

glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

Test di fusione personalizzato OpenGL

Guardando indietro al risultato atteso originale, noterete che alcuni dei colori sono leggermente più tenui di quanto dovrebbero essere (la parte centrale sinistra). In particolare, sono premoltiplicati per metà del loro valore di colore (a causa della .5 alfa) e non riesco a fare una funzione che non lo fa (senza causare strani problemi di fusione con la parte trasparente rossa appena visibile).

Qualcuno conosce una soluzione a questo problema? Uno che avevo era usare l'alfa premoltiplicato nelle fonti (mentre non voglio farlo perché richiede un lavoro extra per convertire tutti i colori che uso nel mio gioco in premoltiplicato o semplicemente scrivere alcune cose in ogni shader) e farlo in quel modo :

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (Nessuna premoltiplicazione)

Test di fusione personalizzato OpenGL

Ovviamente anche quello è sbagliato, ma questo è in realtà l'unico risultato corretto che ho ottenuto finora:

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (input premoltiplicati)

Test di fusione personalizzato OpenGL

L'unico problema è, come potrei sbarazzarmi della premoltiplicazione per visualizzarla sullo schermo? Probabilmente richiederebbe un ciclo di rendering aggiuntivo per ogni cosa che mescolo e questo sembra troppo complesso per questo problema, quindi sto ancora cercando una risposta (è interessante che non riesco a trovare nulla su questo, perché OpenGL è così ampiamente usato che Immagino che qualcun altro abbia riscontrato questo problema).

fonti:

Test delle funzioni di fusione online - http://www.andersriggelsen.dk/glblendfunc.php
Immagine livello inferiore - http://i.stack.imgur.com/XjLNW.png
Immagine livello superiore - http: //i.stack.imgur .com / 9CN6w.png


Tutti gli screenshot sono stati presi dal Visual glBlendFunc + glBlendEquation Tool online di Anders Riggelsen . In futuro, questo genere di cose sarebbe utile menzionare quando si chiede aiuto.
Trevor Powell,

@TrevorPowell Dang Sapevo di aver dimenticato di dire qualcosa (avevo davvero intenzione di metterlo in fondo). In ogni caso è proprio quello che stavo usando per testare facilmente le modalità di fusione, dovrebbe essere standard per qualsiasi altro tipo di cosa OpenGL (anche se posso vedere altre persone che vogliono usarlo).
Lemon Drop,

Risposte:


5

Nel tuo primo esempio ( glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)), gli stai dicendo di fondere i colori in base all'alfa dell'immagine che viene disegnata in alto (quella "Primo piano"). Quindi, quando si fonde il 50% tra il colore di primo piano (38,50,168)e il colore di sfondo (38,50,168)nell'angolo in basso a sinistra dell'immagine, non sorprende che tu abbia esattamente lo stesso colore (38,50,168). Perché quella fusione incrociata è esattamente ciò che hai detto a OpenGL di fare.

A giudicare dalla tua immagine "prevista", non vuoi fare una fusione incrociata tra i due colori: vuoi sovrapporre il colore di primo piano al colore di sfondo a piena forza, non una fusione incrociata tra di loro.

Per fare ciò, vuoi usare glBlendFuncSeparate (dato che stai trattando il colore dello sfondo in modo diverso dalla sua alfa) e specificare che durante l'operazione di fusione, il valore alfa dello sfondo dovrebbe essere trattato al 100%.

Lavorando

Per semplificare la visualizzazione, ecco i valori RGB finali in uscita: RGB

Ed ecco i valori di trasparenza finali in uscita. alfa

(Quell'area di trasparenza "100%" dovrebbe in realtà essere etichettata come trasparente al 99,7%, e l'area "50%" in basso a destra dovrebbe essere etichettata come trasparente al 49,7%, entrambe a causa del bit rosso sul lato destro della prima immagine. Inoltre, mi dispiace per elencare i numeri usando "trasparenza" anziché opacità; forse un po 'di confusione.)

In caso di problemi specifici, indicare l'area dell'immagine RGB o alfa che produce valori errati.


Anche il coefficiente alfa di origine non dovrebbe essere GL_ONE? Altrimenti appare l'equazione alfadest_alpha = src_alpha * src_alpha + 1 * dest_alpha
bcrist,

Bene, se lo guardi quel pezzo in mezzo a sinistra è ancora molto più scuro di quanto dovrebbe essere, anche capovolgere gli strati lo fa sembrare: i.imgur.com/rigBNz6.png (quel rosso appena visibile è lì per testare cose come che
Lemon Drop,

Lo stai mescolando al 50% contro (0,0,0). Di Naturalmente è più scuro rispetto a quando si fondono al 50% contro (255,255,255).
Trevor Powell

@TrevorPowell Non dovrebbe importare nulla se l'alfa è 0? Come le equazioni che sto cercando sono come: finalAlpha = srcAlpha + destAlpha * (1 - srcAlpha)efinalColor = ((srcColor * srcAlpha) + (destColor * destAlpha * (1 - srcAlpha))) / finalAlpha il Color * Alphabit nel calcolo del colore può essere fatto negli shader emettendo valori premoltiplicati, ma non c'è modo di dividere per Alpha finale per liberarsi della premoltiplicazione. (Tratto da qui )
Lemon Drop

0

Ho avuto lo stesso identico problema quando volevo renderizzare una serie di oggetti framebuffer sovrapposti come i livelli. Il problema è che le funzioni di fusione Open GL sono lineari e funzionano quando lo sfondo della destinazione è opaco. Ma l'equazione di fusione effettiva per la fusione di due livelli trasparenti non è un'equazione lineare e contiene una parte di divisione.

out_color = {src_color * src_alpha + dest_color * dest_alpha * (1-src_alpha)} / out_alpha

Non credo sia possibile farlo con le attuali implementazioni di OpengGL. Quindi, per ovviare a questo problema, ho dovuto utilizzare un pixel shader per calcolare manualmente l'output di ciascun pixel.


Sì, quello che ho fatto è stato semplicemente pre-moltiplicare l'alfa sulle trame piuttosto che fare delle soluzioni alternative, è facile farlo con alcune librerie (caricheranno solo le premature dei caricamenti)
Lemon Drop
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.