Bagaimana kerangka Rise of the Tomb Raider ditampilkan


Rise of the Tomb Raider (2015) adalah sekuel dari restart Raider (2013) yang sangat baik. Secara pribadi, saya menemukan kedua bagian menarik karena mereka pindah dari seri asli stagnan dan menceritakan kisah Lara lagi. Dalam permainan ini, seperti dalam prekuel, plot mengambil panggung utama, menyediakan mekanisme menarik kerajinan, perburuan dan pendakian / penelitian.

Tomb Raider menggunakan Crystal Engine, yang dikembangkan oleh Crystal Dynamics, juga digunakan dalam Deus Ex: Human Revolution . Sekuel ini menggunakan mesin baru bernama Foundation, yang sebelumnya dikembangkan untuk Lara Croft dan Kuil Osiris (2014). Rendernya secara umum dapat digambarkan sebagai mesin ubin dengan pas pencahayaan awal, dan kemudian kita akan mengetahui apa artinya ini. Engine memungkinkan Anda untuk memilih antara penyaji DX11 dan DX12; Saya memilih yang terakhir, untuk alasan yang kita diskusikan di bawah ini. Untuk menangkap frame, Renderdoc 1.2 digunakan pada Geforce 980 Ti, game ini mencakup semua fungsi dan dekorasi.

Bingkai yang dianalisis



Untuk menghindari spoiler, saya akan mengatakan bahwa dalam frame ini orang jahat mengejar Lara, karena dia mencari artefak yang mereka cari. Konflik kepentingan ini tidak dapat diselesaikan tanpa senjata. Lara menyelinap ke markas musuh di malam hari. Saya memilih bingkai dengan pencahayaan atmosfer dan kontras, di mana mesin dapat menunjukkan dirinya.

Kedalaman muka


Di sini, optimasi biasa untuk banyak game dilakukan - operan awal yang kecil (sekitar 100 panggilan undian). Gim ini menjadikan objek terbesar (dan bukan obyek yang mengambil lebih banyak ruang di layar) untuk memanfaatkan fitur prosesor video Early-Z. Baca lebih lanjut di artikel Intel . Singkatnya, GPU dapat menghindari mengeksekusi pixel shader jika mereka dapat menentukan bahwa itu tumpang tindih dengan pixel sebelumnya. Ini adalah bagian yang cukup murah, pra-mengisi Z-buffer dengan nilai kedalaman.

Pada titik ini, saya menemukan teknik level detail (LOD) yang menarik yang disebut "fizzle" atau "checkerboard". Ini adalah cara umum untuk secara bertahap menampilkan atau menyembunyikan objek di kejauhan, sehingga nantinya mereka dapat diganti dengan mesh berkualitas lebih rendah, atau sepenuhnya menyembunyikannya. Lihat truk ini. Sepertinya itu rendering dua kali, tetapi sebenarnya rendering dengan LOD tinggi dan LOD rendah di posisi yang sama. Masing-masing level membuat piksel yang tidak dirender oleh yang lainnya. LOD pertama memiliki 182226 simpul, dan LOD kedua memiliki 47250. Pada jarak yang sangat jauh mereka tidak bisa dibedakan, tetapi salah satunya tiga kali lebih murah. Dalam bingkai ini, LOD 0 hampir menghilang, dan LOD 1 hampir sepenuhnya ditampilkan. Setelah penghilangan lengkap LOD 0, hanya LOD 1 yang akan diberikan.


LOD 0


LOD 1


Tekstur pseudo-acak dan koefisien probabilitas memungkinkan kita untuk membuang piksel yang belum melewati nilai ambang batas. Tekstur ini digunakan dalam ROTR. Orang mungkin bertanya-tanya mengapa alpha blending tidak digunakan. Alpha blending memiliki banyak kelemahan dibandingkan fizzle fading.

  1. Kemudahan untuk bagian awal kedalaman: berkat rendering dari objek buram dengan lubang yang dibuat di dalamnya, kita dapat membuat bagian awal dan menggunakan awal-z. Objek dengan alpha blending pada tahap awal tidak akan dirender ke buffer kedalaman karena masalah pengurutan.
  2. Kebutuhan akan shader tambahan : jika penyaji yang ditangguhkan digunakan, shader objek buram tidak mengandung pencahayaan apa pun. Jika Anda perlu mengganti objek yang buram dengan yang transparan, maka Anda memerlukan opsi terpisah di mana ada pencahayaan. Selain meningkatkan jumlah memori yang dibutuhkan dan kompleksitas karena setidaknya satu shader tambahan untuk semua objek buram, mereka harus akurat untuk menghindari objek bergerak maju. Ini rumit karena banyak alasan, tetapi semuanya bermuara pada kenyataan bahwa rendering sekarang dilakukan dalam jalur kode yang berbeda.
  3. Redraw yang lebih besar : alpha blending dapat membuat redraw besar, dan pada tingkat kerumitan objek tertentu, sebagian besar dari bandwidth mungkin diperlukan untuk menaungi LOD.
  4. Konflik-Z : konflik- z adalah efek kedipan ketika dua poligon dirender pada kedalaman yang sangat dekat satu sama lain. Dalam hal ini, ketidakakuratan perhitungan titik apung memaksa mereka untuk diberikan pada gilirannya. Jika kita membuat dua LOD berturut-turut, secara bertahap menyembunyikan satu dan menunjukkan yang kedua, maka mereka dapat menyebabkan z-konflik, karena mereka sangat dekat satu sama lain. Selalu ada cara untuk menyiasatinya, misalnya, lebih suka satu poligon ke poligon lain, tetapi sistem seperti itu kompleks.
  5. Z-Buffer Effects : Banyak efek seperti SSAO hanya menggunakan buffer kedalaman. Jika kami memberikan objek transparan di ujung pipa ketika oklusi ambien telah selesai, kami tidak dapat memperhitungkannya.

