Mode Blend "Normal" dengan Masalah OpenGL

8

Saya telah mengalami banyak kesulitan untuk mencoba fungsi campuran OpenGL agar berfungsi seperti yang saya harapkan dengan apa yang saya harapkan (atau dari program pengeditan gambar yang masuk akal). Sebagai contoh, saya akan menggunakan dua gambar ini untuk berbaur (agak sulit dilihat pada latar belakang putih sehingga warna diberi label):

Gambar yang akan dicampur

Gambar Uji

Inilah yang saya harapkan terjadi (dan apa yang terjadi di paint.net):

Hasil yang diharapkan

Tes Gambar Paint.Net

Jelas fungsi campuran default opengl membuatnya terlihat seperti ini (sangat salah):

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

OpenGL Normal Blending Test

Setelah banyak pengujian, ini adalah yang terdekat yang bisa saya dapatkan untuk membuat fungsi campuran "baik":

glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

OpenGL Custom Blend Test

Melihat kembali pada hasil yang diharapkan, Anda akan melihat bahwa beberapa warna sedikit lebih redup daripada seharusnya (bagian kiri tengah). Secara khusus, mereka ditakdirkan untuk setengah nilai warna mereka (karena alpha .5), dan saya tidak bisa membuat fungsi yang tidak melakukan ini (tanpa menyebabkan masalah pencampuran aneh dengan bagian transparan merah yang nyaris tidak terlihat).

Adakah yang tahu solusi untuk masalah ini? Salah satu yang saya miliki adalah menggunakan alpha yang di-pre-multiplikasi di sumber (sementara saya tidak ingin melakukan ini karena membutuhkan kerja ekstra untuk mengubah setiap warna yang saya gunakan dalam game saya untuk di-pre-multiplikasi atau hanya menulis beberapa hal di setiap shader) dan melakukannya seperti itu :

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (Tanpa premultiplikasi)

OpenGL Custom Blend Test

Jelas itu salah juga, tetapi ini sebenarnya satu-satunya hasil yang benar yang saya dapatkan sejauh ini:

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (input yang diultipultasikan)

OpenGL Custom Blend Test

Satu-satunya masalah adalah, bagaimana saya menyingkirkan premultiplikasi untuk menampilkannya di layar? Mungkin akan membutuhkan siklus render tambahan untuk setiap hal yang saya gabungkan dan itu tampaknya terlalu rumit untuk masalah ini, jadi saya masih mencari jawaban (yang menarik sehingga saya tidak dapat menemukan apa pun tentang ini, karena OpenGL sangat banyak digunakan sehingga Saya akan membayangkan orang lain mengalami masalah ini).

Sumber:

Pengujian fungsi campuran online - http://www.andersriggelsen.dk/glblendfunc.php
Gambar Lapisan Bawah - http://i.stack.imgur.com/XjLNW.png
Gambar Lapisan Atas - http: //i.stack.imgur .com / 9CN6w.png

Lemon Drop
sumber
Semua tangkapan layar telah diambil dari Visual glBlendFunc + glBlendEquation Tool online Anders Riggelsen . Di masa depan, hal semacam itu akan berguna untuk disebutkan ketika meminta bantuan.
Trevor Powell
@ TrevorPowell Dang Saya tahu saya lupa mengatakan sesuatu (saya benar-benar berencana untuk meletakkannya di bagian bawah). Apa pun yang saya gunakan untuk dengan mudah menguji mode campuran, itu harus menjadi standar untuk segala hal OpenGL lainnya (meskipun saya bisa melihat orang lain ingin menggunakannya).
Lemon Drop

Jawaban:

5

Dalam contoh pertama Anda ( glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)), Anda mengatakannya untuk mencampur warna berdasarkan alpha dari gambar yang digambar di atas ("Foreground"). Jadi ketika Anda memadukan 50% antara warna latar depan (38,50,168)dan warna latar belakang (38,50,168)di sudut kiri bawah gambar, Anda secara mengejutkan mendapatkan warna yang persis sama (38,50,168). Karena perpaduan silang itulah yang Anda perintahkan kepada OpenGL untuk dilakukan.

Menilai dari gambar "yang diharapkan" Anda, Anda tidak ingin melakukan perpaduan antara dua warna - Anda ingin overlay warna latar depan di atas warna latar belakang kekuatan penuh, bukan perpaduan lintas di antara keduanya.

Untuk melakukan itu, Anda ingin menggunakan glBlendFuncSeparate (karena Anda memperlakukan warna latar belakang berbeda dari alpha-nya), dan menentukan bahwa selama operasi blending, nilai alfa latar belakang harus diperlakukan sebagai 100%.

kerja

Untuk membuatnya lebih mudah dilihat, inilah nilai-nilai RGB akhir yang diproduksi: RGB

Dan inilah nilai transparansi akhir yang dihasilkan. alfa

(Area transparansi '100%' itu seharusnya benar-benar dilabeli sebagai 99,7% transparan, dan area '50% 'kanan bawah harus dilabeli sebagai 49,7% transparan, keduanya karena bit berwarna merah di sisi kanan gambar pertama. Juga, maaf untuk daftar nomor menggunakan "transparansi" daripada opacity; mungkin sedikit membingungkan.)

Jika ada masalah khusus, harap tunjukkan area RGB atau gambar alfa yang menghasilkan nilai yang salah.

Trevor Powell
sumber
Bukankah seharusnya koefisien alpha sumber GL_ONEjuga? Kalau tidak, persamaan alfa sepertidest_alpha = src_alpha * src_alpha + 1 * dest_alpha
bcrist
Nah jika Anda melihatnya bagian kiri tengah masih jauh lebih gelap dari yang seharusnya, juga membalikkan lapisan membuatnya tampak seperti: i.imgur.com/rigBNz6.png (yang hampir tidak terlihat merah ada untuk menguji hal-hal seperti itu
Lemon Drop
Anda mencampurnya dengan 50% melawan (0,0,0). Tentu saja lebih gelap daripada saat Anda mencampurnya dengan 50% (255,255,255).
Trevor Powell
@ TrevorPowell Bukankah itu tidak masalah sama sekali jika alfa adalah 0? Seperti persamaan saya akan untuk seperti: finalAlpha = srcAlpha + destAlpha * (1 - srcAlpha)dan finalColor = ((srcColor * srcAlpha) + (destColor * destAlpha * (1 - srcAlpha))) / finalAlphaThe Color * Alphabit dalam perhitungan warna bisa dilakukan di shader oleh keluaran nilai premultiplied, tapi theres ada cara untuk membagi oleh finalAlpha untuk menyingkirkan premultiplication tersebut. (Diambil dari sini )
Lemon Drop
0

Saya memiliki masalah yang sama persis ketika saya ingin membuat satu set objek framebuffer yang tumpang tindih seperti lapisan. Masalahnya adalah fungsi Open GL blending linier dan berfungsi ketika latar belakang tujuan buram. Tetapi persamaan pencampuran aktual untuk pencampuran dua lapisan transparan bukanlah persamaan linier dan mengandung bagian pembagian.

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

Saya rasa tidak mungkin melakukan ini dengan implementasi OpengGL saat ini. Jadi sebagai pekerjaan di sekitar saya harus menggunakan shader piksel untuk secara manual menghitung output setiap piksel.

Supun Gothama
sumber
Ya apa yang saya lakukan adalah hanya melipatgandakan alpha pada tekstur daripada melakukan beberapa solusi, mudah untuk melakukannya dengan beberapa perpustakaan (mereka hanya akan tekstur premultiply pada beban)
Lemon Drop