Fisika tornado permainan: bagaimana aerodinamika diterapkan di Just Cause 4 (lalu lintas)

Jacques Kerner adalah insinyur perangkat lunak senior di Avalanche Studios.


Seolah-olah permainan itu tidak cukup gila sebelumnya

Pendahuluan


Serial permainan Just Cause dan Avalanche Studios dikenal dengan teknologi dunia-terbuka mereka, memberikan gameplay yang bervariasi dan menarik. Versi terbaru gim ini - Just Cause 4 - menambahkan bencana angin dan cuaca, yang menjadi hal baru dalam tumpukan teknologi yang memperdalam gameplay. Tetapi kondisi lingkungan yang ekstrem pada awalnya disusun tidak hanya sebagai cara untuk mensimulasikan dunia yang lebih dapat dipercaya. Kemarahan alam dikendalikan oleh kekuatan iblis yang menentang Rico Rodriguez. Kami bermaksud membuat angin memanifestasikan dirinya dengan lebih jelas dan kondisi cuaca ekstrem tidak tampak seperti kejadian mendadak yang asing bagi dunia ini. Artikel ini menyajikan teknik yang dikembangkan oleh kami untuk menerapkan angin dalam semua manifestasinya dari sudut pandang fisik, serta reaksi semua objek terhadapnya.

[Di bawah kucing, sekitar 120 MB file GIF]


Badai Tropis JC4 - Konsep Awal (Volta)

Tawaran yang tidak bisa kami tolak


Karena pengembangan Just Cause 3 hampir selesai, sebagian besar tim pindah ke praproduksi Just Cause 4, dan kernel kecil dibiarkan bekerja pada tambalan untuk JC3 dan konten yang dapat diunduh (“DLC”). Hamish Young dan saya, programmer utama dan perancang kendaraan terkemuka, fokus pada Mech Land Assault DLC. Kami seharusnya menjadi perancang fisika terkemuka (dan mekanik pemain) dan programmer perancang fisika JC4, tetapi DLC benar-benar menyerap kami pada saat desain seri waralaba baru sedang dibuat, fitur-fiturnya yang menarik dan fungsi-fungsi penting ditentukan. Kali ini prototipe skala besar diciptakan untuk menguji mekanika dasar baru dan reaksi Rico terhadap angin. Draf plot ditulis, dan penerbit Square Enix menyetujui arah pengembangan awal. Satu-satunya yang tersisa adalah menguasai konsep. Tetapi bagaimana melakukan ini tanpa mengorbankan kinerja? Segera setelah kami memulai proyek, kami menyerang masalah dari dua front: 1. menetapkan batas lebar untuk menghindari skenario terburuk (spoiler: kami tidak berhasil) 2. berurusan dengan berbagai manifestasi dari kondisi cuaca ekstrem, dan khususnya, angin topan, membuat sistem yang memberikan perilaku realistis, tetapi skala baik untuk jumlah dan kepadatan objek yang diinginkan.


Badai Pasir di JC4 - Early Concept Art (Volta)

Kontrol kerusakan


Hambatan dalam simulasi waktu nyata, dan terutama permainan dunia terbuka, adalah jumlah tubuh fisik yang bertabrakan. Biaya utama timbul karena perhitungan tabrakan dari banyak benda yang bergerak bertabrakan satu sama lain dan dengan lingkungan yang statis (bantuan, bangunan). Itu sebabnya mesin fisik seperti Havok memisahkan tubuh aktif dan tidak aktif. Badan aktif diperiksa untuk tabrakan dengan badan lain dan membutuhkan biaya komputasi penuh. Jika bodi aktif tidak bergerak untuk beberapa bingkai, maka mesin fisik menandainya sebagai tidak aktif, dan sejak saat itu ia dapat diabaikan sepenuhnya hingga "dibangunkan" oleh tubuh aktif yang mendekat. Badan tidak aktif seperti itu biasanya bersandar di tanah dan pemeriksaan tabrakan antara mereka dan bumi tidak lagi dilakukan. Jelaslah bahwa kehadiran angin di mana-mana di dunia terbuka akan menjadi ancaman bagi sistem ini, jadi penting bagi kami untuk memastikan bahwa angin tetap moderat dan murni kosmetik ketika terpapar ke area yang luas, atau pengaktifan yang kuat dan fisik ketika terjadi dalam volume kecil dan tempat-tempat di mana kuantitasnya tubuh yang berpotensi aktif kecil. Saya berbicara tentang batasan-batasan ini kepada departemen desain kami pada tahap awal pengembangan sehingga tidak akan terjebak. Pada awalnya, tampaknya para desainer telah mendengarkan dan memutuskan untuk membatasi lintasan peristiwa cuaca ekstrem ke rute kehancuran yang telah ditentukan, di mana aturan yang lebih ketat untuk membangun dunia harus diterapkan. Dan mereka memang mematuhi beberapa pembatasan ini. Tetapi godaan itu terlalu besar, dan tekanan dari rekan-rekan yang ingin membuat permainan sebaik mungkin ternyata tidak dapat diatasi. Apa yang baru saja aku pikirkan? Segera setelah itu, para perancang menciptakan tornado setinggi beberapa kilometer, melewati ibu kota negara itu - bagian pulau yang paling padat penduduknya. Tornado ini dengan berani tidak hanya setengah dari ibukota, tetapi juga beberapa programmer yang tidak curiga yang tidak mematuhi fitur dasar permainan ini terlalu ketat.


Blizzard di JC4 - Early Concept Art (Volta)

Pendekatan umum


Secara umum, fisika cuaca ekstrem di JC4 membutuhkan bahan-bahan berikut:

  • Model tarik aerodinamis diterapkan pada semua objek dinamis dunia, dengan mempertimbangkan bentuk dan ukurannya
  • Sumber angin yang bersesuaian dalam bentuk dan distribusi dengan kondisi cuaca ekstrem (badai, tornado), tetapi juga memberikan pola perambatan angin di seluruh dunia
  • Optimalisasi sistem di atas sehingga game ini cocok dengan anggaran beban komputasi

Ketiga masalah ini perlu dipecahkan secara bersamaan, dan sesegera mungkin. Banyak keputusan desain bergantung pada kemungkinan penerapan ketiga aspek, dan selama bulan-bulan pertama kami merasa tidak puas dengan desainer yang dengan sabar menunggu kesempatan untuk bermain-main dengan sistem dalam skala besar.