Kerugian dari teknik ini adalah bahwa itu terlihat lebih buruk daripada alpha blending, tetapi pola kebisingan yang baik, kabur setelah gagal, atau anti-aliasing sementara hampir sepenuhnya dapat menyembunyikannya. Dalam hal ini, ROTR tidak melakukan sesuatu yang tidak biasa.

Pass Normal


Crystal Dynamics menggunakan pola pencahayaan yang agak tidak biasa dalam permainannya, yang akan kita bahas di lorong pencahayaan. Untuk saat ini, cukup untuk mengatakan bahwa mesin tidak memiliki pass G-buffer; setidaknya sejauh yang akrab di gim lain. Pada bagian ini, objek hanya mengirimkan informasi tentang kedalaman dan normals ke output. Normal dicatat dalam target render format RGBA16_SNORM di ruang dunia. Sangat aneh bahwa mesin ini menggunakan skema Z-up, bukan Y-up (sumbu Z diarahkan ke atas, bukan sumbu Y), yang lebih sering digunakan dalam mesin / paket pemodelan lainnya. Saluran alfa berisi glossiness, yang kemudian dibongkar sebagai exp2(glossiness * 12 + 1.0) . Nilai kilau juga bisa negatif, karena tanda digunakan sebagai bendera yang menunjukkan apakah permukaannya metalik. Ini bisa diperhatikan sendiri, karena semua warna gelap di saluran alpha terkait dengan benda logam.

RGB
Normal.xNormalNormal.zGlossiness + Metalness


Normal


Glossiness / metalness

Keuntungan Keberangkatan


Ingat bahwa di bagian "Kedalaman Awal", kami berbicara tentang menghemat biaya piksel? Saya akan kembali sedikit untuk menggambarkannya. Ambil gambar berikut. Ini membuat bagian detail gunung ke buffer normal. Renderdoc dengan baik hati menyorot piksel yang lulus uji kedalaman dengan warna hijau, dan piksel yang tidak lulus warna merah (tidak akan ditampilkan). Jumlah piksel yang akan diberikan tanpa lintasan pendahuluan ini kira-kira sama dengan 104518 (dihitung dalam Photoshop). Jumlah piksel yang benar-benar render adalah 23858 (dihitung oleh Renderdoc). Hemat sekitar 77%! Seperti yang kita lihat, dengan penggunaan yang cerdas, kartu pendahuluan ini dapat memberikan keuntungan besar, dan hanya membutuhkan sekitar seratus panggilan draw.

Merekam perintah multithreaded


Perlu dicatat satu aspek yang menarik, karena itu saya memilih renderer DX12 - merekam perintah multi-utas. Di API sebelumnya, seperti DX11, rendering biasanya dilakukan dalam satu utas. Driver grafis menerima perintah rendering dari game dan terus-menerus mengirimkan permintaan GPU, tetapi game tidak tahu kapan ini akan terjadi. Ini mengarah ke inefisiensi, karena pengemudi entah bagaimana harus menebak apa yang coba dilakukan aplikasi, dan tidak menskala ke beberapa utas. API yang lebih baru seperti DX12 menyerahkan kendali kepada pengembang yang dapat memutuskan cara menulis perintah dan kapan mengirimnya. Meskipun Renderdoc tidak dapat menunjukkan bagaimana perekaman dilakukan, Anda akan melihat bahwa ada tujuh lintasan warna yang ditandai sebagai Color Pass N, dan masing-masing dibungkus dengan sepasang ExecuteCommandList: Reset / Tutup. Ini menandai awal dan akhir daftar perintah. Daftar menyumbang sekitar 100-200 panggilan imbang. Ini tidak berarti bahwa mereka direkam menggunakan beberapa aliran, tetapi mengisinya.

Jejak kaki di salju


Jika Anda melihat Lara, Anda dapat melihat bahwa ketika bergerak di depan tangkapan layar ia meninggalkan jejak di salju. Di setiap frame, penghitung bayangan dijalankan, yang merekam deformasi di area tertentu dan menerapkannya berdasarkan jenis dan ketinggian permukaan. Di sini, hanya peta normal yang diterapkan pada salju (mis. Geometri tidak berubah), tetapi di beberapa daerah di mana salju lebih tebal, deformasi sebenarnya dilakukan! Anda juga dapat melihat bagaimana salju "jatuh" ke tempatnya dan mengisi jejak yang ditinggalkan oleh Lara. Teknik ini dijelaskan lebih detail dalam GPU Pro 7 . Tekstur salju lusi adalah sejenis peta ketinggian yang melacak gerakan Lara dan menempel di tepinya sehingga shader pengambilan sampel dapat memanfaatkan lipatan ini.

Atlas of Shadows


