Membuat trek di salju di Unreal Engine 4


Jika Anda memainkan game AAA modern, Anda mungkin telah memperhatikan kecenderungan untuk menggunakan lanskap yang tertutup salju. Misalnya, mereka berada di Horizon Zero Dawn , Rise of the Tomb Raider dan God of War . Dalam semua gim ini, salju memiliki fitur penting: Anda dapat meninggalkan jejak di atasnya!

Berkat interaksi dengan lingkungan ini, pencelupan pemain dalam permainan ditingkatkan. Itu membuat lingkungan lebih realistis, dan mari kita jujur ​​- itu hanya menarik. Mengapa menghabiskan waktu berjam-jam menciptakan mekanik yang ingin tahu jika Anda bisa membiarkan pemain jatuh ke tanah dan membuat malaikat salju?

Dalam tutorial ini Anda akan mempelajari hal-hal berikut:

  • Buat jejak kaki menggunakan capture adegan untuk menutupi objek yang dekat dengan tanah
  • Gunakan topeng dengan bahan medan untuk membuat salju yang dapat dideformasi
  • Untuk mengoptimalkan, tampilkan jejak kaki di salju hanya di sebelah pemain

Catatan: dipahami bahwa Anda sudah terbiasa dengan dasar-dasar bekerja dengan Unreal Engine. Jika Anda baru, lihat seri tutorial Mesin Nyata kami untuk pemula .

Mulai bekerja


Unduh materi untuk tutorial ini. Buka zip mereka, pergi ke SnowDeformationStarter dan buka SnowDeformation.uproject . Dalam tutorial ini kita akan membuat jejak dengan bantuan karakter dan beberapa kotak.


Sebelum kita mulai, Anda perlu tahu bahwa metode dari tutorial ini hanya akan menyimpan jejak di area tertentu, dan tidak di seluruh dunia, karena kecepatannya tergantung pada resolusi render target.

Misalnya, jika kita ingin menyimpan jejak untuk area yang luas, maka kita harus meningkatkan resolusi. Tapi itu juga meningkatkan dampak pengambilan adegan pada kecepatan game dan ukuran memori untuk target render. Untuk optimasi, Anda perlu membatasi ruang lingkup dan resolusi.

Setelah mengatasinya, mari cari tahu apa yang diperlukan untuk mewujudkan jejak kaki di salju.

Implementasi jejak kaki di salju


Hal pertama yang Anda butuhkan untuk membuat jejak adalah target render . Target render akan menjadi topeng dalam skala abu-abu, di mana putih menunjukkan adanya jejak, dan hitam menunjukkan tidak adanya. Kemudian kita dapat memproyeksikan target render ke tanah dan menggunakannya untuk mencampur tekstur dan menggeser simpul.


Hal kedua yang kita butuhkan adalah cara untuk menutupi hanya benda-benda yang mempengaruhi salju. Ini dapat diterapkan dengan terlebih dahulu merender objek dalam Kedalaman Kustom . Anda kemudian dapat menggunakan tangkapan layar dengan bahan proses pos untuk menutupi semua objek yang dirender di Custom Depth. Kemudian Anda bisa menampilkan topeng di render target.

Catatan: pengambilan adegan pada dasarnya adalah kamera dengan kemampuan untuk menghasilkan render target.

Bagian terpenting dari mengabadikan sebuah adegan adalah lokasinya. Berikut ini adalah contoh dari target render yang diambil dari tampilan atas . Di sini, karakter dan kotak orang ketiga disamarkan.


Sekilas, tangkapan dengan tampilan atas cocok untuk kami. Formulir terlihat cocok untuk jerat, jadi seharusnya tidak ada masalah, bukan?

Tidak juga. Masalah menangkap dari tampilan atas adalah bahwa ia tidak menangkap apa pun di bawah titik terlebar. Berikut ini sebuah contoh:


Bayangkan bahwa panah kuning sampai ke tanah. Dalam kasus kubus dan kerucut, panah akan selalu tetap berada di dalam objek. Namun, dalam kasus bola, titik muncul darinya ketika mendekati bumi. Namun menurut kamera, ujungnya selalu di dalam bola. Beginilah bentuk sphere untuk kamera:


