Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Shaders

Membuat Air Toon untuk Web: Bagian 3

by
Difficulty:AdvancedLength:LongLanguages:
This post is part of a series called Creating Toon Water for the Web.
Creating Toon Water for the Web: Part 2

Indonesian (Bahasa Indonesia) translation by Suci Rohini (you can also view the original English article)

Selamat datang kembali ke seri tiga bagian ini pada pembuatan air toon bergaya di PlayCanvas menggunakan vertex shaders. Di Part 2 kita membahas buoyancy & garis busa. Pada bagian akhir ini, kita akan menerapkan distorsi bawah laut sebagai efek pasca-proses.

Efek Refraksi & Pasca Proses

Tujuan kita adalah untuk mengkomunikasikan secara visual pembiasan cahaya melalui air. Kita sudah membahas cara membuat distorsi semacam ini dalam shader fragmen dalam tutorial sebelumnya untuk adegan 2D. Satu-satunya perbedaan di sini adalah bahwa kita harus mencari tahu area layar mana yang berada di bawah air dan hanya menerapkan distorsi di sana.

Pengolahan pasca

Secara umum, efek pasca-proses adalah apa pun yang diterapkan ke seluruh adegan setelah ditampilkan, seperti warna berwarna atau efek layar CRT yang lama. Alih-alih membuat adegan Anda langsung ke layar, Anda terlebih dahulu membuatnya ke buffer atau tekstur, dan kemudian membuat itu ke layar, melewati shader kustom.

Di PlayCanvas, Anda dapat menyiapkan efek pasca-proses dengan membuat skrip baru. Sebut saja Refraction.js, dan salin template ini untuk memulai dengan:

Ini seperti skrip biasa, tetapi kita mendefinisikan kelas RefractionPostEffect yang dapat diterapkan ke kamera. Ini membutuhkan titik dan shader fragmen untuk membuat. Atribut sudah disiapkan, jadi mari kita buat Refraction.frag dengan konten ini:

Dan Refraction.vert dengan shader vertex dasar:

Sekarang lampirkan skrip Refraction.js ke kamera, dan tetapkan shader ke atribut yang sesuai. Saat Anda meluncurkan gim, Anda harus melihat adegan persis seperti sebelumnya. Ini adalah efek posting kosong yang hanya mengembalikan adegan. Untuk memverifikasi bahwa ini berfungsi, coba beri suasana merah.

Dalam Refraction.frag, daripada hanya mengembalikan warna, coba atur komponen merah ke 1.0, yang seharusnya terlihat seperti gambar di bawah.

Scene rendered with a red tint

Distorsi Shader

Kita perlu menambahkan seragam waktu untuk distorsi animasi, jadi lanjutkan dan buat satu di Refraction.js, di dalam konstruktor ini untuk efek posting:

Sekarang, di dalam fungsi render ini, kita menyebarkannya ke shader kita dan meningkatkannya:

Sekarang kita bisa menggunakan kode shader yang sama dari tutorial distorsi air, membuat shader fragmen penuh kita terlihat seperti ini:

Jika semuanya berhasil, semuanya sekarang harus terlihat seperti di bawah air, seperti di bawah ini.

Underwater distortion applied to the whole scene
Tantangan #1: Buat distorsi hanya berlaku untuk setengah bagian bawah layar.

Masker Kamera

Kita hampir sampai. Yang perlu kita lakukan sekarang adalah menerapkan efek distorsi ini hanya di bagian bawah air layar. Cara langsung saya telah datang dengan untuk melakukan ini adalah untuk kembali membuat adegan dengan permukaan air yang diterjemahkan sebagai putih solid, seperti yang ditunjukkan di bawah ini.

Water surface rendered as a solid white to act as a mask

Ini akan menjadi tekstur yang akan bertindak sebagai topeng. Kita kemudian akan melewatkan tekstur ini ke shader refraksi kita, yang hanya akan mendistorsi piksel pada gambar akhir jika piksel yang sesuai dalam topeng berwarna putih.

Mari tambahkan atribut boolean di permukaan air untuk mengetahui apakah itu digunakan sebagai masker. Tambahkan ini ke Water.js:

Kita kemudian dapat meneruskannya ke shader dengan material.setParameter ('isMask', this.isMask); seperti biasa. Kemudian deklarasikan di Water.frag dan atur warnanya menjadi putih jika itu benar.

Konfirmasikan bahwa ini berfungsi dengan mengaktifkan "Is Mask?" properti di editor dan meluncurkan kembali game. Seharusnya terlihat putih, seperti pada gambar sebelumnya.

Sekarang, untuk membuat ulang adegan, kita membutuhkan kamera kedua. Buat kamera baru di editor dan beri nama CameraMask. Gandakan entitas Air di editor juga, dan beri nama WaterMask. Pastikan "Is Mask?" salah untuk entitas Water tetapi berlaku untuk WaterMask.

Untuk memberi tahu kamera baru agar merender ke tekstur alih-alih layar, buat skrip baru yang disebut CameraMask.js dan lampirkan ke kamera baru. Kita membuat RenderTarget untuk menangkap output kamera ini seperti ini:

Sekarang, jika Anda meluncurkan, Anda akan melihat kamera ini tidak lagi render ke layar. Kita bisa mengambil output dari target rendernya di Refraction.js seperti ini:

Perhatikan bahwa saya melewatkan tekstur topeng ini sebagai argumen untuk konstruktor efek pos. Kita perlu membuat referensi untuk itu di konstruktor kita, sehingga terlihat seperti:

Akhirnya, dalam fungsi render, berikan buffer ke shader kita dengan:

Sekarang untuk memverifikasi bahwa ini semua berfungsi, saya akan meninggalkan itu sebagai tantangan.