Pertama, kami menciptakan model tarik aerodinamis. Setelah selesai, setiap objek tiba-tiba belajar merespons dengan cara yang cukup realistis untuk angin. Misalnya, jika ada benda yang jatuh dari tebing atau terlempar karena ledakan, semua benda melambat dan berputar secara realistis di udara, yang dengan sendirinya sudah sepadan dengan usaha. Tetapi dengan tidak adanya sumber angin, sulit untuk mengatakan bagaimana mereka akan berperilaku dalam kondisi angin yang ekstrem. Meskipun kami bangga dengan diri kami sendiri dan fakta bahwa pengalaman dan intuisi membantu kami dengan cepat menemukan pendekatan untuk dua masalah pertama yang memenuhi persyaratan kinerja, kami memutuskan bahwa kami sangat beruntung ketika versi pertama dari tornado mulai bekerja persis seperti yang kami harapkan. Dia mengangkat semua objek dinamis dan memelintirnya dengan cara yang agak realistis, tanpa menghabiskan waktu prosesor. Direktur JC4 Francesco Antollini, yang sangat sering bertanya tentang situasi tornado, muncul tepat di sebelah stasiun kerja saya dan menyatakan kelegaannya: Saya pikir saya kehilangan kesempatan untuk mempermalukannya karena meragukan saya; tapi sebenarnya aku merasakan hal yang sama.

Dari sudut pandang fisik, JC4 adalah terobosan dibandingkan dengan JC3: itu adalah dunia yang lebih padat, penuh, bersemangat dan indah, yang jauh lebih menarik untuk dihancurkan. Dan semua ini dimungkinkan pada platform target yang sama (XBox One dan PlayStation 4). Tidak mengherankan, pengoptimalan membutuhkan waktu yang sangat lama. Direktur teknis kami Dave Barrett segera mengambil keuntungan dari keunggulan kami: kami memiliki indikator kinerja yang diperlukan untuk JC3, sehingga kepala departemen pengembangan mesin, Daniel Pieroni, diberi tugas untuk menentukan biaya kinerja dan memori maksimum yang dapat digunakan untuk setiap aspek teknis. Kami diberi fisika 8,5 ms murah hati pada 4 utas dari waktu prosesor 33 ms, dialokasikan untuk membuat bingkai dengan frekuensi 30 kali per detik. Havok menempati sebagian besar anggaran ini untuk mengenali kemungkinan tabrakan antara objek, menghitung kontak, menyelesaikan kendala, dan "mengintegrasikan" pergerakan semua badan aktif untuk menentukan posisi mereka setelah 33 ms waktu simulasi. Saya kira-kira menghitung bahwa anggaran kami untuk semua perhitungan yang terkait dengan aerodinamika dan angin harus sekitar 1 ms pada 4 utas. Pada dasarnya, kami berhasil tetap dalam anggaran, walaupun kemungkinan besar lebih baik untuk bertanya kepada Daniel tentang hal ini. Solusi yang disajikan di bawah ini cukup cepat untuk waktu nyata ketika menghitung beberapa ratus objek pada CPU modern. Tentu saja, seperti banyak lagi, dapat lebih dioptimalkan dengan mengadaptasinya untuk bekerja pada GPU.

Di sisa artikel, saya akan secara singkat berbicara tentang bagaimana kami menyelesaikan setiap masalah, dan bagi mereka yang tertarik, saya akan hadir dalam rincian aplikasi dan perhitungan matematis.


Wind in JC4 - Seni Konsep Awal (Ironklad Studios)

Model resistensi


Tujuan kami dalam menciptakan model perlawanan adalah untuk mengevaluasi kekuatan-kekuatan perlawanan dan torsi, yang kira-kira akan menyerupai kekuatan yang diterapkan pada tubuh yang bentuknya sewenang-wenang di dunia nyata. Perhatikan betapa tidak ambisiusnya kami di sini - tidak ada yang menuntut realisme besar. Namun, kami memiliki beberapa persyaratan. Pertama, kekuatan perlawanan harus menetralkan gerakan tubuh. Kedua, gaya harus dihitung dari persamaan dasar tarik aerodinamis, yaitu bervariasi sesuai dengan luas permukaan gambar dan kuadrat kecepatan gerakan di udara. Akhirnya, entah bagaimana bentuk dan ukuran tubuh harus diperhitungkan sehingga benda-benda dengan luas permukaan yang sama tetapi bentuk yang sangat berbeda berperilaku berbeda. Saya tergoda untuk hanya memperkirakan bentuk masing-masing tubuh sesuai dengan jajaran genjang yang menggambarkannya, tetapi saya berpikir bahwa sesuatu yang lebih dibutuhkan, karena itu jelas - bentuk banyak objek dapat berbeda secara signifikan dari sebuah kotak atau bahkan sejumlah kecil kotak. Pengalaman saya sebelumnya bekerja dengan sistem yang secara kasar mendekati volume objek 3D menggunakan voxels atau spheres membuat saya mencari solusi yang lebih baik. Saya ditawari untuk memilih koefisien resistansi untuk setiap objek secara manual, tetapi saya ingin menghindari satu tahap penyesuaian manual dalam pipa yang sudah rumit. Karena itu, saya terus mencari cara otomatis. Dan aku senang aku tidak mundur.

Cara paling sederhana untuk mengevaluasi tekanan angin pada setiap permukaan bentuk tumbukan benda-benda kita adalah dengan hanya memperhitungkan angin yang masuk, mengabaikan semua sirkulasi udara di sekitar benda dan viskositas udara di sekitarnya. Seolah-olah hambatan udara hanya terdiri dari bergerak maju massa udara di depan objek atau penyerapannya di sisi lain. Prototipe awal menunjukkan bahwa metode ini cukup baik untuk tujuan kita.

Masalah “satu-satunya” adalah bahwa jumlah kontribusi dari ribuan segitiga untuk setiap figur individu selama pelaksanaan permainan adalah urutan besarnya lebih tinggi dari tingkat biaya yang diperlukan. Dalam adegan "berat", kita dapat dengan mudah mencapai lebih dari 100.000 wajah. Akan lebih bagus jika kita bisa menghitung kekuatan di muka. Metode pertama dari "brute force" terdiri dalam perhitungan pendahuluan dari gaya aerodinamis dan torsi yang muncul ketika benda bergerak pada kecepatan berbeda di beberapa arah di udara diam ketika berputar pada kecepatan sudut berbeda di arah berbeda. Jadi kami mendapat tabel pencarian dari mana kami bisa mengambil nilai selama pelaksanaan game. Ini dapat dibayangkan sebagai terowongan angin virtual, termasuk selama kompilasi konten kami, di mana kami menempatkan semua objek secara bergantian dan memaparkannya pada kecepatan gerakan atau rotasi yang berbeda, menempatkan setiap objek pada sudut yang berbeda, dan setiap kali mengukur gaya dan torsi.

