Bisakah (dan bagaimana) shaders mewarnai piksel layar melebihi yang ditempati oleh jaring berbayang?

8

Saya memiliki beberapa pengalaman pemrograman geometri dan komputasi shader - tetapi tidak pernah bertualang sendiri untuk benar-benar bermain dengan fragmen shader. Saat ini, saya mencoba untuk lebih memahami bagaimana mereka bekerja dan potensi mereka. Salah satu hal yang saya baca di banyak tempat adalah bahwa sebuah fragmen (yaitu piksel layar) tidak dapat melampaui dirinya dalam fragmen shader. Yang berarti, fragmen yang diberikan diulangi hanya dapat mempengaruhi dirinya sendiri.

Karena itu, dan demi belajar, saya ingin tahu apakah yang berikut ini mungkin (dan jika ya, bagaimana, secara umum, dapat dicapai). Misalkan kita memiliki, demi kesederhanaan, sebuah mesh-titik yang hanya terdiri dari dua simpul (terletak di ruang Dunia 3D). Bisakah kita memprogram shader dengan cara sedemikian rupa sehingga masing-masing dari dua simpul ini akan dilukis di layar pada posisi WorldToViewport yang tepat, tetapi juga bahwa lingkaran di sekitar masing-masing dari jari-jari = R juga dicat dalam piksel sekitarnya bahkan jika mereka memperpanjang di luar jaring asli tempat shader terpasang? Seperti pada gambar di bawah ini (di mana kotak merah di tengah lingkaran mewakili simpul yang dilukis di layar):

masukkan deskripsi gambar di sini

Jika itu mungkin, dapatkah shader juga diprogram sedemikian rupa sehingga lingkaran yang melampaui titik mempengaruhi warna (RGBA) satu sama lain? Seperti pada gambar di bawah ini:

masukkan deskripsi gambar di sini

Seperti yang saya katakan, jika ini adalah hal yang mungkin, saya akan senang mendengar sedikit tentang bagaimana mencapai hal seperti itu - baik secara konseptual atau praktis. Apakah itu dilakukan dalam fragmen shader, atau harus dihitung sebelumnya di vertex atau geometri shader? Bagaimana cara menghitung dan lulus "fragmen tambahan" yang melampaui fragmen yang ditempati oleh badan mesh?

AndrewSteer
sumber
Shader geometri dapat menambahkan lebih banyak primitif daripada yang ditemukan di mesh asli. Apakah ini melakukannya untuk Anda?
Andreas

Jawaban:

6

Ketika Anda menggunakan linewidth atau antialiasing garis atau pointwidth atau pointsprite, OpenGL membuat untuk Anda sebuah persegi kecil kecil alih-alih garis atau titik, dengan koordinat tekstur. Saat ini Anda bahkan dapat memprogram ini sendiri menggunakan geometri shader atau bahkan tesselator.

Pendekatan yang sama sekali berbeda adalah dengan menggunakan penangguhan yang ditunda, menggunakan satu lintasan geometris hanya untuk menyimpan informasi dalam buffer RGBAZ, kemudian lintasan kedua daripada yang Anda jalankan pada semua piksel layar untuk melakukan beberapa proses. (untuk bertindak pada semua piksel, cukup gambar satu persegi panjang layar penuh). Saat ini Anda bahkan dapat melakukan pass pertama sebagai satu atau beberapa "render to tekstur", lalu MIPmap tekstur ini, sehingga pass terakhir dapat dengan mudah mengakses nilai-nilai lokal yang kurang.

Fabrice NEYRET
sumber
Terima kasih! Saya telah melakukan apa yang Anda katakan di awal, menggunakan geometri shader untuk membuat geometri di sekitar titik dan memungkinkan untuk menggambar piksel di sekitar titik. Ini bekerja, tentu saja, tetapi ini merupakan solusi yang lebih rumit. Saya sangat tertarik pada bagian terakhir dari apa yang Anda katakan: jika saya mengerti Anda dengan benar, apa yang Anda sebutkan adalah seseorang dapat membuat seluruh adegan dan kemudian menggunakan layar shader yang ditujukan pada bidang yang diminati dan kemudian melakukan oper diberikan bingkai untuk bekerja pada berapa banyak piksel yang diinginkan di sekitar titik di tengah?
AndrewSteer
Anda bisa membuat pass pertama dalam tekstur. Kemudian pada lintasan kedua pada layar penuh, dalam setiap piksel Anda dapat memeriksa konten tekstur dalam disk di sekitar piksel dan melakukan apa yang Anda inginkan (mis. Warna sesuai dengan piksel terisi terdekat, atau cat putih hanya jika jaraknya di bawah ambang) . Tentu saja untuk hanya menggambar disk, ini masih jauh dari cara yang paling efisien ;-)
Fabrice NEYRET
Tentu, saya hanya memberikan contoh sederhana yang bisa saya pikirkan. Tapi ya, saya pikir apa yang Anda katakan sejalan dengan apa yang saya pikirkan, yaitu rendering ke tekstur dalam satu pass dan kemudian kita memiliki informasi untuk, di pass lain, mengubah piksel dalam kaitannya dengan apa yang ada di piksel sekitarnya . Terimakasih banyak.
AndrewSteer
3

Salah satu cara yang baik untuk mengatur lingkaran (atau bentuk lain) yang akan ditarik untuk setiap simpul dalam mesh adalah dengan menggunakan geometri instancing . Ini adalah fitur GPU yang memungkinkan beberapa instance (salinan) dari sebuah mesh dapat ditarik sekaligus, dengan simpul / indeks dari mesh yang diberikan oleh satu set buffer, dan buffer vertex lain yang dapat memberikan data tambahan per-instance. Vertex shader dapat digunakan untuk menggabungkan data dari kedua buffer dengan cara apa pun yang Anda pilih.

Untuk menjadi konkret, dalam kasus Anda, Anda dapat membuat mesh yang mewakili lingkaran dari jari-jari yang diinginkan, dengan simpulnya ditentukan secara langsung dalam koordinat ruang layar dan dipusatkan pada titik asal. Kemudian Anda akan menggunakan instancing untuk membuat GPU membuat salinan baru dari lingkaran lingkaran untuk setiap simpul dari titik-mesh asli Anda. Di vertex shader, Anda akan menghitung posisi layar-ruang dari titik (menggunakan transformasi proyeksi-pandangan-dunia seperti biasa), kemudian menerjemahkan lingkaran lingkaran untuk dipusatkan pada posisi itu.

Adapun bagian kedua dari pertanyaan Anda, tentang bagaimana lingkaran memengaruhi warna masing-masing: tergantung pada apa yang ingin Anda lakukan, khususnya. Blending perangkat keras dapat digunakan untuk menangani kasus-kasus sederhana, seperti menambah atau mengalikan warna, atau alpha-blending. Jika Anda menginginkan sesuatu yang lebih rumit dari itu, maka dimungkinkan untuk melakukannya dengan algoritma multi-pass, atau (pada GPU terbaru) yang dapat dipadukan.

Nathan Reed
sumber