Saat membuat pemetaan bayangan, pendekatan yang cukup umum digunakan - mengemas kartu bayangan sebanyak mungkin menjadi tekstur bayangan yang umum. Atlas bayangan seperti itu sebenarnya merupakan tekstur 16-bit besar dengan ukuran 16384 Γ— 8196. Ini memungkinkan Anda untuk secara fleksibel menggunakan kembali dan skala peta bayangan di atlas. Dalam bingkai yang kami analisis, 8 peta bayangan dicatat di atlas. Empat dari mereka berhubungan dengan sumber utama penerangan terarah (bulan, karena itu terjadi di malam hari), karena mereka menggunakan peta bayangan mengalir - teknik bayangan jarak jauh yang cukup standar untuk penerangan terarah, yang sudah saya jelaskan sebelumnya . Lebih menarik lagi, beberapa sumber proyeksi dan sorotan juga termasuk dalam penangkapan frame ini. Fakta bahwa 8 peta bayangan direkam dalam bingkai ini tidak berarti bahwa hanya ada 8 sumber pencahayaan bayangan bayangan di dalamnya. Gim ini dapat melakukan cache perhitungan bayangan, yaitu pencahayaan yang tidak mengubah posisi sumber atau geometri dalam ruang lingkup seharusnya tidak memperbarui peta bayangannya.


Tampaknya rendering bayangan peta juga mendapat manfaat dari penulisan perintah multi-threaded ke daftar, dan dalam hal ini, sebanyak 19 daftar perintah ditulis untuk membuat peta bayangan.

Bayangan dari pencahayaan terarah

Bayangan dari pencahayaan terarah dihitung sebelum diteruskannya pencahayaan dan kemudian disampel. Saya tidak tahu apa yang akan terjadi jika ada beberapa sumber pencahayaan terarah di tempat kejadian.


Oklusi ambien


Untuk oklusi ambien, ROTR memungkinkan Anda untuk menggunakan HBAO atau varian HBAO + (teknik ini awalnya diterbitkan oleh NVIDIA). Ada beberapa variasi dari algoritma ini, jadi saya akan mempertimbangkan salah satu yang saya temukan di ROTR. Pertama, buffer kedalaman dibagi menjadi 16 tekstur, yang masing-masing berisi 1/16 dari semua nilai kedalaman. Pemisahan dilakukan sedemikian rupa sehingga setiap tekstur mengandung satu nilai dari blok 4 Γ— 4 dari tekstur asli yang ditunjukkan pada gambar di bawah ini. Tekstur pertama berisi semua nilai yang ditandai dengan warna merah (1), yang kedua berisi nilai yang ditandai dengan warna biru (2), dan seterusnya. Jika Anda ingin tahu lebih banyak tentang teknik ini, berikut adalah artikel oleh Louis Bavoil , yang juga merupakan salah satu penulis artikel tentang HBAO.


Langkah selanjutnya menghitung oklusi ambien untuk setiap tekstur, yang memberi kita 16 tekstur AO. Oklusi ambien dihasilkan sebagai berikut: buffer kedalaman disampel beberapa kali, menciptakan kembali posisi dan mengakumulasikan hasil perhitungan untuk masing-masing sampel. Setiap tekstur oklusi ambien dihitung menggunakan koordinat pengambilan sampel yang berbeda, yaitu, dalam blok 4x4 piksel, masing-masing piksel menceritakan bagiannya sendiri dari cerita. Ini dilakukan karena alasan kinerja. Setiap piksel telah mengambil sampel kedalaman buffer 32 kali, dan efek penuh akan membutuhkan 16 Γ— 32 = 512 sampel, yang merupakan bust bahkan untuk GPU paling kuat. Kemudian mereka bergabung kembali menjadi satu tekstur layar penuh, yang ternyata cukup berisik, sehingga untuk memperlancar hasilnya setelah itu, dilakukan blur pass layar penuh. Kami melihat solusi yang sangat mirip di Shadow of Mordor .

gambar

Bagian HBAO

gambar

HBAO penuh dengan kebisingan

gambar

Blur horizontal HBAO penuh

gambar

HBAO siap

Pra-pass pencahayaan ubin


Persiapan Cahaya adalah teknik yang agak tidak biasa. Sebagian besar tim pengembangan menggunakan kombinasi perhitungan pencahayaan langsung + ditangguhkan (dengan variasi, misalnya, dengan ubin, klaster) atau sepenuhnya langsung untuk beberapa efek dari ruang layar. Teknik pra-pencahayaan sangat tidak biasa sehingga layak mendapat penjelasan. Jika konsep pencahayaan yang ditangguhkan tradisional adalah untuk memisahkan sifat-sifat bahan dari pencahayaan, maka gagasan untuk memisahkan pencahayaan dari sifat-sifat material adalah landasan dari bagian awal pencahayaan. Meskipun kata-kata ini terlihat sedikit konyol, perbedaan dari pencahayaan tradisional yang ditangguhkan adalah bahwa kami menyimpan semua sifat material (seperti albedo, warna specular, kekasaran, logam, mikro-oklusi, emisif) dalam buffer-G besar, dan menggunakannya nanti sebagai input data untuk melewati penerangan selanjutnya. Penerangan tradisional yang ditangguhkan dapat menghadirkan beban besar pada throughput; semakin kompleks bahannya, semakin banyak informasi dan operasi diperlukan dalam buffer-G. Namun, dalam izin pencahayaan pendahuluan, pertama-tama kami mengakumulasikan semua pencahayaan secara terpisah, menggunakan jumlah data minimum, dan kemudian menerapkannya pada izin berikutnya pada material. Dalam hal ini, pencahayaan hanya cukup untuk normals, roughness dan metalness. Shader (dua lintasan digunakan di sini) menghasilkan data dalam tiga format render target RGBA16F. Satu berisi pencahayaan difus, yang kedua berisi pencahayaan specular, dan yang ketiga berisi pencahayaan sekitar. Pada titik ini, semua data bayangan diperhitungkan. Sangat mengherankan bahwa pada lintasan pertama (pencahayaan bercermin + cermin) untuk lintasan layar penuh, digunakan quadrangle dua segitiga, dan pada efek lainnya, satu segitiga layar penuh digunakan (mengapa ini penting, Anda dapat menemukannya di sini ). Dari sudut pandang ini, seluruh bingkai tidak terpisahkan.