Akan seperti apa tabel ini? Nilai-nilai yang diketahui pada saat runtime adalah kecepatan linear dan sudut tubuh S=5, yaitu, hanya sekitar 300 KB per objek. Dan tetap saja, ini setidaknya urutan besarnya lebih besar dari konsumsi memori yang diijinkan.

Untuk mengurangi jumlah sampel secara signifikan, saya menggunakan dua teknik. Pertama, saya mengubah perhitungan menjadi bentuk linier menjadi sejumlah kontribusi berdasarkan perhitungan awal gaya dan torsi secara terpisah hanya untuk benda yang bergerak dan hanya berputar. Kedua, saya memperkirakan ini menjadi formula analitis untuk mengekstrapolasi nilai-nilai pada kecepatan arbitrer berdasarkan pada reaksi yang dihitung sebelumnya dan hanya pada kecepatan 1 m / s dan kecepatan 1 rad / s. Ini mengurangi tabel pra-komputasi menjadi hanya 7 KB per objek. Sayangnya, untuk ini saya harus melakukan beberapa perkiraan. Alasan untuk masalah ini adalah bahwa bahkan dengan model resistensi yang sangat sederhana, kita dihadapkan dengan fakta bahwa gaya yang diterapkan pada tubuh, yaitu, rotasi dan perpindahan, bukan hanya jumlah dari gaya yang diterapkan secara terpisah untuk rotasi dan perpindahan. Meskipun saya harus menambahkan perkiraan, saya berhasil menyelamatkan beberapa istilah yang disebabkan oleh kombinasi rotasi ketika bergerak, mirip dengan komponen Coriolis. Kesimpulan dari kata-kata tersebut dapat ditemukan di Lampiran 1. Sebagai hasilnya, alih-alih secara langsung menyimpan gaya dan torsi untuk setiap sampel, kami menyimpan vektor anggota  mathcalA( hatu)digunakan dalam rumus linier. Setiap sampel sesuai dengan kecepatan linier satuan relatif terhadap udara pada 1 m / s atau kecepatan sudut satuan relatif terhadap udara pada 1 rad / s, dalam arah tertentu. Komponen-komponen vektor ini digunakan dalam rumus, yang juga memperhitungkan kecepatan linear dan angular sebenarnya dari objek relatif terhadap udara ketika menghitung gaya dan torsi yang perlu diterapkan pada objek. Lampiran 1 merinci bagaimana ini terjadi.

Untuk menyimpan tabel pencarian, kami menggunakan peta kubus, mis. sebuah kubus yang wajahnya dibagi menjadi kisi-kisi ukuran, katakanlah sel 3x3, seperti kubus Rubik. Kami menyimpan nilai di sudut sel, sehingga setiap wajah dapat menyimpan nilai 4x4. Di setiap sudut sel, kami menghitung vektor dari pusat kubus ke sudut, dan menormalkan vektor ini untuk mendapatkan arah satuan. Kami menggunakan vektor arah unit ini sebagai  mathcalA( hatu)untuk sudut sel. Hasilnya, kami mendapatkan 6 tabel (satu per tepi) dari 16 elemen dengan masing-masing nilai float 19, yang sedikit lebih dari 7 KB, dan ini sangat nyaman. Ada beberapa cara untuk mengurangi jumlah sampel, tetapi dengan metode ini sangat mudah untuk menginterpolasi arah kecepatan sewenang-wenang: karena selalu jatuh ke dalam sel, selalu mungkin untuk menggunakan nilai-nilai di empat sudut sel ini untuk melakukan interpolasi bilinear untuk arah spesifik ini. Teknik peta kubik dan interpolasi bilinear sangat banyak digunakan dalam rendering, sehingga menemukan informasi tentang itu dan kode yang sesuai sangat mudah.


Gambar 1. Peta kubik kecepatan unit relatif terhadap udara. Dalam gambar ini, saya menyoroti merah sel terpisah dari peta kubik untuk menggambarkan prinsip tersebut. Memiliki kecepatan linier  hat omegarelatif terhadap udara, kami kembali mengambil sampel peta kubik yang sama untuk menemukan sel biru dan menggunakan 4 koefisien yang disimpan di sudut-sudutnya. Kemudian kita mencampur semua nilai sesuai dengan rumus dalam Lampiran 1.

Meskipun ini bekerja dalam banyak kasus, kami mengalami kesulitan mengubah pusat massa atau skala objek saat runtime. Solusi kami untuk masalah ini dapat ditemukan di Lampiran 2 dan 3.

Ketika mengembangkan model ini, saya tidak yakin tentang jumlah sampel yang cukup untuk mendapatkan perilaku objek yang baik bergerak dan berputar di udara, jadi saya tidak tahu persis apakah saya memiliki cukup memori pada disk saat runtime. Secara paralel, kami mulai membuat aset penghancuran baru untuk Havok, dengan ratusan fragmen dari berbagai ukuran, terkadang beberapa ratus bagian untuk satu aset. Saya sadar bahwa beberapa aset ini akan membutuhkan jumlah memori yang sama, seperti total aset lainnya, jika masing-masing fragmen memiliki peta kubiknya sendiri. Model umum dengan baik menyampaikan beberapa karakteristik unik dari objek kompleks, tetapi terlalu banyak untuk fragmen kecil. Selain itu, saya tidak yakin tentang biaya saat runtime, dan dapat kembali ke model biaya yang lebih rendah adalah cara yang baik untuk mengurangi risiko. Oleh karena itu, saya menemukan kata-kata yang sangat kompak (membuat perkiraan yang murah hati) hanya berdasarkan kotak objek yang terikat. Itu dapat ditemukan di Lampiran 4.

Volume angin


