[Pemulihan program animasi Henrik Enquist menggambarkan bagaimana timnya menciptakan simulasi jas wol yang menarik dari protagonis thriller horor Alan Wake.]Karakter utama dari action thriller kami adalah Alan Wake, seorang penulis yang jatuh ke dalam mimpi buruk, di mana ia dipaksa untuk bertarung dengan kekuatan gelap dan memecahkan misteri kepergian istrinya. Dia bukan pahlawan aksi yang terlatih, tetapi orang biasa.
Untuk menekankan karakternya, direktur seni kami ingin mendandaninya dengan jaket wol tua dengan tambalan di sikunya. Permainan berlangsung di rombongan dunia nyata, oleh karena itu, tidak seperti permainan fantasi atau penembak ruang, karakter terbatas pada alat yang digunakan. Dan ini berarti bahwa pakaian karakter kita menjadi jauh lebih penting.
Untuk menyampaikan ilusi atmosfer thriller, jaket Alan Wake harus bisa dipercaya semaksimal mungkin. Jaket harus berkibar di angin dan menambahkan gerakan tambahan ke karakter saat bergerak melalui hutan. Sebagai seorang programmer, saya segera mulai berpikir tentang menggunakan simulasi jaringan.
Simulasi kain digunakan di banyak permainan sebelum kita, tetapi teknik yang sering digunakan di sana memberi perasaan sutra atau karet - bahan yang tidak cocok untuk kita. Hanya baru-baru ini sistem simulasi jaringan yang sangat baik dari perusahaan pihak ketiga mulai muncul, tetapi pada saat kami membutuhkan solusi yang stabil, alat-alat seperti itu belum ada, atau mereka tidak memenuhi kebutuhan kami.
Pada artikel ini, saya akan berbicara tentang masalah yang harus kita hadapi, dan tentang solusi untuk membuat simulasi jaringan kita sendiri.
Rig jaket
Jaket dimodelkan bersama dengan sisa karakter seperti jala skinning biasa. Tulang yang mengendalikan jala jaket adalah lapisan terpisah di atas kerangka biasa. Lengan jaket menggunakan pola biasa untuk bahu dan lengan. Baik bahu dan lengan dibagi menjadi satu tulang utama dan satu tulang bengkok. Bagian atas jaket dikontrol oleh kendala penglihatan, dan bagian bawah dikontrol oleh simulasi Verlet.
Gambar 1. Jaket rig di atas kerangka permainan biasa.Jaket atas
Tulang jaket memiliki hierarki yang berjalan dari atas ke bawah (yang lebih rendah adalah anak-anak dari yang atas), jadi ketika tulang atas bergerak, tulang yang lebih rendah mengikutinya. Kami tergoda untuk membuat tulang bawah anak perempuan langsung ke dada, tetapi itu akan menyebabkan hilangnya gerakan, terutama gerakan vertikal, ketika karakter mengangkat bahunya.
Di bagian atas jaket, kami mensimulasikan gerakan bantalan di bahu, menggerakkan tulang pundak dengan bantuan melihat kendala ke arah tulang pundak. Berkat ini, bantalan mengikuti bahu, dan ketika Anda mengangkat tangan, bantalan mengangkat sisa tulang, seperti di jaket sungguhan.
Seperti apa kendala melihat-lihat costraintLihat biaya yang diterapkan pada kerucut merah Tulang berikutnya dalam rantai adalah lapisan antara bagian atas jaket dan bagian bawah yang disimulasikan. Tulang-tulang ini digerakkan langsung oleh kendala penglihatan ke bawah untuk mengimbangi rotasi yang dibuat bahu. Kami juga menambahkan batasan posisi antara tulang kiri dan kanan untuk mengimbangi peregangan yang terjadi ketika bantalan bahu bergerak.
Gambar 2. Gerakan tulang saat mengangkat karakter tangan.Ini bisa cukup untuk menerapkan pembatasan dalam pengekspor animasi dan memanggang hasilnya dalam data animasi, tetapi kami masih mencoba untuk mengontrol tulang-tulang di mesin game secara real time.
Berkat ini, kami dapat menyimpan beberapa byte dalam data animasi, serta dengan mudah mentransfer animasi antar karakter, terlepas dari apakah ada jaket di dalamnya. Selain itu, gerakan bahu yang dihasilkan oleh kinematika terbalik permainan (misalnya, pada saat membidik) ketika menyelesaikan kendala waktu nyata akan diterapkan dengan benar.
Bagian bawah jaket
Setelah menyelesaikan masalah dengan bagian atas jaket, kami melanjutkan untuk mensimulasikan bagian bawah. Sebagian besar game simulasi kain menggunakan satu-ke-satu yang mengikat antara simpul dalam simulasi jaringan dan simpul dari mesh yang diberikan.
Kami ingin menjaga keakuratan jaket agar tidak mengganggu batasan yang ditentukan oleh programmer. Sebagai contoh, jika kami memutuskan untuk menggunakan mesh yang sama untuk simulasi kain seperti untuk rendering, maka siluet kantong dan bagian depan jaket akan hilang.
Peta normal dapat digunakan untuk memberikan volume pada jaket, tetapi kami merasa itu tidak akan cukup. Kami ingin seniman kami membuat model jaket seperti yang mereka inginkan, dan kemudian membiarkan mereka menggunakan peta normal untuk menambahkan lipatan atau detail lainnya, alih-alih mengimbangi hilangnya geometri.
Kami sampai pada keputusan ini: membuat mesh kain resolusi rendah untuk mensimulasikan jaket, dan kemudian menempelkannya pada tulang kerangka yang digunakan untuk mengontrol mesh skinning.
Gambar 3. Perbandingan siluet jaket dan kain kami yang memiliki simpul yang sama dengan simulasi.Fisika Werle
Pertama kita melihat fisika Verlet, dan kemudian kita belajar cara membuat kecocokan untuk simulasi tulang. Verlé Physics saat ini merupakan solusi standar untuk mensimulasikan kain dalam permainan. Jika Anda tidak terbiasa dengan teknik Verlet, maka pertama-tama saya sarankan membaca salah satu artikel ini di Gamasutra:
Iblis dalam Gaun Berwajah Biru: Animasi Kain Real Time atau
Fisika Karakter Tingkat Lanjut .
Gambar 4. Kisi simpul 4x4 dan batasan untuk salah satu simpul.Selebihnya, saya akan mengulangi prinsip kerja secara singkat. Gambar 4 menunjukkan mesh kain dan kendala pegas untuk salah satu simpulnya. Seperti yang dapat Anda lihat dari gambar, setiap simpul jala terhubung ke semua simpul tetangga, serta ke tetangga mereka.
Batasan dari tetangga terdekat disebut stretch stretch dan ditandai dengan warna biru. Batasan panjang yang ditunjukkan dengan warna merah disebut batasan geser / tikungan.
Penting untuk menyimpan pembatasan ini dalam dua grup, karena nanti kita akan menyelesaikannya dengan parameter yang berbeda. Harap dicatat bahwa di jaket kami, baris teratas dari titik-titik kain terikat pada karakter dengan menguliti dan tidak akan dikendalikan oleh simulasi.
Kehadiran mesh mesh bukan persyaratan algoritma itu sendiri, namun, untuk mensimulasikan kain dengan topologi seperti itu, paling mudah untuk bekerja dengannya. Landasan simulasi jaringan terdiri dari dua bagian. Bagian pertama adalah integrasi Verlet, di mana kami menghitung kecepatan untuk setiap titik dan menerapkannya pada posisi.
Vector3 vVelocity = vertex.vCurrentPosition - vertex.vPreviousPosition; vertex.vPreviousPosition = vertex.vCurrentPosition; vertex.vCurrentPosition += vVelocity * ( 1.0f - fDampingFactor ) + vAcceleration * fDeltaTime * fDeltaTime;
Dalam proyek kami,
vAcceleration
ditentukan oleh jumlah gaya gravitasi dan angin. Atenuasi digunakan untuk menyesuaikan tampilan jaket, dan untuk menstabilkan simulasi. Faktor redaman tinggi
fDampingFactor
memberi jaket perasaan kain yang sangat ringan turun perlahan dan mulus, sementara faktor redaman rendah membuat jaket lebih berat, menyebabkannya bergoyang / berosilasi lebih lama setelah gerakan.
Bagian kedua dari algoritma adalah resolusi kendala pegas (proses ini disebut relaksasi). Untuk setiap kendala, kami menarik atau menolak simpul dari satu sama lain sehingga mereka memenuhi panjang aslinya. Berikut ini cuplikan kode yang dapat dibaca.
Vector3 vDelta = constraint.m_vertex1.m_vCurPos - constraint.m_vertex0.m_vCurPos; float fLength = vDelta.length(); vDelta.normalize(); Vector3 vOffset = vDelta * ( fLength - constraint.m_fRestLength ); constraint.m_vertex0.m_vCurrentPosition += vOffset / 2.0f; constraint.m_vertex1.m_vCurrentPosition -= vOffset / 2.0f;
Batasan regangan menahan bagian atas kain bersamaan, dan batasan kemiringan / tekukan membantu mempertahankan bentuk kain. Seperti yang Anda lihat, dengan solusi ideal untuk sistem ini, kain akan bergerak terlalu keras. Itulah sebabnya, sebelum menyelesaikan posisi baru, kami menambahkan koefisien pada batasan kemiringan / tikungan.
vOffset *= fStiffness; constraint.m_vertex0.m_vCurrentPosition += vOffset / 2.0f; constraint.m_vertex1.m_vCurrentPosition -= vOffset / 2.0f;
Dengan koefisien kekakuan 1,0, kain akan menjadi tidak fleksibel, dan pada 0,0, kain akan menekuk tanpa batasan.
Memperbaiki langkah waktu
Anda pasti sudah memperhatikan bahwa integrasi Verlet menunjukkan bahwa langkah waktu sebelumnya persis sama dengan yang saat ini; jika tidak, kecepatan yang dihitung akan salah. Saat menggunakan integrasi Verlet, langkah waktu variabel dapat diabaikan, tetapi resolusi kendala sangat sensitif terhadap perubahan dalam langkah waktu.
Karena pemecah menyelesaikan masalah dengan iteratif menghindari pembatasan, mereka tidak pernah bisa diselesaikan secara ideal. Dalam permainan, ketidaktepatan ini akan memanifestasikan dirinya sebagai peregangan, dan semakin pendek langkah waktunya, semakin sedikit peregangan yang akan dilihat pemain.
Pada akhirnya, ini akan menjadi kompromi antara akurasi dan jumlah waktu prosesor yang dapat Anda habiskan untuk pakaian. Jika langkah waktu tidak konstan, maka peregangan pakaian akan bervariasi, dan kami akan memasukkan getaran yang tidak diinginkan ke dalam sistem. Lebih penting lagi, langkah waktu akan mempengaruhi indikator kekakuan dan parameter kain lainnya: semakin pendek langkah waktu, semakin kaku kain akan, bahkan ketika menggunakan koefisien kekakuan yang sama.
Dalam praktiknya, ini berarti bahwa sebelum Anda mulai menyesuaikan penampilan pakaian dengan bantuan parameter kain, Anda sendiri harus memutuskan langkah waktu yang tetap. Saya tahu bahwa ada permainan di mana langkah waktu variabel digunakan untuk fisika, tetapi pengalaman pribadi saya memberi tahu saya bahwa hidup menjadi lebih mudah ketika langkah waktu diperbaiki untuk fisika dan logika permainan.
Kap mesin
Sebelum kita masuk ke detail simulasi jaringan, mari kita lihat sekilas bagaimana kap disimulasikan. Untuk menguliti bagian atas sungkup, kami menggunakan tulang tambahan. Kami menciptakan pendulum dari tengah tulang ke posisi di belakang kap. Ujung pendulum adalah satu partikel yang dikendalikan oleh fisika Verlet. Kemudian, dengan menggunakan batasan pandang, tulang diarahkan ke pendulum.
Gambar 5. Hood dan pendulum.Membuat matriks tulang
Tudung memberi kami petunjuk tentang apa yang harus dilakukan selanjutnya dengan bagian bawah jaket. Kami akan menggunakan posisi vertex dalam mesh simulasi untuk menghitung transformasi tulang.
Hal pertama yang kita lakukan adalah memetakan tulang sehingga engsel setiap tulang cocok dengan bagian atas jala yang disimulasikan. Karena itu, tugas dari bagian matriks yang terkait dengan perpindahan akan menjadi proses yang sepele.
Maka kita perlu menghitung matriks rotasi 3x3. Setiap baris (atau kolom, tergantung pada konfigurasi matriks) ditentukan oleh sumbu x, y, dan z tulang.
Kami mendefinisikan sumbu x tulang sebagai arah dari simpul dasar ke berikutnya di bawahnya. Kemudian, sumbu y ditentukan oleh vektor dari titik di sebelah kiri ke titik di sebelah kanan.
Gambar 6. Tulang yang menempel pada mesh kain.Pada Gambar 6, sumbu x ditunjukkan dengan warna merah, dan sumbu y ditunjukkan dengan warna hijau. Kemudian, sumbu z dihitung sebagai produk vektor dari vektor-vektor ini. Pada akhirnya, kami juga ortonormalisasi matriks untuk menghilangkan distorsi dalam data perpindahan.
Seperti yang Anda lihat, dalam arah vertikal, kami menggunakan setiap baris dari jalinan kain (kecuali yang terakhir) untuk menyesuaikan tulang, tetapi dalam arah horizontal hanya setiap kolom kedua digunakan. Selain karena memberikan keunggulan artistik seperti dijelaskan di atas, metode ini juga cukup cepat. Berkat ini, teknik skinning tradisional dapat digunakan pada sisi GPU untuk membuat mesh, karena jika tidak kita harus memperbarui buffer vertex dinamis yang besar.
Jala kain dapat memiliki resolusi yang cukup rendah, yang mengurangi beban pada CPU. Satu-satunya biaya tambahan untuk solusi kami adalah untuk mengkonversi simulasi resolusi rendah ke mesh resolusi tinggi, tetapi dalam skema kami biaya ini akan diabaikan dibandingkan dengan sisa simulasi.
Tabrakan
Untuk mengatasi masalah pemangkasan jaringan dengan kaki dan tubuh, kami menggunakan pengenalan tabrakan antara ellipsoid dan sebuah partikel. Gambar 7 menunjukkan ellipsoids yang dibutuhkan untuk menyelesaikan pemotongan jaket oleh model karakter.
Gambar 7. Sistem ellipsoid untuk model Wake.Pengenalan tabrakan ellipsoid dengan partikel sangat cepat. Tabrakan dapat diselesaikan dengan mengubah ruang di mana ellipsoid dan partikel ada, sehingga ellipsoid berubah menjadi bola. Anda kemudian dapat melakukan uji tabrakan cepat pada bola dan partikel.
Dalam praktiknya, ini disertai dengan penciptaan transformasi terbalik berdasarkan nilai-nilai panjang, lebar dan tinggi ellipsoid dengan penerapannya pada posisi partikel. Satu-satunya masalah di sini adalah bahwa tabrakan normal yang kita dapatkan setelah mengkonversi kembali ke sistem koordinat asli terdistorsi.
Kami memutuskan bahwa kami bisa berdamai dengan sedikit ketidakakuratan dalam menghitung arah tumbukan. Dalam kasus di mana ellipsoid yang terentang kuat dapat menyebabkan reaksi yang salah, kami membaginya menjadi dua yang lebih homogen.
Jarak maksimum ke partikel
Masalah lain yang perlu dipecahkan adalah stabilitas jaket. Jaringan selama gerakan cepat dapat menyebabkan pembentukan kelenjar getah bening atau muncul di sisi lain volume tumbukan dan melewati tubuh. Kami memecahkan masalah ini dengan menetapkan jarak yang aman untuk setiap simpul jaringan yang disimulasikan.
Untuk setiap titik, posisi istirahat awal dengan menguliti melekat pada tulang terdekat dan kami menggunakannya sebagai titik referensi. Jika simulasi melebihi nilai ambang batas, maka kita cukup memindahkan titik lebih dekat ke titik referensi. Dalam desain kami, kami membiarkan puncak di bawah bergerak lebih jauh dari puncak lebih dekat ke bahu.
Jarak maksimum yang kita bisa memungkinkan puncak untuk bergerak adalah sekitar 40 cm, ketika nilai ini terlampaui, kasus langka node dan pemotongan mulai muncul. Kami juga mencoba menggunakan teknik lain, misalnya, pesawat bertabrakan, tetapi metode jarak maksimum ternyata yang terbaik. Itu cepat, mudah diatur dan memberikan kebebasan bergerak terbesar sebelum kesalahan yang terlihat mulai muncul dalam jalinan.
Lebih Banyak Tweed, Lebih Sedikit Karet
Sejauh ini, kami telah dapat menemukan cara yang baik untuk mencapai tujuan kami. Artis kami memodelkan jaketnya sesuai keinginannya; untuk menghidupkan jaket, animator tidak diperlukan, karena semuanya disimulasikan dalam permainan, dan prosesor senang bahwa kami memiliki sumber daya yang cukup untuk perhitungan dalam game lainnya. Tapi satu hal yang mengganggu kami - kainnya terlihat seperti karet.
Berjuang Peregangan
Pertama, kita harus menyingkirkan peregangan. Seperti yang saya katakan di atas, fenomena peregangan disebabkan oleh kesalahan yang muncul karena sifat berulang dari algoritma. Ini adalah topik penelitian yang populer dan banyak metode dapat ditemukan untuk menyelesaikan masalah ini.
Sayangnya, semua solusi yang tersedia akan memaksa kita untuk mengalokasikan sumber daya CPU yang jauh lebih langka untuk perhitungan jaringan. Oleh karena itu, kami memecahkan masalah peregangan dengan menambahkan langkah terakhir ke simulasi jaringan, di mana apa yang disebut "kendala keras" diterapkan.
Kami membuat batasan ketat pada batasan regangan (semuanya diarahkan secara vertikal). Pembatasan ini diurutkan dari atas ke bawah sehingga pembatasan di dekat bahu diselesaikan untuk pembatasan di dekat kaki.
Karena kita mengulangi kendala dari atas, kita tahu bahwa simpul atas pada pasangan telah diselesaikan dan tidak menyebabkan peregangan, jadi kita hanya perlu memindahkan simpul bawah ke arah atas. Berkat ini, kita dapat yakin bahwa setelah satu iterasi, panjang dari atas ke bawah akan sama persis dengan panjang saat istirahat.
Vector3 vDelta = constraint.m_vertexTop.m_vCurPos - constraint.m_vertexDown.m_vCurPos; float fLength = vDelta.length(); vDelta.normalize(); Vector3 vOffset = vDelta * ( fLength - constraint.m_fRestLength ); constraint.m_vertexDown.m_vCurrentPosition += vOffset;
Gambar 8. Pembatasan ketat.Seperti yang Anda lihat, kami tidak memperhitungkan peregangan jaket secara horizontal. Tidak mungkin untuk menerapkan batasan ketat pada arah horizontal, karena dalam hal ini titik akan diselesaikan dua kali, yaitu, kita akan kehilangan hasil tahap perhitungan vertikal dan panjang kain tidak akan disimpan saat istirahat.
Namun, kami memperhatikan bahwa dalam kasus jaket, peregangan horizontal sebenarnya tetap tidak terlihat oleh mata manusia, dan karena peregangan vertikal, jaket terlihat sangat buruk. Solusi ini ternyata cukup bagus.
Tepi jaket
Kedua, kami ingin tepi jaket bergerak sedikit lebih dari yang lain. Misalnya, jika Anda menggunakan jaket terbuka lebar, Anda akan melihat bahwa hambatan udara memengaruhi tepi jaket lebih dari bagian tengah. Ini karena tubuh Anda menutupi sisa jaket dari angin.
Tepi dapat dengan mudah ditemukan oleh sejumlah kendala yang melekat padanya. Setiap simpul yang memiliki batasan regangan kurang dari empat adalah tepi. Oleh karena itu, kita dapat menandai simpul ini dan mensimulasikannya dengan parameter lain.
- Redaman yang berkurang.
- Angin global memiliki dampak yang lebih besar.
- Gerakan di ruang dunia memiliki dampak yang lebih besar (untuk lebih banyak tentang pergerakan di ruang dunia, lihat di bawah).
- Jarak aman maksimum yang diizinkan lebih tinggi.
Karena ini, frekuensi internal tepi akan berbeda dari sisa jaket. Sekarang seluruh jaket tidak menanggapi impuls seperti pendulum besar, dan hanya ujung-ujungnya menambahkan gerakan tambahan yang indah untuk gerakan.
Gambar 9. Bagian atas tepi.Gerakan di ruang dunia dan di ruang lokal
Kemudian kami perhatikan bahwa ketika memindahkan karakter, gerakan di ruang dunia memiliki efek yang agak besar pada simulasi, sementara tubuh lokal kecil berubah atau gerakan bahu tidak diperhatikan.
Dalam simulasi jaringan tradisional, posisi simpul disimulasikan di ruang dunia. Seseorang mungkin mengatakan bahwa mensimulasikan kain itu benar, tetapi rasanya tidak wajar. Oleh karena itu, kami mensimulasikan jaket pada karakter di ruang lokal dan secara terpisah menambahkan sedikit gerakan di ruang dunia. Kami memperhatikan bahwa hasil yang kami butuhkan diperoleh dengan animasi kerangka lokal 100% dengan gerakan 10-30% di ruang dunia.
Gesekan
Dan akhirnya, kami ingin melebih-lebihkan kontras antara jaket dalam gerakan lambat dan cepat. Kami ingin jaket menjadi relatif tidak bergerak ketika berjalan, dan ketika Alan melompat atau menghindar, gerakan itu harus lebih hidup.
Kami berpikir bahwa ketika jaket menyentuh tubuh, itu harus bergerak kurang karena gesekan antara jaket dan kemeja, dan ketika jaket naik, itu harus bergerak lebih karena tidak ada yang membatasi itu. Kami mensimulasikan ini dengan menerapkan nilai atenuasi yang meningkat pada setiap titik yang menyentuh ellipsoid. Berkat ini, atasan yang menyentuh tubuh akan tampak agak lengket, menciptakan kontras yang cukup antara jaket dalam situasi normal dan dalam gerakan cepat.
Kesimpulan dan pekerjaan lebih lanjut
Perwujudan pertama simulasi jaringan cukup sederhana untuk diterapkan: kami hanya mencari kata "fabric" dalam literatur pengembangan game dan menerapkan algoritma yang kami temukan. Tahap kedua, di mana kami mencoba untuk mencapai sensasi yang meyakinkan dari jaket wol, membutuhkan studi artikel ilmiah, banyak trial and error, dan bahkan penghapusan bagian dari kode.
Tentu saja, Anda selalu dapat meningkatkan sesuatu. Misalnya, menggunakan simulasi resolusi rendah dan menautkannya ke mesh resolusi tinggi mempersulit solusi untuk masalah semua pemotongan. Kami tidak punya cukup waktu untuk perincian kecil lainnya: misalnya, ini adalah kartu lipatan di tempat lipatan jaket atau penerapan interaksi jaket dan tornado yang benar.
Pada akhirnya, upaya kami terbayar - kain kami sangat berbeda dari simulasi jaringan di game lain. Dia lebih mirip tweed daripada sutra atau karet. Selain itu, sistem kami terbukti sangat fleksibel dan memungkinkan kami untuk mensimulasikan kain lain, misalnya, jaket bawah Barry Wheeler dan kerudung wanita tua itu. Tampaknya dengan menyesuaikan parameter Anda dapat mencapai simulasi dan jenis jaringan lainnya.
Gambar 10. Jaket wol.