gambar

Pencahayaan baur

gambar

Pencahayaan Cermin

gambar

Pencahayaan sekitar

Pengoptimalan ubin

Pencahayaan genteng adalah teknik pengoptimalan yang dirancang untuk menghasilkan sejumlah besar sumber cahaya. ROTR membagi layar menjadi 16 Γ— 16 ubin, dan kemudian menyimpan informasi tentang sumber mana yang melintasi setiap ubin, yaitu, perhitungan pencahayaan hanya akan dilakukan untuk sumber-sumber yang terkait dengan ubin tersebut. Pada awal frame, serangkaian shader komputasi diluncurkan, yang menentukan sumber mana yang berhubungan dengan ubin. Pada tahap pencahayaan, setiap piksel menentukan ubin yang ada di dalamnya dan loop melalui setiap sumber cahaya di ubin, melakukan semua perhitungan pencahayaan. Jika sumber ditautkan ke ubin secara efisien, Anda dapat menyimpan banyak perhitungan dan sebagian besar bandwidth, serta meningkatkan produktivitas.

Zoom Kedalaman

Upampling berbasis kedalaman adalah teknik menarik yang berguna dalam operan ini dan selanjutnya. Kadang-kadang algoritma yang mahal secara komputasi tidak dapat dirender pada resolusi penuh, sehingga mereka diberikan pada resolusi yang lebih rendah, dan kemudian ditingkatkan. Dalam kasus kami, pencahayaan sekitar dihitung dalam setengah resolusi, yaitu, setelah perhitungan, pencahayaan harus dibuat kembali dengan benar. Dalam bentuk paling sederhana, 4 piksel resolusi rendah diambil dan diinterpolasi untuk mendapatkan sesuatu yang menyerupai gambar asli. Ini berfungsi untuk transisi yang mulus, tetapi tidak terlihat bagus pada diskontinuitas, karena di sana kami mencampur nilai-nilai yang tidak terkait yang dapat berdekatan dalam ruang layar, tetapi jauh dari satu sama lain di ruang dunia. Dalam solusi untuk masalah ini, beberapa sampel buffer kedalaman biasanya diambil dan dibandingkan dengan sampel kedalaman yang ingin kami buat ulang. Jika sampel terlalu jauh, maka kami tidak memperhitungkannya saat merekonstruksi. Skema semacam itu bekerja dengan baik, tetapi itu berarti bahwa shader rekreasi sangat intensif bandwidth.

ROTR membuat langkah rumit dengan membuang stensil awal. Setelah melewati normals, buffer kedalaman benar-benar penuh, sehingga mesin melakukan operan layar penuh, menandai semua piksel yang terputus dalam buffer stensil. Ketika tiba saatnya untuk menciptakan kembali buffer pencahayaan sekitar, mesin menggunakan dua shader: satu sangat sederhana untuk area tanpa kesenjangan kedalaman, yang lain lebih kompleks untuk piksel dengan celah. Stensil awal membuang piksel jika tidak termasuk wilayah yang sesuai, mis. Ada biaya hanya di wilayah yang diperlukan. Gambar-gambar berikut ini jauh lebih jelas:

gambar

Pencahayaan Ambient Setengah Resolusi

gambar

Menskalakan kedalaman interior

gambar

Pencahayaan ambient resolusi penuh, tanpa tulang rusuk

gambar

Meningkatkan kedalaman tulang rusuk

gambar

Pencahayaan ambient yang siap

gambar

Tampilan setengah resolusi

gambar

Tampilan close-up dari gambar yang dibuat ulang

Setelah bagian awal pencahayaan, geometri dipindahkan ke konveyor, hanya kali ini masing-masing objek sampel tekstur pencahayaan, tekstur oklusi ambien dan sifat-sifat lain dari bahan yang kita tidak menulis ke buffer-G dari awal. Ini bagus, karena bandwidth sangat disimpan di sini karena Anda tidak perlu membaca banyak tekstur untuk menulisnya ke buffer-G besar, kemudian membaca / mendekodekannya lagi. Kelemahan yang jelas dari pendekatan ini adalah bahwa semua geometri perlu ditransmisikan kembali, dan tekstur bagian awal pencahayaan itu sendiri merupakan beban besar pada throughput. Saya bertanya-tanya mengapa tidak menggunakan format yang lebih ringan, misalnya R11G11B10F, untuk tekstur lulus pencahayaan awal, tetapi ada informasi tambahan di saluran alpha, jadi ini tidak mungkin. Bagaimanapun, ini adalah solusi teknis yang menarik. Pada titik ini, semua geometri buram sudah dirender dan menyala. Perhatikan bahwa itu termasuk objek yang memancarkan cahaya seperti langit dan layar laptop.


Refleksi