Kami memperkenalkan konsep volume angin, mendukung gagasan bahwa angin objek yang kuat dan aktif secara fisik hanya dapat terjadi di ruang terbatas, dan mulai mengklasifikasikannya sesuai dengan bentuk dan distribusi angin. Kami membagi volume angin menjadi beberapa jenis utama berikut:

  • Volume angin silinder digunakan untuk badai salju, badai pasir, dan badai tropis
  • Volume angin tornado - satu set vertikal silinder yang berpusat relatif terhadap spline vertikal yang berubah bentuk seiring waktu
  • Terowongan angin terdiri dari beberapa figur berbentuk kapsul yang terhubung (kapsul dengan jari-jari berbeda di ujung yang berbeda), membentuk sesuatu seperti "lubang cacing"

Pembatasan angin oleh volume akhir ini dikritik beberapa kali, dan pada saat terakhir mereka hampir mengabaikannya, menggantinya dengan “angin topografi”. Angin di mana-mana seharusnya sesuai dengan pergerakan awan di atmosfer atas dan memberi pemain aliran udara ke atas saat bertemu dengan kemiringan medan yang meningkat.Kami menerapkannya, tetapi tidak adanya tampilan grafis yang jelas dari angin memaksa kami untuk meninggalkan fungsi ini. Orang-orang dari departemen rendering sudah memiliki terlalu banyak tugas untuk mengimplementasikan awan, sungai, air terjun, meningkatkan ke DirectX 12 dan banyak lagi.

Dalam retrospeksi, ternyata badai menjadi volume angin yang paling sederhana, baik dari segi bentuk (silinder) dan distribusi angin (hampir searah untuk badai pasir, atau berputar di sekitar poros tengah untuk badai salju). Di sisi lain, tornado dan terowongan angin ternyata lebih kompleks dan layak mendapat penjelasan lebih rinci.

Tornado


Kami memiliki gagasan yang jelas dan sederhana tentang bagaimana benda-benda harus berputar di sekitar tornado, tetapi kami tidak setuju pada distribusi angin yang diperlukan untuk mencapai hasil ini. Alih-alih perdebatan tanpa akhir, kami membuat berbagai komponen bidang angin dapat disesuaikan saat runtime sehingga Hamish dapat bereksperimen dengan mereka dan dengan cepat menemukan opsi yang berfungsi. Tornado pada dasarnya adalah tumpukan silinder horizontal yang pusatnya terletak di spline tengah, yang berubah bentuk seiring waktu. Dalam silinder horizontal ini, kami menguraikan medan angin tornado menjadi koordinat silinder dengan komponen tangen, komponen radial, dan komponen vertikal. Setiap komponen dapat disesuaikan menggunakan kurva variabel.


2. — . , , . . , .

Seperti banyak fitur lainnya, dan seperti yang sering terjadi di industri kami, Hamish dan saya sering beralih dari pengaturan ke kode hingga hasilnya cukup baik. Hamish mengutak-atik kurva sesuai dengan keinginannya, melemparkan lusinan kontainer sepanjang 12 meter di sepanjang tornado untuk melihat perilaku mereka. Dia menggunakan kecepatan angin maksimum yang direkam (sekitar 230 mph) untuk tornado. Setelah beberapa waktu, Hamish menemukan bahwa pengaturannya rumit karena itu perlu untuk membuat angin di mana-mana sesuai dengan gerakan rotasi sederhana, tetapi pada saat yang sama menarik benda ke tengah. Kecepatan sudut sudah menjadi bagian dari medan, tidak hanya mendorong, tetapi juga memutar objek dalam tornado. Ini memastikan bahwa, misalnya, objek yang terjebak di tengah akan berputar di tempat, seperti yang kita inginkan.Oleh karena itu, Hamish diminta untuk memulai dengan angin, di mana-mana sesuai dengan kecepatan sudut ini di tengah, yaitu, mulai dengan bidang kecepatan bidang rotasi ideal, ke mana bidang angin kustom dapat ditambahkan. Setelah pengaturan terakhir ini, kurva mulai terdiri dari komponen-komponen berikut:

  • R(d)- faktor komponen radial (gerakan radial)
  • T(d)adalah faktor komponen tangen (gerakan radial)
  • V(d)- faktor komponen vertikal (gerakan radial)
  • H(h)- pengganda komponen horisontal (gerakan vertikal)
  • Φ(h)- faktor komponen vertikal (gerakan vertikal)

Dimana hadalah ketinggian di atas dasar tornado, dand adalah jarak dari pusat. Kecepatan angin tornado diberikan oleh persamaan:

V(d,h)=[VtT(d)H(h)+Ωd]t^+VrR(d)H(h)r^+VuV(d)Φ(h)up^


Ketika benda-benda dipercepat dengan kecepatan singgung tornado pada jarak tertentu, komponen singgung dari pasukan hambatan udara pada dasarnya adalah nol, karena baik udara dan benda bergerak sepanjang tangen secara serempak. Sisa kecepatan angin menarik benda ke dalam, saat planet menarik satelit untuk menekuk lintasannya sehingga tetap berada di orbit; Juga, benda didorong ke atas untuk mencapai ketinggian yang lebih besar. Mendorong objek ke atas adalah optimalisasi kinerja yang paling penting, mencegah perhitungan mahal dari kontak ratusan objek dan bumi. Ini juga membantu bahwa dengan ketinggian tornado itu meningkatkan jari-jari dengan mendistribusikan benda secara spasial untuk mengurangi kemungkinan tabrakan dan perhitungan kontak. Tornado di dunia nyata terbentuk oleh pertukaran udara ketika lapisan udara dingin berada di atas lapisan udara hangat.Udara hangat naik seperti pusaran air di sekitar pusat tornado, yang merupakan udara dingin yang turun. Karena itu, pada prinsipnya, di tengah corong, kecepatan angin harus diarahkan dengan kuat ke bawah. Seperti yang Anda lihat, ini tidak diterapkan di negara kami untuk mengurangi kemungkinan mendorong benda ke tanah dan menariknya ke dalam tornado, jika tidak, ini akan meningkatkan perhitungan tabrakan yang mahal.


3. (), (). Ωdmedan putar angin yang digunakan untuk memulai, agar lebih memahami apakah diperlukan medan tambahan untuk pengoperasian tornado yang benar. Dalam versi di sebelah kanan, bidang yang berputar ditambahkan. Di kejauhan kita melihat angin yang sangat kencang, di titik mana saja yang diarahkan sekitar 45 derajat dari jari-jari. Bagian vertikal di sebelah kiri menunjukkan seberapa besar tornado harus ditarik ke tengah. Lalu ada interval transisi kecil di mana hampir tidak ada angin, dan di belakangnya ada bidang rotasi yang kuat di tengah. Kekuatan medan angin ditunjukkan dalam warna, semakin merah, semakin kuat.