Oleh karena itu, topeng bola akan lebih besar dari yang seharusnya, bahkan jika area kontak dengan bumi kecil.

Selain itu, masalah ini dilengkapi dengan fakta bahwa sulit bagi kita untuk menentukan apakah objek tersebut menyangkut tanah.


Untuk mengatasi kedua masalah ini, Anda dapat menggunakan tangkapan dari bawah .

Pegangan bawah


Tangkapan dari bawah adalah sebagai berikut:


Seperti yang Anda lihat, kamera sekarang menangkap sisi bawah, yaitu, yang menyentuh tanah. Ini menghilangkan masalah "area terluas" yang muncul saat menangkap dari atas.

Untuk menentukan apakah suatu benda menyentuh tanah, Anda dapat menggunakan bahan pasca-pemrosesan untuk melakukan pemeriksaan kedalaman. Ini memeriksa apakah kedalaman objek lebih besar dari kedalaman bumi dan apakah itu di bawah offset yang telah ditentukan. Jika kedua kondisi terpenuhi, maka kita dapat menutupi piksel ini.


Di bawah ini adalah contoh di dalam mesin dengan zona tangkap 20 unit di atas tanah. Perhatikan bahwa topeng hanya muncul ketika objek melewati titik tertentu. Perhatikan juga bahwa topeng menjadi lebih putih saat objek mendekati tanah.


Pertama, buat bahan pasca pemrosesan untuk melakukan pemeriksaan mendalam.

Membuat Bahan Uji Kedalaman


Untuk melakukan pemeriksaan kedalaman, Anda perlu menggunakan dua buffer kedalaman - satu untuk tanah, yang lainnya untuk objek yang mempengaruhi salju. Karena menangkap pemandangan hanya melihat bumi, Pemandangan Kedalaman akan menyimpulkan kedalaman untuk bumi. Untuk mendapatkan kedalaman untuk objek, kami hanya akan membuatnya Depth Kustom .

Catatan: untuk menghemat waktu, saya telah merender karakter dan kotak di Kedalaman Kustom. Jika Anda ingin menambahkan objek lain yang memengaruhi salju, Anda harus mengaktifkan Render CustomDepth Pass untuknya .

Pertama, Anda perlu menghitung jarak setiap piksel ke tanah. Buka Bahan \ PP_DepthPeriksa dan buat yang berikut:


Selanjutnya, Anda perlu membuat zona tangkap. Untuk melakukan ini, tambahkan node yang disorot:


Sekarang jika pixel berada dalam 25 unit bumi, maka akan muncul di mask. Kecerahan Masking tergantung pada seberapa dekat pixel ke tanah. Klik Terapkan dan kembali ke editor utama.

Selanjutnya Anda perlu membuat tangkapan adegan.

Buat tangkapan adegan


Pertama, kita membutuhkan target render untuk menangkap adegan. Buka folder RenderTarget dan buat Target Render baru yang disebut RT_Capture .

Sekarang mari kita membuat capture adegan. Dalam tutorial ini kita akan menambahkan adegan pengambilan ke cetak biru, karena nanti kita akan memerlukan skrip untuk itu. Buka Cetak Biru \ BP_Capture dan tambahkan Komponen Pengambilan Gambar 2D . Beri nama SceneCapture .


Pertama, kita perlu mengatur pergantian tangkapan sehingga terlihat di tanah. Buka panel Detail dan atur Rotasi ke (0, 90, 90) .


Selanjutnya adalah jenis proyeksi. Karena topeng adalah representasi 2D dari adegan, kita perlu menyingkirkan distorsi perspektif. Untuk melakukan ini, tetapkan Jenis Proyeksi \ Jenis Proyeksi ke Orthografis .


Selanjutnya, kita perlu memberi tahu tangkapan adegan yang menjadi target rekaman untuk direkam. Untuk melakukan ini, pilih nilai RT_Capture untuk Scene Capture \ Target Tekstur .