Adegan ini bukan contoh yang baik untuk menunjukkan refleksi, jadi saya memilih yang lain. Reflektor bayangan adalah kombinasi yang agak rumit dari siklus yang dapat direduksi menjadi dua bagian: satu sampel peta kubik, dan yang lainnya melakukan SSR (Refleksi ruang layar - perhitungan refleksi di ruang layar); semua ini dilakukan dalam satu pass dan pada akhirnya dicampur dengan memperhitungkan koefisien yang menentukan apakah SSR mendeteksi refleksi (mungkin koefisien tersebut bukan biner, tetapi merupakan nilai dalam interval [0, 1]). SSR bekerja dengan cara standar untuk banyak gim - ini berulang kali melacak buffer kedalaman, mencoba menemukan persimpangan terbaik antara sinar yang dipantulkan oleh permukaan yang diarsir dan permukaan lain di layar. SSR bekerja dengan rantai mip dari skala yang sebelumnya dikurangi dari buffer HDR saat ini, dan tidak dengan seluruh buffer.

Ada juga faktor-faktor koreksi seperti kecerahan pantulan, serta tekstur Fresnel yang aneh, yang dihitung sebelum bagian ini, berdasarkan pada normals dan kekasaran. Saya tidak sepenuhnya yakin, tetapi setelah mempelajari kode perakitan, menurut saya ROTR hanya dapat menghitung SSR untuk permukaan yang halus. Mesin tidak memiliki rantai mip blur setelah tahap SSR, yang ada di mesin lain, dan bahkan tidak ada yang seperti melacak buffer kedalaman menggunakan sinar, yang bervariasi berdasarkan kekasaran . Secara umum, permukaan yang lebih kasar menerima pantulan dari peta kubik, atau tidak menerimanya sama sekali. Namun demikian, di mana SSR bekerja, kualitasnya sangat tinggi dan stabil, dengan mempertimbangkan fakta bahwa SSR tidak menumpuk dari waktu ke waktu dan pengaburan spasial tidak dilakukan untuk itu. Data alfa juga mendukung SSR (di beberapa kuil Anda dapat melihat pantulan yang sangat indah di dalam air) dan ini merupakan tambahan yang baik yang tidak sering Anda lihat.

gambar

Refleksi untuk

gambar

Buffer refleksi

gambar

Refleksi sesudahnya

Kabut menyala



Dalam adegan kami, kabut kurang terwakili karena ia menggelapkan latar belakang dan karena itu dibuat oleh partikel, sehingga kami kembali menggunakan contoh dengan refleksi. Kabutnya relatif sederhana, tetapi cukup efektif. Ada dua mode: global, warna umum kabut, dan warna hamburan ke dalam yang diperoleh dari peta kubik. Mungkin peta kubik sekali lagi diambil dari peta refleksi kubik, atau mungkin dibuat baru. Dalam kedua mode, penghalusan kabut diambil dari tekstur penghalusan global, di mana kurva penghalusan dikemas untuk beberapa efek. Dalam skema semacam itu, sungguh luar biasa bahwa kabut ini memberikan kabut yang sangat murah, mis. hamburan perubahan dalam ruang, menciptakan ilusi interaksi kabut dengan pencahayaan jauh. Pendekatan ini juga dapat digunakan untuk hamburan atmosfer dalam di dekat langit.

gambar

Kabut ke

gambar

Kabut setelah

Pencahayaan volumetrik


Pada tahap awal frame, beberapa operasi dilakukan untuk mempersiapkan pencahayaan volumetrik. Dua buffer disalin dari CPU ke GPU: indeks sumber cahaya dan data sumber cahaya. Keduanya dibaca oleh shader komputasi yang menghasilkan tekstur 3D 40x23x16 dari tampilan kamera yang berisi jumlah sumber cahaya yang melintasi area ini. Teksturnya adalah 40 Γ— 23 karena setiap ubin menempati 32 Γ— 32 piksel (1280/32 = 40, 720/32 = 22.5), dan 16 adalah jumlah piksel secara mendalam. Teksturnya tidak termasuk semua sumber cahaya, tetapi hanya yang ditandai sebagai banyak (ada tiga di adegan kami). Seperti yang akan kita lihat di bawah, ada efek volumetrik palsu lainnya yang dibuat oleh tekstur datar. Tekstur yang ditampilkan memiliki resolusi lebih tinggi - 160x90x64. Setelah menentukan jumlah sumber cahaya per ubin dan indeksnya, tiga shader komputasi dieksekusi secara berurutan, melakukan operasi berikut:

  1. Lintasan pertama menentukan jumlah cahaya yang memasuki sel dalam volume dalam bentuk piramida visibilitas. Setiap sel mengakumulasikan pengaruh semua sumber cahaya, seolah-olah mereka memiliki partikel yang bereaksi terhadap cahaya dan mengembalikan sebagiannya ke kamera.
  2. Lintasan kedua mengaburkan pencahayaan dengan radius kecil. Ini mungkin perlu untuk menghindari kedipan saat menggerakkan kamera, karena resolusinya sangat rendah.
  3. Lewat ketiga melewati tekstur volume dari depan ke belakang, secara bertahap menambahkan pengaruh masing-masing sumber dan memberikan tekstur jadi. Bahkan, ini mensimulasikan jumlah total pencahayaan yang masuk sepanjang balok ke jarak tertentu.Karena setiap sel berisi bagian cahaya yang dipantulkan oleh partikel-partikel ke arah kamera, di masing-masingnya kita akan menerima kontribusi gabungan dari semua sel yang sebelumnya dilewati. Bagian ini juga tidak kabur.