Gambar 4. Garis-garis lintasan di sekitar medan angin tornado - garis tengah garis.

Tornado langsung sepertinya membosankan. Untuk mendeformasi bentuknya, kami menggunakan 2 spline kubik yang dihubungkan oleh ujungnya, 3 titik kontrol di antaranya berada di orbit dan bergerak dengan kecepatan berbeda di sekitar garis vertikal imajiner. Profil tornado yang dihasilkan berubah dari waktu ke waktu, sehingga perlahan-lahan bergeser dari bentuk-S ke bentuk-C, dan sebaliknya. Lampiran 5 merinci bagaimana kami membuat splines. Menariknya, tornado dalam mode bengkok tidak berhasil juga. Benda-benda yang berputar-putar di orbit tornado langsung sekarang tersebar begitu bagian tengah tornado menjauh dari mereka, dan dengan sedih jatuh ke tanah. Untuk memperbaiki masalah ini, kami menambahkan istilah lain ke kecepatan karena deformasi tornado itu sendiri. Pada akhirnya, deformasi ini terutama timbul karena pergerakan udara, dan tampaknya alami bagi kita untuk menambahkan komponen ini. Ini memecahkan masalah dengan indah, memberi kami garis jalan yang sangat mirip dengan gambar di bawah ini.


Gambar 5. Garis-garis jalur di sekitar medan angin tornado - spline tengah membungkuk dari waktu ke waktu


Gambar 6. Contoh tornado dalam game, ia menghancurkan dan menyerap semua yang dilaluinya. Ini adalah Havok Visual Debugger (VDB), alat yang sangat berguna yang memungkinkan kita untuk mengamati elemen yang disimulasikan.

Terowongan angin


Terowongan angin telah dirancang untuk memberikan kontrol angin fisik di beberapa bagian dunia, seperti ngarai dan gua, serta kolom asap di depan penggemar industri besar dan meriam angin. Mereka dapat digunakan untuk memandu pemain di ruang atau misi tertentu. Prototipe pertama kami menggunakan silinder tradisional dengan bidang vektor seragam dengan kecepatan konstan yang sejajar dengan sumbu rotasi silinder. Menempatkan semua silinder ini dalam adegan adalah tugas yang melelahkan, jadi alih-alih kami menggunakan spline Bezier kubik di mana lingkaran dengan berbagai jari-jari direntangkan. Bentuk ini diperkirakan dengan membagi spline pusat menjadi angka berbentuk kapsul, yaitu pada kapsul dengan jari-jari yang berbeda di sekitar tepi. Bidang kecepatan di dalamnya juga telah mengalami beberapa perubahan. Awalnya, angin di terowongan bersinggungan dengan spline pusat. Kami mengatur kecepatan angin di setiap titik kontrol spline, dan mereka diinterpolasi dari satu titik kontrol ke yang lain di sepanjang segmen spline. Namun, Joshua Espinosa (perancang yang mengerjakan terowongan angin dan pergerakan pemain di atasnya) segera mengetahui bahwa ia membutuhkan dua komponen lagi. Salah satu komponen adalah hulu, memberi pemain tumpangan buatan tambahan, selalu mengarah ke atas. Kami menyebut komponen lain "retraksi", itu mendorong pemain ke arah spline tengah, tetapi yang paling utama di tepi terowongan, jatuh ke tengah ke nol. Akhirnya, batas reduksi di bagian luar terowongan memastikan transisi yang mulus dari bagian luar ke bagian luar terowongan. Ketebalan batas ini ditentukan sebagai persentase dari jari-jari; ia bekerja di sepanjang terowongan angin.


Gambar 7. Terowongan angin dibagi menjadi urutan angka berbentuk kapsul yang tumpang tindih. Pemisahan terjadi ketika arah perubahan spline, atau ketika tidak mungkin lagi melakukan interpolasi linear longitudinal dari jari-jari (A) atau kecepatan angin (B). Kami menghitung turunan kedua dari variabel-variabel ini di sepanjang spline untuk menentukan kapan harus membagi.


Gambar 8. Terowongan angin yang diedit di Mesin Apex. Terowongan angin dipecah menjadi kapsul dengan cara yang benar, tergantung pada spline, perubahan dalam radius dan kecepatan angin di sepanjang spline. Seperti yang dinyatakan di bagian berikutnya, Anda juga dapat melihat pemisahan spasial yang mengurutkan sosok berbentuk kapsul menjadi kurva Morton. Perhitungan ini cukup cepat untuk pembaruan waktu nyata; selain itu, Anda dapat dengan cepat berinteraksi dengan terowongan angin untuk mengujinya. Alat pengeditan dibuat dengan mengerjakan ulang beberapa bagian alat pembuatan sungai dengan penambahan rendering debugging.


Gambar 9. Contoh terowongan angin panjang yang memungkinkan pemain untuk bergerak ke hulu ke gunung. Arus sungai mendorong Rick ke laut, dan angin dapat dengan cepat mengembalikannya ke dalam tanah di atas sungai yang sama. Bagian mekanika pemain memperhatikan bahwa angin sisi Rico terlalu tajam, sehingga pengaruh utama angin adalah mempercepat pemain (dengan penarik angin) atau mengerem (menanduk angin) dan memberinya tumpangan tambahan (komponen hulu).


Gambar 10. Rico dalam setelan sayap di terowongan angin yang sama. Di sini pemain tidak mengendalikan arah. Pada awalnya, Rico kehilangan ketinggian sampai mencapai bagian luar terowongan angin, yang secara bertahap memperlambat penurunannya. Kemudian bagian tengah menciptakan aliran ke atas yang cukup untuk mengatasi gravitasi dan dengan cepat mempercepatnya ke ngarai. Kode JC3 Wingsuit untuk interaksi yang tepat dengan angin dikembangkan oleh Joshua Espinosa, Hamish Young dan Rickard Granfeld.

Optimasi permintaan angin


Dengan potensi ratusan badan aktif, menghitung angin lokal di posisi mereka harus menjadi proses yang cepat. Kami mulai mengoptimalkan kueri dengan menghitung AABB (axis aligned box) untuk setiap volume angin dan menyimpannya dalam array yang sangat padat. Ini memungkinkan penolakan kasar karena mungkin untuk dengan cepat memeriksa posisi sehubungan dengan setiap AABB tanpa kehilangan cache. Di setiap frame AABB, volume angin dalam array diperbarui untuk mempersiapkan permintaan.