Akhirnya, kita perlu menggunakan bahan pemeriksaan kedalaman. Tambahkan PP_DepthPeriksa ke Rendering Features \ Post Process Materials . Agar post-processing berfungsi, kita juga perlu mengubah Scene Capture \ Capture Source ke Final Color (LDR) di RGB .


Sekarang setelah pengambilan adegan dikonfigurasikan, kita perlu menentukan ukuran area pengambilan.

Mengatur ukuran area tangkapan


Karena lebih baik menggunakan resolusi rendah untuk target render, kita perlu menggunakan ruang secara efisien. Artinya, kita harus memilih area mana yang satu piksel akan mencakup. Misalnya, jika resolusi area tangkap dan target render sama, maka kami mendapatkan rasio 1: 1. Setiap piksel akan mencakup area 1 Γ— 1 (dalam satuan dunia).

Untuk trek di salju, rasio 1: 1 tidak diperlukan, karena kita kemungkinan besar tidak membutuhkan detail seperti itu. Saya sarankan menggunakan rasio yang lebih besar karena ini akan memungkinkan Anda untuk meningkatkan ukuran area pengambilan pada resolusi rendah. Tetapi jangan membuat rasio terlalu besar, jika tidak rinciannya akan mulai hilang. Dalam tutorial ini, kita akan menggunakan rasio 8: 1, yaitu, ukuran setiap piksel akan menjadi 8 Γ— 8 unit dunia.

Anda dapat mengubah ukuran area pengambilan dengan mengubah properti Scene Capture \ Ortho Width . Misalnya, jika Anda ingin menangkap area 1024 Γ— 1024, maka atur nilainya menjadi 1024. Karena kami menggunakan rasio 8: 1, atur nilainya menjadi 2048 (resolusi default dari target render adalah 256 Γ— 256).


Ini berarti bahwa pengambilan adegan akan menangkap area 2048 Γ— 2048 . Berjarak sekitar 20 Γ— 20 meter.

Bahan dasar juga membutuhkan akses untuk menangkap ukuran untuk memproyeksikan render target dengan benar. Cara termudah untuk melakukan ini adalah dengan menyimpan ukuran tangkapan di Koleksi Parameter Material . Ini pada dasarnya adalah kumpulan variabel yang dapat diakses materi apa pun .

Menyimpan ukuran tangkapan


Kembali ke editor utama dan buka folder Bahan . Buat Koleksi Parameter Bahan yang akan di Bahan & Tekstur . Ubah nama menjadi MPC_Capture dan buka.

Kemudian buat Parameter Skalar baru dan beri nama CaptureSize . Jangan khawatir tentang pengaturan nilainya - kami akan melakukannya terus terang.


Kembali ke BP_Capture dan tambahkan node yang disorot ke Event BeginPlay . Setel Koleksi ke MPC_Capture , dan Nama Parameter ke CaptureSize .


Sekarang bahan apa pun bisa mendapatkan nilai Lebar Ortho dengan membacanya dari parameter CaptureSize . Sejauh ini dengan penangkapan adegan kami selesai. Klik Kompilasi dan kembali ke editor utama. Langkah selanjutnya adalah memproyeksikan target render ke tanah dan menggunakannya untuk merusak lanskap.

Deformasi lanskap


Buka M_Landscape dan buka panel Detail. Kemudian atur properti berikut:

  • Untuk Dua Sisi, pilih diaktifkan . Karena menangkap pemandangan akan "melihat" dari bawah, ia hanya akan melihat muka bumi yang terbalik. Secara default, mesin tidak membuat permukaan belakang jerat. Ini berarti bahwa ia tidak akan menyimpan kedalaman bumi dalam buffer kedalaman. Untuk memperbaiki ini, kita perlu memberitahu mesin untuk membuat kedua sisi mesh.
  • Untuk D3D11 Tessellation, pilih Flat Tessellation (PN Segitiga juga dapat digunakan). Tessellation akan memecah segitiga jala menjadi yang lebih kecil. Intinya, ini meningkatkan resolusi mesh dan memungkinkan kita untuk mendapatkan detail yang lebih baik saat menggeser simpul. Tanpa ini, kepadatan puncak akan terlalu rendah untuk membuat jejak yang bisa dipercaya.