Ketika semua ini selesai, kami mendapatkan tekstur 3D yang melaporkan seberapa banyak cahaya yang diterima posisi tertentu dibandingkan dengan kamera. Semua yang masih harus dilakukan dalam bagian layar penuh adalah menentukan posisi ini, menemukan voxel yang sesuai dari tekstur dan menambahkannya ke buffer HDR. Shader pencahayaan itu sendiri sangat sederhana dan hanya berisi sekitar 16 instruksi.

gambar

Volumetrik menyala

gambar

Pencahayaan volumetrik setelah

Rendering rambut


Jika fungsi PureHair tidak diaktifkan, maka lapisan standar rambut diberikan di atas satu sama lain. Solusi ini masih terlihat bagus, tetapi saya ingin fokus pada teknologi terbaru. Jika fungsi ini diaktifkan, frame dimulai dengan simulasi rambut Lara dengan urutan shader komputasi. Bagian pertama dari Tomb Raider menggunakan teknologi yang disebut TressFX, dan dalam sekuel Crystal Dynamics menerapkan teknologi yang ditingkatkan. Setelah perhitungan awal, kami mendapatkan sebanyak 7 buffer. Semuanya digunakan untuk mengendalikan rambut Lara. Prosesnya adalah sebagai berikut:

  1. Luncurkan shader komputasi untuk menghitung nilai gerak berdasarkan posisi sebelumnya dan saat ini (untuk blur gerakan)
  2. 1Γ—1 ()
  3. 122 (Triangle Strip) ( β€” ). , . 7 , . , , . Β« Β».
  4. / quad , , . , , .
  5. 4, ( Β« Β»)

Jika Anda tertarik mempelajari lebih lanjut tentang ini, maka AMD memiliki banyak sumber daya dan presentasi , karena ini adalah perpustakaan umum yang dibuat oleh perusahaan . Saya bingung dengan tahap sebelum tahap 1, di mana draw call yang sama dilakukan seperti pada tahap 3, dikatakan bahwa itu hanya memberikan nilai kedalaman, tetapi sebenarnya isinya tidak dirender, dan ini menarik; mungkin Renderdoc tidak memberitahuku apa-apa. Saya menduga bahwa dia mungkin telah mencoba menjalankan permintaan rendering bersyarat, tetapi saya tidak melihat panggilan prediksi.

gambar

Rambut

gambar

Pixel rambut yang terlihat

gambar

Rambut yang diarsir

Render ubin dari data alfa dan partikel


Objek transparan lagi menggunakan klasifikasi ubin sumber cahaya dihitung untuk lulus pencahayaan awal ubin. Setiap objek transparan menghitung pencahayaannya sendiri dalam satu lintasan, yaitu, jumlah instruksi dan siklus menjadi cukup menakutkan (itulah sebabnya lintasan awal pencahayaan digunakan untuk objek buram). Objek transparan bahkan dapat melakukan pantulan di ruang layar jika dihidupkan! Setiap objek disajikan dalam urutan penyortiran dari belakang ke depan langsung ke buffer HDR, termasuk kaca, api, air bekas, dll. Bagian alfa juga menjadikan tepi disorot ketika Lara berfokus pada beberapa objek (misalnya, botol dengan campuran yang mudah terbakar pada kotak di sebelah kiri).


Akan tetapi, partikel-partikel tersebut dibuat menjadi penyangga setengah-resolusi untuk memperlancar beban yang sangat besar pada bandwidth yang diciptakan oleh pengecatan ulang mereka, terutama ketika banyak partikel besar yang menutupi layar digunakan untuk membuat kabut, kabut, api, dll. Oleh karena itu, penyangga HDR dan penyangga kedalaman berkurang setengahnya di setiap sisi, setelah itu rendering partikel dimulai. Partikel membuat jumlah besar redrawing, beberapa piksel diarsir sekitar 40 kali. Peta panas menunjukkan apa yang saya maksud. Karena partikel-partikel tersebut dibuat dalam resolusi setengah, trik zoom pintar yang sama digunakan di sini seperti pada pencahayaan sekitar (celah ditandai dalam stensil, pass pertama merender ke dalam piksel internal, yang kedua menciptakan kembali tepi). Anda mungkin memperhatikan bahwa partikel menghasilkan beberapa efek alfa lain, seperti nyala api,bersinar, dll. Ini diperlukan agar alpha dapat diurutkan dengan benar relatif terhadap, misalnya, asap. Anda juga dapat melihat bahwa sinar "volumetrik" muncul di sini, berasal dari lampu sorot keamanan. Mereka ditambahkan di sini, dan tidak dibuat pada tahap pencahayaan volumetrik. Ini adalah cara murah namun realistis untuk membuatnya dari jarak jauh.

gambar



gambar

-

gambar

1

gambar

2

gambar

3

gambar


gambar



gambar

-


