Bagaimana saya bisa menggambar garis besar di sekitar model 3D? Saya merujuk pada sesuatu seperti efek dalam game Pokemon baru-baru ini, yang tampaknya memiliki garis piksel tunggal di sekitarnya:
3d
shaders
graphics
graphics-programming
portal mistik
sumber
sumber
Jawaban:
Saya tidak berpikir ada jawaban lain di sini yang akan mencapai efek di Pokemon X / Y. Saya tidak tahu persis bagaimana itu dilakukan, tetapi saya menemukan cara yang sepertinya cukup banyak apa yang mereka lakukan dalam permainan.
Dalam Pokémon X / Y, garis besar digambar di sekitar tepi siluet dan di tepi non-siluet lainnya (seperti di mana telinga Raichu bertemu kepalanya di screenshot berikut).
Melihat jaring Raichu di Blender, Anda dapat melihat telinga (disorot dengan warna oranye di atas) hanyalah objek terpisah dan terputus yang memotong kepala, menciptakan perubahan mendadak pada permukaan normal.
Berdasarkan hal itu, saya mencoba membuat garis besar berdasarkan normals, yang memerlukan rendering dalam dua lintasan:
Pass pertama : Render model (bertekstur dan cel-shaded) tanpa garis besar, dan render normals ruang kamera ke target render kedua.
Lulus kedua : Lakukan filter deteksi tepi layar penuh di atas normals dari lintasan pertama.
Dua gambar pertama di bawah ini menunjukkan output dari pass pertama. Yang ketiga adalah garis besar dengan sendirinya, dan yang terakhir adalah hasil gabungan akhir.
Inilah shader fragmen OpenGL yang saya gunakan untuk deteksi tepi pada lintasan kedua. Itu yang terbaik yang bisa saya lakukan, tetapi mungkin ada cara yang lebih baik. Ini mungkin tidak dioptimalkan dengan sangat baik juga.
Dan sebelum memberikan pass pertama, saya menghapus target render normals ke vektor yang menghadap jauh dari kamera:
Saya membaca di suatu tempat (saya akan memberikan tautan di komentar) bahwa Nintendo 3DS menggunakan pipeline fungsi-tetap alih-alih shader, jadi saya kira ini tidak persis seperti yang dilakukan dalam permainan, tetapi untuk saat ini saya ' Saya yakin metode saya cukup dekat.
sumber
Efek ini sangat umum dalam gim yang menggunakan efek cel shading, tetapi sebenarnya adalah sesuatu yang dapat diterapkan secara terpisah dari gaya cel shading.
Apa yang Anda gambarkan disebut "fitur edge rendering," dan dalam proses umum menyoroti berbagai kontur dan garis besar model. Ada banyak teknik yang tersedia dan banyak makalah tentang masalah ini.
Teknik sederhana adalah membuat hanya tepi siluet, garis besar. Ini dapat dilakukan sesederhana merender model asli dengan tulisan stensil, dan kemudian merendernya kembali dalam mode bingkai rangka tebal, hanya jika tidak ada nilai stensil. Lihat disini untuk contoh implementasi.
Itu tidak akan menyoroti kontur interior dan tepi lipatan, meskipun (seperti yang ditunjukkan pada gambar Anda). Secara umum, untuk melakukan itu secara efektif, Anda perlu mengekstraksi informasi tentang tepi mesh (berdasarkan diskontinuitas pada normals wajah di kedua sisi tepi, dan membangun struktur data yang mewakili setiap tepi.
Anda kemudian dapat menulis shader untuk mengusir atau membuat tepi tersebut sebagai geometri biasa melebihi model dasar Anda (atau bersamaan dengan itu). Posisi tepi, dan normals dari permukaan yang berdekatan relatif terhadap vektor tampilan, digunakan untuk menentukan apakah tepi tertentu dapat digambar.
Anda dapat menemukan diskusi lebih lanjut, detail, dan makalah dengan berbagai contoh di internet. Sebagai contoh:
sumber
dz/dx
dan / ataudz/dy
Cara paling sederhana untuk melakukan ini, umum pada perangkat keras yang lebih lama sebelum pixel / fragmen shaders, dan masih digunakan pada ponsel, adalah untuk menduplikasi model, membalikkan urutan belitan vertex sehingga model menampilkan luar dalam (atau jika Anda mau, Anda dapat lakukan ini di alat pembuatan aset 3D Anda, katakanlah Blender, dengan membalikkan permukaan normal - hal yang sama), kemudian rentangkan seluruh duplikat sedikit di sekitar pusatnya, dan akhirnya warna / tekstur duplikat ini sepenuhnya hitam. Ini menghasilkan garis besar di sekitar model asli Anda, jika model sederhana seperti kubus. Untuk model yang lebih kompleks dengan bentuk cekung (seperti pada gambar di bawah), perlu untuk secara manual mengubah model duplikat menjadi "lebih gemuk" daripada rekan aslinya, seperti Minkowski Sumdalam 3D. Anda bisa mulai dengan mendorong setiap simpul sedikit di sepanjang normalnya untuk membentuk garis kerangka, seperti yang dilakukan oleh Blender's Shrink / Fatten transform.
Pendekatan ruang layar / piksel shader cenderung lebih lambat dan lebih sulit untuk diterapkan dengan baik , tetapi OTOH tidak menggandakan jumlah simpul di dunia Anda. Jadi, jika Anda melakukan pekerjaan poli tinggi, sebaiknya pilih pendekatan itu. Mengingat konsol modern dan kapasitas desktop untuk memproses geometri, saya tidak khawatir tentang faktor 2 sama sekali . Gaya kartun = poli rendah pasti, sehingga menduplikasi geometri termudah.
Anda dapat menguji efeknya sendiri dalam mis. Blender tanpa menyentuh kode apa pun. Garis besar harus terlihat seperti gambar di bawah ini, perhatikan bagaimana beberapa internal, misalnya di bawah lengan. Lebih detail di sini .
.
sumber
Untuk model yang halus (sangat penting), efek ini cukup sederhana. Dalam shader fragmen / piksel Anda, Anda perlu normal dari fragmen yang diarsir. Jika sangat dekat dengan tegak lurus (
dot(surface_normal,view_vector) <= .01
- Anda mungkin perlu bermain dengan ambang itu) maka warnai fragmen hitam daripada warna yang biasa.Pendekatan ini "mengkonsumsi" sedikit model untuk melakukan garis besar. Ini mungkin atau mungkin bukan yang Anda inginkan. Sangat sulit untuk mengetahui dari gambar Pokemon jika ini yang sedang dilakukan. Itu tergantung pada apakah Anda mengharapkan garis besar untuk dimasukkan dalam siluet karakter atau jika Anda lebih suka memiliki garis besar melampirkan siluet (yang membutuhkan teknik yang berbeda).
Sorotan akan berada pada bagian mana pun dari permukaan di mana ia bertransisi dari menghadap ke depan ke menghadap ke belakang, termasuk "tepi bagian dalam" (seperti kaki pada Pokemon hijau, atau kepalanya - beberapa teknik lain tidak akan menambahkan garis besar pada yang ).
Objek yang memiliki tepi yang keras dan tidak mulus (seperti kubus) tidak akan menerima sorotan di lokasi yang diinginkan dengan pendekatan ini. Itu berarti pendekatan ini sama sekali bukan opsi dalam beberapa kasus; Saya tidak tahu apakah model Pokemon semuanya mulus atau tidak.
sumber
Cara paling umum yang pernah saya lihat dilakukan adalah melalui render pass kedua pada model Anda. Pada dasarnya, duplikat dan balik normals, dan dorong itu menjadi vertex shader. Dalam shader, skala setiap simpul sepanjang normalnya. Dalam pixel / fragmen shader, gambarlah hitam. Itu akan memberi Anda garis besar eksternal dan internal, seperti di sekitar bibir, mata, dll. Ini sebenarnya adalah panggilan undian yang cukup murah, jika tidak ada yang lain itu biasanya lebih murah daripada pasca memproses garis, tergantung pada jumlah model dan kompleksitasnya. Guilty Gear Xrd menggunakan metode ini karena mudah untuk mengontrol ketebalan garis melalui warna titik.
Cara kedua melakukan garis dalam saya belajar dari permainan yang sama. Dalam peta UV Anda, sejajarkan tekstur Anda sepanjang sumbu u atau v, terutama di daerah di mana Anda ingin garis dalam. Gambarlah garis hitam di sepanjang salah satu sumbu, dan gerakkan koordinat UV Anda ke dalam atau ke luar garis itu untuk membuat garis dalam.
Lihat video dari GDC untuk penjelasan yang lebih baik: https://www.youtube.com/watch?v=yhGjCzxJV3E
sumber
Salah satu cara untuk membuat garis besar adalah dengan menggunakan vektor normal model kami. Vektor normal adalah vektor yang tegak lurus terhadap permukaannya (menunjuk menjauh dari permukaan). Kuncinya di sini adalah untuk membagi model karakter Anda menjadi dua bagian. Verteks yang menghadap kamera dan simpul yang menghadap jauh dari kamera. Kami akan memanggil mereka FRONT dan BACK masing-masing.
Untuk garis besarnya kita ambil simpul KEMBALI kita dan gerakkan sedikit ke arah vektor normalnya. Pikirkan itu seperti membuat bagian dari karakter kita yang menghadap jauh dari kamera sedikit lebih gemuk. Setelah kita selesai melakukannya, kita memberi mereka warna pilihan kita dan kita memiliki garis besar yang bagus.
Baris 41: Pengaturan "Cull Front" memberi tahu shader untuk melakukan pemusnahan pada simpul yang menghadap ke depan. Ini berarti bahwa kita akan mengabaikan semua simpul yang menghadap ke depan dalam lintasan ini. Kita dibiarkan dengan sisi KEMBALI yang ingin kita manipulasi sedikit.
Garis 51-53: Matematika memindahkan simpul di sepanjang vektor normal mereka.
Baris 54: Mengatur warna titik ke warna pilihan kami yang ditentukan dalam properti shaders.
Tautan Berguna: http://wiki.unity3d.com/index.php/Silhouette-Outlined_Diffuse
Memperbarui
contoh lain
sumber
Salah satu cara terbaik untuk melakukannya adalah dengan membuat adegan Anda pada tekstur Framebuffer , untuk kemudian membuat tekstur itu sambil melakukan Sobel Filtering pada setiap piksel, yang merupakan teknik mudah untuk deteksi tepi. Dengan cara ini Anda tidak hanya dapat membuat adegan menjadi pixelated (menetapkan resolusi rendah ke tekstur Framebuffer), tetapi juga memiliki akses ke setiap nilai piksel untuk membuat Sobel berfungsi.
sumber