Tantangan #2: Render uMaskBuffer ke layar untuk mengonfirmasi bahwa ini adalah output dari kamera kedua.

Satu hal yang harus diperhatikan adalah bahwa render target diatur dalam menginisialisasi CameraMask.js, dan yang perlu siap pada saat Refraction.js dipanggil. Jika skrip dijalankan sebaliknya, Anda akan mendapatkan kesalahan. Untuk memastikannya berjalan dalam urutan yang benar, seret CameraMask ke bagian atas daftar entitas dalam editor, seperti ditunjukkan di bawah ini.

PlayCanvas editor with CameraMask at top of entity list

Kamera kedua harus selalu melihat pada tampilan yang sama seperti yang asli, jadi mari kita membuatnya selalu mengikuti posisinya dan rotasi dalam pembaruan CameraMask.js:

Dan tentukan CameraToFollow di inisialisasi:

Menyisihkan Mask

Kedua kamera saat ini memberikan hal yang sama. Kita ingin kamera masker untuk merender segalanya kecuali air asli, dan kita ingin kamera nyata untuk merender segalanya kecuali air masker.

Untuk melakukan ini, kita bisa menggunakan masker bit pemusnahan kamera. Ini bekerja sama dengan collision mask jika Anda pernah menggunakannya. Sebuah objek akan dimusnahkan (tidak diberikan) jika hasil bitwise DAN antara mask dan mask kamera adalah 1.

Katakanlah Air akan memiliki bit 2 set, dan WaterMask akan memiliki bit 3. Maka kamera yang sebenarnya harus memiliki semua bit yang ditetapkan kecuali untuk 3, dan kamera mask harus memiliki semua bit yang ditetapkan kecuali 2. Cara mudah untuk mengatakan "semua bit kecuali N" harus dilakukan:

Anda dapat membaca lebih lanjut tentang operator bitwise di sini.

Untuk mengatur masker pemusnahan kamera, kita dapat menempatkan ini di dalam inisialisasi CameraMask.js di bagian bawah:

Sekarang, di Water.js, atur Water mesh mask pada bit 2, dan versi mask di bit 3:

Sekarang, satu tampilan akan memiliki air normal, dan yang lainnya akan memiliki air putih padat. Setengah bagian kiri gambar di bawah adalah tampilan dari kamera asli, dan setengah bagian kanan dari kamera mask.

Split view of mask camera and original camera

Menerapkan Mask

Satu langkah terakhir sekarang! Kita tahu area bawah laut ditandai dengan piksel putih. Kita hanya perlu memeriksa apakah kita tidak berada pada piksel putih, dan jika demikian, matikan distorsi di Refraction.frag:

Dan itu harus dilakukan!

Satu hal yang perlu diperhatikan adalah karena tekstur untuk mask diinisialisasi saat peluncuran, jika Anda mengubah ukuran jendela saat runtime, itu tidak akan lagi sesuai dengan ukuran layar.

Anti-Aliasing

Sebagai langkah pembersihan opsional, Anda mungkin telah memperhatikan bahwa tepian dalam adegan sekarang terlihat sedikit tajam. Ini karena ketika kita menerapkan efek posting kita, kita kehilangan anti-aliasing.

Kita dapat menerapkan tambahan anti-alias di atas efek kita sebagai efek posting lain. Untungnya, ada satu yang tersedia di toko PlayCanvas yang bisa kita gunakan. Buka halaman aset skrip, klik tombol unduhan hijau besar, dan pilih proyek Anda dari daftar yang muncul. Skrip akan muncul di akar jendela aset Anda sebagai posteffect-fxaa.js. Cukup lampirkan ini ke entitas Kamera, dan adegan Anda akan terlihat sedikit lebih bagus!

Pikiran Akhir

Jika Anda sudah berhasil sejauh ini, beri tepukan pada punggung Anda! Kita membahas banyak teknik dalam seri ini. Anda sekarang harus merasa nyaman dengan vertex shaders, rendering tekstur, menerapkan efek pasca-pemrosesan, secara selektif memuntahkan objek, menggunakan buffer kedalaman, dan bekerja dengan pencampuran dan transparansi. Meskipun kita menerapkan ini di PlayCanvas, ini semua adalah konsep grafis umum yang akan Anda temukan dalam beberapa bentuk di platform apa pun yang Anda masuki.

Semua teknik ini juga berlaku untuk berbagai efek lainnya. Salah satu aplikasi yang sangat menarik yang saya temukan dari vertex shaders adalah dalam pembicaraan ini pada seni Abzu, di mana mereka menjelaskan bagaimana mereka menggunakan vertex shaders untuk secara efisien menghidupkan puluhan ribu ikan di layar.

Anda sekarang harus memiliki efek air yang bagus yang dapat Anda terapkan ke gim Anda! Anda dapat dengan mudah menyesuaikannya sekarang karena Anda telah mengumpulkan setiap detail sendiri. Masih banyak lagi yang bisa Anda lakukan dengan air (saya bahkan belum menyebutkan semacam refleksi sama sekali). Di bawah ini adalah beberapa ide.

Gelombang Berbasis Kebisingan

Alih-alih hanya menganimasikan gelombang dengan kombinasi sinus dan cosinus, Anda dapat mencicipi tekstur suara untuk membuat gelombang terlihat sedikit lebih alami dan tidak dapat diprediksi.

Jalur Busa Dinamis

Alih-alih garis air statis sepenuhnya di permukaan, Anda bisa menggambar ke tekstur itu ketika objek bergerak, untuk menciptakan jejak busa dinamis. Ada banyak cara untuk melakukan ini, jadi ini bisa menjadi proyek sendiri.

Kode Sumber

Anda dapat menemukan proyek PlayCanvas yang sudah jadi di sini. Port Three.js juga tersedia di repositori ini.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.