Setelah tessellations diaktifkan, Pengganda Dunia dan Pengganda Tessellation akan menyala.


Tessellation Multipler mengontrol jumlah tessellation. Dalam tutorial ini, kita tidak akan menghubungkan node ini, yaitu, kita menggunakan nilai default ( 1 ).

World Displacement mendapatkan nilai vektor yang menggambarkan ke arah mana dan seberapa banyak untuk memindahkan titik. Untuk menghitung nilai kontak ini, pertama-tama kita harus memproyeksikan target render ke tanah.

Render Target Proyek


Untuk memproyeksikan target render, Anda perlu menghitung koordinat UV-nya. Untuk melakukan ini, buat skema berikut:


Apa yang terjadi di sini:

  1. Pertama kita perlu mendapatkan posisi XY dari simpul saat ini. Karena kami menangkap dari bawah, koordinat X dibalik, jadi Anda perlu membaliknya kembali (jika kami ingin menangkap dari atas, kami tidak memerlukan ini).
  2. Bagian ini melakukan dua tugas. Pertama, ia memusatkan target render sedemikian rupa sehingga medianya berada di koordinat (0, 0) dari ruang dunia. Dia kemudian mengubah koordinat dari ruang dunia ke ruang UV.

Selanjutnya, buat node yang dipilih dan gabungkan perhitungan sebelumnya seperti yang ditunjukkan di bawah ini. Untuk Sampel Tekstur, pilih RT_Capture .


Ini akan memproyeksikan target render ke tanah. Namun, semua simpul di luar area tangkapan akan mengambil sampel tepi target render. Ini sebenarnya masalah karena target render seharusnya hanya digunakan untuk simpul dalam area tangkapan. Begini tampilannya dalam game:


Untuk memperbaikinya, kita perlu menutupi semua UV yang berada di luar kisaran 0 hingga 1 (mis., Area tangkapan). Untuk ini, saya membuat fungsi MF_MaskUV0-1 . Ini mengembalikan 0 jika UV yang ditransmisikan berada di luar kisaran 0 hingga 1 dan mengembalikan 1 jika ada di dalamnya. Mengalikan hasilnya dengan target render, kami melakukan masking.

Sekarang kita telah memproyeksikan render target, kita dapat menggunakannya untuk mencampur warna dan memindahkan titik.

Menggunakan Target Render


Mari kita mulai dengan mencampur warna. Untuk melakukan ini, kita cukup menghubungkan 1-x ke Lerp :


Catatan: jika Anda tidak mengerti mengapa saya menggunakan 1-x , saya akan menjelaskan - ini diperlukan untuk membalikkan target render, sehingga perhitungannya menjadi sedikit lebih mudah.

Sekarang kita memiliki jejak, warna bumi berubah menjadi cokelat. Jika tidak ada warna, tetap putih.

Langkah selanjutnya adalah perpindahan simpul. Untuk melakukan ini, tambahkan node yang dipilih dan hubungkan semuanya sebagai berikut:


Ini akan menyebabkan semua area salju naik 25 unit. Daerah tanpa salju memiliki offset nol, yang akan membuat jejak.

Catatan: Anda dapat mengubah DisplacementHeight untuk menambah atau mengurangi level salju. Perhatikan juga bahwa DisplacementHeight memiliki nilai yang sama dengan capture offset. Ketika mereka memiliki makna yang sama, itu memberi kita deformasi yang tepat. Tetapi ada beberapa kasus ketika Anda perlu mengubahnya secara individual, jadi saya meninggalkannya sebagai parameter terpisah.

Klik Terapkan dan kembali ke editor utama. Buat instance BP_Capture di level dan berikan koordinatnya (0, 0, -2000) untuk meletakkannya di bawah tanah. Klik Play dan berkeliaran dengan tombol W , A , S dan D untuk membelokkan salju.