Jika posisinya di dalam volume badai, maka kita langsung menghitung efek angin menggunakan bentuk silindris. Untuk tornado, Anda perlu melakukan lebih banyak perhitungan, karena di atasnya jauh lebih luas daripada di bagian bawah, sedangkan kepadatan objek tertinggi ada di bagian bawah. Solusi AABB tidak memotong objek dengan sangat baik di dekat tornado, jadi kami menggunakan silinder yang saling bertumpuk. Mereka mentransmisikan bentuk tornado lebih dekat dan digunakan untuk memotong objek sebelum menghitung angin. Optimasi tornado terbaru adalah untuk menghindari memproyeksikan posisi permintaan ke spline pusat. Ini dimungkinkan karena meskipun tornado spline diinterpolasi dalam titik 3D, dan oleh karena itu merupakan kurva 3D parametrik, dalam praktiknya titik kontrol yang diinterpolasi olehnya didistribusikan secara seragam dan berurutan di sepanjang vertikal, yang memberi kita kurva yang cukup sederhana. Secara umum, memproyeksikan titik ke spline 3D atau menemukan titik pada spline dengan ketinggian yang sama memerlukan pencarian di sepanjang spline itu. Tetapi sebagai gantinya, kami memutuskan untuk mengubah cara sampel spline menggunakan ketinggian di atas bagian bawah tornado sebagai parameter pengambilan sampel untuk spline itu sendiri. Ini sedikit mengubah bentuk spline, tetapi spline masih melewati titik interpolasi. Tetapi pada saat yang sama, untuk menemukan titik pada spline pada ketinggian yang sama, ia turun untuk mentransfer ketinggian posisi permintaan ke sana, diikuti dengan memperbaiki ketinggian titik di ketinggian permintaan. Untuk titik kontrol yang terletak tidak rata di sepanjang sumbu vertikal, perbedaannya terlihat, tetapi ketika mereka berada secara merata, ia hampir tidak terlihat. Kita juga bisa mengubah cara kurva pusat dibangun menggunakan fungsi tinggi kubik alih-alih kurva parametrik, tetapi, seperti banyak optimasi lainnya, kurva ini muncul terlambat.

Terowongan angin juga membutuhkan optimasi, karena proyeksi setiap titik kueri pada spline pusat dari setiap terowongan angin bahkan tidak dipertimbangkan. Untungnya, kami berhasil mengambil keuntungan dari teknologi yang secara simultan diterapkan untuk sungai oleh Engin Silasun: database spasial yang jarang. Kami membagi ruang menjadi 32 O( log(n)). Jika sel tidak ada dalam basis data spasial, maka tidak ada angin di titik kueri yang disebabkan oleh terowongan angin. Jika sel ditemukan, maka Anda perlu melakukan pemeriksaan yang lebih mahal. Selain itu, pemeriksaan ini harus cukup cepat, jadi kami memotong terowongan angin menjadi angka berbentuk kapsul. Dalam kasus umum, kapsul digunakan karena dimungkinkan untuk menghitung jarak ke segmen pusat dengan biaya rendah. Angka berbentuk kapsul sedikit lebih mahal, tetapi masih lebih cepat daripada menemukan jarak terpendek ke spline kubik. Properti lain dari sistem terowongan angin spasial holistik adalah bahwa kita dapat mengingat indeks sel dari objek tertentu yang terletak di bingkai sebelumnya dan menggunakannya sebagai petunjuk untuk mempercepat kueri dalam bingkai berikutnya, karena kemungkinan besar itu sudah ada di ini atau tetangga sel.


Gambar 11. Gambar terowongan angin berbentuk kapsul dimasukkan ke dalam basis data spasial yang jarang sesuai dengan sel yang dilintasi. Hasilnya adalah susunan 9 sel, yang masing-masing hanya memiliki beberapa angka berbentuk kapsul.

Kesimpulannya


Kombinasi teknik yang kami gunakan terbukti sangat efektif. Sendiri, teknik ini secara aktif digunakan dalam pemrograman. Sebagian besar pekerjaan terletak pada pilihan mereka dan memastikan kolaborasi yang tepat untuk menyelesaikan masalah saat ini. Ini tipikal untuk pemrograman video game: penuh dengan masalah kecil yang membutuhkan solusi sederhana namun dapat diandalkan.

Model hambatan udara sangat disederhanakan dan tidak mencerminkan beberapa sifat penting dari aliran fluida nyata. Misalnya, selembar dengan sudut 45 derajat akan menghasilkan lebih banyak daya angkat daripada pada model kasar kami. Tetapi hal baiknya adalah bahwa gaya dan torsi tidak dihitung pada saat runtime, dan solusi dengan peta kubik menghindari simulasi yang lebih rinci. Faktanya, kami memeriksa perhitungan gaya dan torsi yang dihasilkan pada seluruh peta kubik dari objek uji (mobil vintage dari JC4) menggunakan perangkat lunak dinamika fluida komputasi sumber terbuka (OpenFOAM). Perbandingan menunjukkan bahwa kami tidak terlalu jauh dari hasil yang benar, tetapi "bentuk" dari peta kubik berbeda, dan saya berharap bahwa itu akan jauh lebih berbeda untuk objek dalam bentuk sayap. Namun, butuh beberapa jam untuk menghitung perangkat lunak, sehingga jelas bahwa solusi seperti itu tidak cocok untuk digunakan pada semua objek. Metode kami membutuhkan waktu kurang dari satu detik per objek. Tetapi saya pikir akan sangat menarik bagi permainan berbasis fisika untuk memiliki koefisien aerodinamika yang cepat, tetapi realistis untuk semua objek. Misalkan Rico bisa mengumpulkan benda-benda di bumerang besar. Saya sempat bermain-main dengan ide ini, menyaksikan jatuh cepat dan rotasi biji helikopter maple, dan menciptakan model di Maya untuk melihat apa yang terjadi. Hasilnya ternyata lebih baik dari yang diharapkan, dan objek itu benar-benar diputar perlahan ketika jatuh. Tetapi bagi saya kelihatannya bahwa untuk rotasi yang lebih cepat akan diperlukan untuk secara signifikan meningkatkan model hambatan udara. Seperti yang sering terjadi, kami tidak punya cukup waktu.