ROTR melakukan kecepatan rana dan koreksi nada dalam satu lintasan. Namun, meskipun kami biasanya percaya bahwa koreksi gamma terjadi dengan koreksi nada, ini tidak terjadi di sini. Ada banyak cara untuk menerapkan pencahayaan, seperti yang telah kita lihat dengan game lain . Perhitungan pencahayaan dalam ROTR sangat menarik dan hampir tidak memerlukan data perantara atau lintasan, jadi kami akan menjelaskan proses ini secara lebih rinci. Seluruh layar dibagi menjadi 64 Γ— 64 ubin, setelah itu perhitungan kelompok (20, 12, 1) dari 256 aliran di setiap mulai mengisi seluruh layar. Setiap utas pada dasarnya melakukan tugas berikut (pseudo-code disajikan di bawah):

 for(int i = 0; i < 16; ++i) { uint2 iCoord = CalculateCoord(threadID, i, j); // Obtain coordinate float3 hdrValue = Load(hdrTexture, iCoord.xyz); // Read HDR float maxHDRValue = max3(hdrValue); // Find max component float minHDRValue = min3(hdrValue); // Find min component float clampedAverage = max(0.0, (maxHDRValue + minHDRValue) / 2.0); float logAverage = log(clampedAverage); // Natural logarithm sumLogAverage += logAverage; } 

Setiap kelompok menghitung jumlah logaritmik dari semua 64 piksel (256 utas, yang masing-masing memproses 16 nilai). Alih-alih menyimpan nilai rata-rata, ia menyimpan jumlah dan jumlah piksel yang benar-benar diproses (tidak semua grup memproses dengan tepat 64 Γ— 64 piksel, karena, misalnya, mereka dapat melampaui tepi layar). Shader dengan bijak menggunakan penyimpanan utas lokal untuk membagi jumlahnya; masing-masing aliran pertama-tama bekerja dengan 16 nilai horisontal, dan kemudian memisahkan aliran meringkas semua nilai-nilai ini secara vertikal, dan akhirnya aliran kontrol grup ini (aliran 0) menambahkan hasilnya dan menyimpan semuanya ke buffer. Buffer ini berisi 240 elemen, yang pada dasarnya memberi kita kecerahan rata-rata banyak area layar. Perintah berikut memulai 64 utas yang melingkari semua nilai ini dan menambahkannya,untuk mendapatkan kecerahan layar akhir. Ini juga mengembalikan kembali dari logaritma ke unit linier.

Saya tidak punya banyak pengalaman dengan teknik paparan, tetapi membaca posting ini oleh Krzysztof Narkovic mengklarifikasi beberapa hal. Menyimpan ke array 64 elemen diperlukan untuk menghitung rata-rata bergerak, di mana Anda dapat melihat nilai-nilai yang dihitung sebelumnya dan memuluskan kurva untuk menghindari perubahan kecerahan yang sangat tajam, menciptakan perubahan tajam dalam kecepatan rana. Ini adalah shader yang sangat kompleks dan saya masih belum menemukan semua detailnya, tetapi hasil akhirnya adalah nilai kecepatan rana yang sesuai dengan bingkai saat ini.

Setelah menemukan kecepatan rana yang memadai, satu lintasan melakukan kecepatan rana terakhir plus koreksi nada. ROTR tampaknya menggunakan Tonemapping Fotografi, yang menjelaskan penggunaan cara logaritmik alih-alih cara biasa. Formula koreksi tonal dalam shader (setelah paparan) dapat diperluas sebagai berikut:



Penjelasan singkat dapat ditemukan di sini . Saya tidak bisa mencari tahu mengapa pembagian tambahan oleh Lm diperlukan, karena itu membatalkan pengaruh perkalian. Dalam kasus apa pun, whitePoint adalah 1.0, jadi prosesnya tidak banyak membantu dalam bingkai ini, gambar hanya mengubah kecepatan rana. Bahkan tidak ada batas untuk nilai-nilai interval LDR! Itu terjadi selama penilaian warna, ketika kubus warna secara tidak langsung membatasi nilai lebih dari 1.0.

gambar

Paparan terhadap

gambar

Paparan Setelah

Lensa menyala


Suar lensa ditampilkan dengan cara yang menarik. Lulus pendahuluan kecil menghitung tekstur 1xN (di mana N adalah jumlah total elemen silau yang akan dirender sebagai suar lensa, dalam kasus kami ada 28). Tekstur ini berisi nilai alfa untuk partikel dan beberapa informasi lain yang tidak digunakan, tetapi alih-alih menghitungnya dari permintaan visibilitas atau sesuatu yang serupa, mesin menghitungnya dengan menganalisis buffer kedalaman di sekitar partikel dalam lingkaran. Untuk melakukan ini, informasi tentang simpul disimpan dalam buffer yang tersedia untuk pixel shader.


Kemudian setiap elemen diberikan sebagai pesawat rata-rata bidang yang dipancarkan dari sumber cahaya. Jika nilai alfa kurang dari 0,01, maka nilai NaN ditugaskan ke posisi sehingga partikel ini tidak dirasterisasi. Mereka sedikit seperti efek mekar dan menambahkan cahaya, tetapi efek ini sendiri dibuat kemudian.

gambar

Lensa menyala

gambar

Elemen Flare Lensa

gambar

Lensa menyala setelah

Bloom


Bloom menggunakan pendekatan standar: downsampling buffer HDR dilakukan, piksel cerah diisolasi, dan kemudian skalanya ditingkatkan secara berurutan dengan blur untuk memperluas area pengaruhnya. Hasilnya diperbesar ke resolusi layar dan pengomposisian ditumpangkan di atasnya. Ada beberapa poin menarik yang perlu dijelajahi. Seluruh proses dilakukan dengan menggunakan 7 komputasi shader: 2 untuk downsampling, 1 untuk pengaburan sederhana, 4 untuk memperbesar.

  1. target (mip 1). . , mip- , 0.02.
  2. mip mip 2, 3, 4 5.
  3. mip 5. , . , .
  4. β€” . 3 , mip N mip N + 1, , . bloom , .
  5. mip 1 HDR-, bloom.

gambar

Bloom


MIP 1 Bloom


MIP 2 Bloom


MIP 3 Bloom


MIP 4 Bloom

gambar

MIP 5 Bloom


MIP 5 Bloom


MIP 4 Bloom


MIP 3 Bloom

gambar

MIP 2 Bloom


MIP 1 Bloom


Bloom after

Aspek yang aneh adalah bahwa tekstur skala dikurangi mengubah rasio aspek. Demi visualisasi, saya mengoreksi mereka, dan saya hanya bisa menebak alasannya; mungkin ini dilakukan agar ukuran tekstur adalah kelipatan dari 16. Poin menarik lainnya: karena shader ini biasanya sangat terbatas dalam bandwidth, nilai-nilai yang disimpan dalam memori bersama grup dikonversi dari float32 ke float16! Ini memungkinkan shader untuk bertukar operasi matematika untuk menggandakan memori bebas dan bandwidth. Agar ini menjadi masalah, rentang nilai harus menjadi cukup besar.

Fxaa


ROTR mendukung berbagai teknik anti-aliasing yang berbeda, seperti FXAA (Fast Approximate AA) dan SSAA (Super Sampling AA). Perlu dicatat bahwa opsi untuk mengaktifkan AA sementara tidak ada, karena untuk sebagian besar game AAA modern, ini menjadi standar. Meskipun demikian, FXAA mengatasi tugasnya dengan luar biasa, SSAA juga bekerja dengan baik, ini adalah opsi yang agak "berat" jika permainan tidak memiliki kinerja.

Motion blur


Tampaknya Motion blur menggunakan pendekatan yang sangat mirip dengan solusi di Shadows of Mordor. Setelah merender pencahayaan volumetrik, pass rendering yang terpisah menampilkan vektor gerakan dari objek animasi ke buffer gerakan. Kemudian buffer ini dikombinasikan dengan gerakan yang disebabkan oleh kamera, dan buffer gerakan akhir menjadi input ke blur pass, yang melakukan blur ke arah yang ditunjukkan oleh vektor gerakan ruang layar. Untuk memperkirakan radius blur dalam beberapa lintasan, tekstur vektor gerakan pada skala tereduksi dihitung sehingga setiap piksel memiliki gagasan perkiraan tentang jenis gerakan apa yang ada di sekitarnya. Pengaburan dilakukan dalam beberapa lintasan pada resolusi setengah dan, seperti yang kita lihat, kemudian skalanya dengan bantuan stensil meningkat dalam dua lintasan. Beberapa operan dilakukan karena dua alasan: pertama,untuk mengurangi jumlah pembacaan tekstur yang diperlukan untuk membuat blur dengan radius yang berpotensi sangat besar, dan kedua karena berbagai jenis blur dilakukan. Itu tergantung pada apakah karakter animasi itu pada piksel saat ini.

gambar

Gerak kabur ke


Kecepatan Gerak Gerak


Motion Blur Pass 1


Motion Blur Pass 2


Motion Blur Pass 3


Motion Blur Pass 4


Motion Blur Pass 5


Motion Blur Pass 6


Motion Blur, memperbesar dan memperkecil


Motion Blur, tepi zoom

Fitur dan Detail Tambahan


Ada beberapa hal lagi yang layak disebutkan tanpa banyak detail.

  1. Pembekuan kamera: dalam cuaca dingin, tambahkan kepingan salju dan embun beku ke kamera
  2. Kamera Kotor: Menambahkan kotoran ke kamera.
  3. Koreksi warna: di ujung bingkai, koreksi warna kecil dilakukan, menggunakan kubus warna yang cukup standar untuk melakukan koreksi warna, seperti dijelaskan di atas, dan juga menambahkan noise untuk membuat beberapa adegan lebih parah

UI


UI diimplementasikan sedikit tidak biasa - ini membuat semua elemen dalam ruang linear. Biasanya, pada saat rendering, UI sudah melakukan koreksi nada dan koreksi gamma. Namun, ROTR menggunakan ruang linear hingga akhir frame. Ini masuk akal, karena gim ini menggunakan UI 3D yang mengingatkan; namun, sebelum merekam gambar sRGB ke dalam buffer HDR, gambar tersebut harus dikonversi ke ruang linear sehingga operasi terbaru (koreksi gamma) tidak mengubah warna.

Untuk meringkas


Saya harap Anda menikmati membaca analisis ini dengan cara yang sama seperti saya melakukannya. Secara pribadi, saya pasti belajar banyak dari itu. Selamat kepada pengembang Crystal Dynamics yang berbakat atas kerja luar biasa yang dilakukan untuk menciptakan mesin ini. Saya juga ingin berterima kasih kepada Baldur Karlsson untuk karyanya yang luar biasa di Renderdoc. Karyanya membuat men-debug gambar pada PC menjadi proses yang jauh lebih nyaman. Saya pikir satu-satunya hal yang sedikit rumit dalam analisis ini adalah pelacakan peluncuran shader sendiri, karena pada saat penulisan fitur ini tidak tersedia untuk DX12. Saya berharap bahwa seiring waktu akan muncul dan kita semua akan sangat senang.

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


All Articles