Deformasi bekerja, tetapi tidak ada jejak yang tersisa! Ini terjadi karena penangkapan menimpa target yang diberikan setiap kali penangkapan dilakukan. Kami membutuhkan beberapa cara untuk membuat trek permanen .

Membuat Jejak Permanen


Untuk membuat kegigihan, kita perlu render target lain ( buffer konstan ), di mana semua konten capture akan disimpan sebelum ditimpa. Kemudian kita akan menambahkan buffer konstan ke capture (setelah menimpanya). Kami mendapatkan loop di mana setiap target membuat menulis ke yang lain. Ini adalah bagaimana kami akan membuat jejak permanen.


Pertama, kita perlu membuat buffer konstan.

Membuat buffer persisten


Buka folder RenderTarget dan buat Target Render baru yang disebut RT_Persistent . Dalam tutorial ini kami tidak perlu mengubah parameter tekstur, tetapi dalam proyek Anda sendiri, Anda harus memastikan bahwa kedua target yang dirender menggunakan resolusi yang sama.

Selanjutnya, kita membutuhkan materi yang akan menyalin tangkapan ke buffer permanen. Buka Bahan \ M_DrawToPersistent dan tambahkan simpul Contoh Tekstur . Pilih tekstur RT_Capture untuknya dan sambungkan sebagai berikut:


Sekarang kita perlu menggunakan bahan gambar. Klik Terapkan , lalu buka BP_Capture . Pertama, buat instance dinamis dari materi (nanti kita perlu memberikan nilai padanya). Tambahkan node yang disorot ke Event BeginPlay :


Clear Render Target 2D node menghapus setiap target render sebelum digunakan.

Kemudian buka fungsi DrawToPersistent dan tambahkan node yang disorot:


Selanjutnya, kita perlu memastikan bahwa gambar ke buffer konstan dilakukan di setiap frame, karena penangkapan terjadi di setiap frame. Untuk melakukan ini, tambahkan DrawToPersistent ke Event Tick .


Akhirnya, kita perlu menambahkan buffer persisten kembali ke target capture render.

Rekam kembali untuk ditangkap


Klik Kompilasi dan buka PP_DepthCheck . Kemudian tambahkan node yang disorot. Untuk Sampel Tekstur, tetapkan nilainya ke RT_Persistent :


Sekarang target membuat menulis satu sama lain, kami mendapatkan jejak yang tersisa. Klik Terapkan , lalu tutup materi. Klik Play dan mulai meninggalkan trek!


Hasilnya tampak hebat, tetapi sirkuit yang dihasilkan hanya berfungsi untuk satu area peta. Jika Anda melampaui area tangkapan, jejak akan berhenti muncul.


Anda dapat mengatasi masalah ini dengan memindahkan area tangkap dengan pemain. Ini berarti bahwa jejak akan selalu muncul di sekitar area di mana pemain berada.

Catatan: saat pengambilan bergerak, semua informasi di luar area pengambilan dihapus. Ini berarti bahwa jika Anda kembali ke area di mana sudah ada jejak, maka mereka akan menghilang. Dalam tutorial berikutnya, saya akan menunjukkan kepada Anda cara membuat trek yang dipertahankan sebagian.

Tangkap gerakan


Anda dapat memutuskan bahwa itu cukup sederhana untuk mengikat posisi penangkapan XY ke posisi pemain XY. Tetapi jika Anda melakukannya, maka target render akan mulai kabur. Ini karena kami memindahkan target render dengan langkah yang kurang dari satu piksel. Ketika ini terjadi, posisi piksel baru berada di antara piksel. Akibatnya, satu piksel diinterpolasi oleh beberapa piksel. Begini tampilannya:


Untuk memperbaiki masalah ini, kita perlu memindahkan tangkapan dalam langkah-langkah terpisah. Kami menghitung ukuran piksel di dunia , dan kemudian memindahkan tangkapan ke langkah yang sama dengan ukuran itu. Maka setiap piksel tidak akan pernah berada di antara yang lain, sehingga kekaburan tidak akan muncul.