Gambar 12. Kiri: semua orientasi mobil oli vintage dari Just Cause 4, ditempatkan di terowongan angin virtual untuk mengisi peta kubik dengan kisi 5x5 di setiap wajah. Kanan: Paraview memvisualisasikan hasil untuk dua orientasi - pada sudut di atas (di atas) dan di belakang (di bawah). Merah menunjukkan tekanan tinggi, biru menunjukkan tekanan rendah, garis mengindikasikan mengalir.

Tornado dan badai bekerja sangat efektif. Deformasi tornado masih bisa diperbaiki. Jika kita menghabiskan lebih banyak waktu untuk ini, kita mungkin bisa membuat tornado air (tentu saja, dengan hiu bukan sapi), pusaran air atau tornado berapi-api. Kami punya ide lain - untuk mengembangkan meriam yang menciptakan tornado mini.

Terowongan angin telah digunakan di berbagai belahan dunia untuk mengendalikan angin di sebuah pulau, seperti ngarai, misi, di sekitar pangkalan militer. Mereka membantu pemain melintasi bentangan luas dunia terbuka kita dengan angin yang berhembus secara strategis. Tapi saya pikir akan lebih baik menggunakan ide angin topografi, yang kami tidak punya waktu untuk menerapkannya. Akan lebih rasional untuk menerapkannya terlebih dahulu, itu akan memberi kita angin all-meresap sistematis yang hampir tidak memerlukan penyesuaian, dan terowongan angin akan memberikan kontrol lokal atas penyimpangan dari itu.

Dan, akhirnya, itu ide yang logis untuk menggunakan penghalang angin sebagai mekanik game. Kami menerapkan prototipe hambatan yang dapat dimainkan, yang ditunjukkan di dalam tim, tetapi mengabaikannya karena kurangnya waktu untuk implementasi yang benar. Fisika-nya hanyalah sebagian dari total biaya fitur ini, yang seharusnya didukung oleh sebagian besar tim pengembangan.

Tapi tidak ada yang bisa mengalihkan saya dari betapa bangganya saya dengan apa yang kami berhasil lakukan di JC4. Visualisasi kami tentang kondisi cuaca ekstrem dan khususnya tornado, dikombinasikan dengan kemampuan Rico untuk bergerak di ruang angkasa, memungkinkan untuk membuat gameplay yang benar-benar unik dan luar biasa. Saya harap Anda menikmati bermain JC4 seperti yang kami lakukan ketika kami membuatnya.


Lampiran 1: Model Tahan Udara


Kami melihat tubuh  mathcalBdidefinisikan oleh mesh Ti,i in[0,N1].


Gambar 13. Tubuh i in[0,N1].

Pertimbangkan segitiga  vecVi:

 vecVi= vecV+ vec Omega kali vecOCi=Vi  hatvi



Gambar 14. Segitiga dan kecepatan di tengahnya.

Sekarang kita perlu menulis kekuatan elemen  vecFibertindak pada segitiga ini. Di sinilah kita perlu mempertimbangkan persyaratan kita:

 vecFi=Ai Vi ( vecVi cdot hatni)  hatni


Ini sesuai dengan persyaratan, karena gaya hampir selalu diarahkan ke sisi berlawanan dengan arah gerakan, sebanding dengan luas permukaan segitiga dan sebanding dengan kuadrat kecepatan segitiga relatif terhadap udara. Untuk mendapatkan kekuatan yang bekerja pada seluruh tubuh, cukup bagi kita untuk merangkum kekuatan-kekuatan ini:

 vecF= sum vecFi= sumAi Vi ( vecVi cdot hatni)  hatni


Saat kami berusaha mengurangi semuanya menjadi 1 m / s dan 1 rad / s, mari kita menulis ulang  hat omega:

 vecF= sumAi  |V hatv+ Omega hat omega kali vecOCi |(V topiv+ Omega topi omega kali vecOCi) cdot topini  topini


Dan sekarang perkiraan besar pertama:

 |V topiv+ Omega topi omega kali vecOCi | kirakiraV+ Omega | hat omega times vecOCi |


Ini sama dengan mendekati panjang sisi miring sebuah segitiga dengan jumlah panjang kedua sisinya. Perkiraan ini juga dikenal sebagai "jarak blok kota" (jarak Manhattan). Ketika saya mengerjakan tugas ini, saya hanya di Manhattan, jadi bodoh jika tidak menggunakannya. Jadi kami memiliki yang berikut:

 vecF= jumlahAi (V+ Omega | hat omega kali vecOCi |)(V topiv+ Omega hat omega times vecOCi) cdot hatni  hatni


Kami membusuk:

 vecF=V2 sumAi hatv cdot hatni hatni+ Omega2 sumAi | hat omega times vecOCi |( hat omega times vecOCi) cdot hatni hatni+V Omega sumAi( hat omega kali vecOCi) cdot hatni hatni+ OmegaV jumlahAi | hat omega times vecOCi |( hatv cdot hatni) hatni


Pada awalnya, ini mungkin tampak menakutkan. Tapi kemudian Anda perhatikan bahwa inilah yang kami cari. Perhatikan bahwa hanya jumlah yang ditemukan  | hat omega kali vecOCi |dengan nilai rata-rata di antara semua segitiga:

 | hat omega kali vecOCi | approxRatarata( | hat omega kali vecOCi |)i in[0,N1]


Mari kita tandai dengan  hat omega. Sekarang kita akhirnya bisa menulis:

 vecF=V(V+ Omega  overlinevr( hat omega))) vecFt( hatv)+ Omega2 vecFr( hat omega)+V Omega vecFc( hat omega)


dimana:

\ begin {align *} \ vec {F} _t (\ hat {v}) & = \ jumlah {-A_i \ hat {v} \ cdot \ hat {n} _i \ \ hat {n} _i} \\ \ vec {F} _r (\ hat {\ omega}) & = \ jumlah {-A_i \ | \ hat {\ omega} \ kali \ vec {OC_i} \ | (\ hat {\ omega} \ kali \ vec { OC_i}) \ cdot \ hat {n} _i \ \ hat {n} _i} \\ \ vec {F} _c (\ hat {\ omega}) & = \ jumlah {-A_i (\ hat {\ omega} \ kali \ vec {OC_i}) \ cdot \ hat {n} _i \ \ hat {n} _i} \\ \ overline {v_r} (\ hat {\ omega}) & = {1 \ lebih dari N} \ jumlah {\ | \ hat {\ omega} \ kali \ vec {OC_i} \ | } \ end {align *}