Untuk memulai, mari kita buat parameter di mana lokasi pengambilan akan disimpan. Bahan bumi akan membutuhkannya untuk melakukan perhitungan proyeksi. Buka MPC_Capture dan tambahkan Parameter Vektor yang disebut CaptureLocation .


Selanjutnya, Anda perlu memperbarui materi bumi untuk menggunakan parameter baru. Tutup MPC_Capture dan buka M_Landscape . Ubah bagian pertama dari perhitungan proyeksi sebagai berikut:


Sekarang target render akan selalu diproyeksikan ke lokasi penangkapan. Klik Terapkan dan tutup materi.

Selanjutnya, kita akan melakukan penangkapan dengan langkah terpisah.

Gerakan menangkap langkah diskrit


Untuk menghitung ukuran piksel di dunia, Anda dapat menggunakan persamaan berikut:

(1 / RenderTargetResolution) * CaptureSize 

Untuk menghitung posisi baru, kami menggunakan persamaan yang ditunjukkan di bawah ini untuk setiap komponen posisi (dalam kasus kami, untuk koordinat X dan Y).

 (floor(Position / PixelWorldSize) + 0.5) * PixelWorldSize 

Sekarang gunakan dalam pengambilan cetak biru. Untuk menghemat waktu, saya membuat makro SnapToPixelWorldSize untuk persamaan kedua. Buka BP_Capture , lalu buka fungsi MoveCapture . Selanjutnya, buat diagram berikut:


Ini akan menghitung lokasi baru, dan kemudian menyimpan perbedaan antara lokasi baru dan saat ini di MoveOffset . Jika Anda menggunakan resolusi selain 256 Γ— 256, maka ubah nilai yang disorot.

Selanjutnya, tambahkan node yang dipilih:


Sirkuit ini akan memindahkan tangkapan dengan offset yang dihitung. Dia kemudian akan menyimpan lokasi pengambilan baru di MPC_Capture sehingga dapat digunakan oleh bahan dasar.

Akhirnya, kita perlu melakukan pembaruan posisi di setiap frame. Tutup fungsinya dan tambahkan ke Event Tick sebelum DrawToPersistent MoveCapture .


Memindahkan tangkapan hanya setengah dari solusi. Kita juga perlu memindahkan buffer konstan. Kalau tidak, capture dan buffer persisten akan tidak sinkron dan akan menghasilkan hasil yang aneh.


Pindah Buffer Permanen


Untuk menggeser buffer konstan, kita harus melewati offset perpindahan yang dihitung. Buka M_DrawToPersistent dan tambahkan node yang disorot:


Karena ini, buffer konstan akan digeser oleh nilai offset yang ditransmisikan. Seperti pada materi bumi, kita perlu membalik koordinat X dan melakukan masking. Klik Terapkan dan tutup materi.

Maka Anda perlu mentransfer ofset. Buka BP_Capture , lalu buka fungsi DrawToPersistent . Selanjutnya, tambahkan node yang disorot:


Ini adalah bagaimana kami mengonversi MoveOffset ke ruang UV, dan kemudian meneruskannya ke bahan gambar.

Klik Kompilasi , lalu tutup cetak biru. Klik Play dan jalankan sesuka hati Anda! Tidak peduli seberapa jauh Anda berlari, jejak akan selalu ada di sekitar Anda.


Ke mana harus pergi selanjutnya?


Proyek yang sudah selesai dapat diunduh dari sini.

Tidak perlu menggunakan trek yang dibuat dalam tutorial ini untuk salju saja. Anda bahkan dapat menggunakannya untuk hal-hal seperti rumput yang dihancurkan (dalam tutorial berikutnya saya akan menunjukkan cara membuat versi lanjutan dari sistem).

Jika Anda ingin bekerja dengan lanskap dan rendering target, saya sarankan menonton video Chris Murphy Building High-End Gameplay Effects dengan Blueprint . Tutorial ini akan menunjukkan cara membuat laser besar yang membakar bumi dan rumput!

Source: https://habr.com/ru/post/id416703/


All Articles