Momen kekuatan ini relatif ke titik Oodapat diperoleh dengan cara yang serupa. Dan sebagai hasilnya, kami mendapatkan yang berikut:

 kiri. vecM kanan|O( hatv, hatw)=V(V+ Omega  overlinevr( hat omega)) vecMt( hatv)+ Omega2 vecMr( hat omega)+V Omega vecMc( hat omega)


dimana:

\ begin {align *} \ vec {M} _t (\ hat {v}) & = \ jumlah {-A_i \ hat {v} \ cdot \ hat {n} _i \ (\ vec {OC_i} \ kali \ hat {n} _i)} \\ \ vec {M} _r (\ hat {\ omega}) & = \ jumlah {-A_i \ | \ hat {\ omega} \ kali \ vec {OC_i} \ | (\ hat {\ omega} \ times \ vec {OC_i}) \ cdot \ hat {n} _i \ (\ vec {OC_i} \ kali \ hat {n} _i)} \\ \ vec {M} _c (\ hat {\ omega}) & = \ jumlah {-A_i (\ hat {\ omega} \ kali \ vec {OC_i}) \ cdot \ hat {n} _i \ (\ vec {OC_i} \ kali \ hat {n} _i)} \ end {align *}


Dengan definisi di atas, kita sekarang dapat membentuk vektor  mathcalA( hatu):

 mathcalA( hatu)= beginbmatrix vecFt( hatu) vecFr( hatu) vecFc( hatu) vecMt( hatu) vecMr( hatu) vecMc( hatu) overlinevr( hatu) endbmatrix


Ini adalah vektor dari 19 nilai dan kami merujuk ke tabel sampel  hatw, tetapi kita dapat menemukan nilai yang cukup dekat, dan kemudian menggunakannya secara langsung, atau menggunakannya untuk menginterpolasi output. Dan pada tahap ini, peta kubik yang dijelaskan dalam artikel mulai berlaku.

Lampiran 2: pusat massa


Anda mungkin memperhatikan bahwa nilai yang ditunjukkan di atas dihitung relatif terhadap titik arbitrer Pi. Total kekuatan yang bekerja pada tubuh hanyalah jumlah dari semua kekuatan:

 vecF= jumlah vecfi



Momen Oditetapkan sebagai:

 kiri. vecmi kanan|O= vecOPi kali vecfi


dan momen total dari kekuatan-kekuatan ini relatif ke titik Osama dengan:

M|O=mi|O=OPi×fi


Sekarang ini hanya definisi matematis, sebuah formula yang tidak dapat digunakan secara langsung untuk mengubah gerakan tubuh, karena pusat gravitasi Gdalam rumus ini, menurut teorema Schall, sama dengan:

M|O=(OG+GPi)×fi=OG×fi+GPi×fi


Kami mengenali momen kekuatan sehubungan dengan F, oleh karena itu:

M|O=OG×F+M|G


Dan itu sangat berguna bagi kita jika kita menghitung kekuatan totalnya Ftidak berubah dan menerapkan torsi berikut ke pusat massa:

M|G=M|O+GO×F


Pada awalnya, saya memutuskan untuk mengambil asal usul tubuh sebagai suatu poin Odi tengah jajaran genjang tubuh yang terikat, yang masih harus dekat dengan pusat massa dan pengambilan sampel angin lokal di tempat yang paling logis relatif terhadap tubuh.

Lampiran 3: Penskalaan


Kelemahan lain muncul ketika balon dimasukkan ke dalam permainan. Bola-bola ini adalah benda-benda berbentuk bola, yang ukurannya dapat bervariasi dengan faktor 5 atau 10. Seperti halnya pada pusat massa, terlalu mahal untuk menghitung ulang sifat aerodinamik pada waktu berjalan. Apakah mungkin untuk mendapatkan formula analitik?


Gambar 15 Tubuh OsCsi=s OCi

Pertimbangkan kembali tubuh Ftapi sekarang untuk objek berskala. Kami mendapatkan:

Fs=V2Aiv^n^in^i+Ω2Aiω^×OCsi(ω^×OCsi)n^in^i+VΩAi(ω^×OCsi)n^in^i+ΩVAiω^×OCsi(v^n^i)n^i


Menggunakan perkiraan yang sama seperti pertama kali, dan mengganti s OCikami mendapatkan:

Fs=V(Vs2+Ωs3 vr¯(ω^))Ft(v^)+Ω2s4Fr(ω^)+VΩs3Fc(ω^)


Untuk pusat massa tubuh bersisik Gs.

Lampiran 4: Model Perlawanan Sederhana untuk Paralelogram


Ada banyak cara untuk memperkirakan gaya dan torsi untuk jajar genjang, dan berbagai formula dapat diperoleh. Cukup ringkas, mudah diimplementasikan dalam kode dan perhitungan saat runtime, dapat disimpulkan dengan mengabaikan efek gerak sudut pada gaya linier dan efek kecepatan linier pada torsi. Mengambil ukuran jajar genjang yang mengikatez , kita bisa sampai pada rumus ringkas berikut:

F=ρV2eyez,exez,exeyv^


M=ρ6Ω2exeyezw^ey2+ez2,ex2+ez2,ex2+ey2


Lampiran 5: Tornado Center Spline


Tornado berpusat di sekitar kurva pusat yang bentuknya perlahan berubah. Kami menerapkan ini menggunakan dua spline kubik Bezier berturut-turut:C0 untuk bagian bawah dan C1untuk bagian atas. SplineC0 memiliki titik kontrol P0, P1, P2dan P3, dan C1dikontrol oleh poin P4, P5, P6dan P7. Posisi tornado itu sendiri ada di suatu titik P0di tanah dan titik tertinggi P7Itu dimulai tepat di atas tingkat lapisan awan, tetapi terlambat, perlahan-lahan mengikuti posisi di bumi. Karena kurva terhubung di satu ujung,P3 dan P4bertepatan di ruang angkasa. Kami juga menggunakan 3 orbit referensi horisontal untuk poinP1 , P2dan P5. Akhirnya P3terletak persis di titik tengah antara P2dan P5, dan P6di titik tengah antara P5dan P7.

Membuat spline tengah tornadoTornado pusat evolusi spline dalam waktu

Referensi


  1. Hanya karena 4
  2. Havok
  3. Yayasan Struktur Data Multidimensi dan Metrik . Hanan samet
  4. Kurva Z-order
  5. Pemetaan kubus
  6. Buka busa
  7. Volta
  8. Studio Ironklad

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


All Articles