Manipulasi Real-time dari Meshes on Unity

gambar

Salah satu keunggulan Unity sebagai platform untuk pengembangan game adalah mesin 3D-nya yang kuat. Dalam tutorial ini, Anda akan belajar tentang dunia objek 3D dan manipulasi mesh.

Karena pertumbuhan teknologi virtual dan augmented reality (VR / AR), sebagian besar pengembang dihadapkan dengan konsep kompleks grafis 3D. Biarkan tutorial ini menjadi titik awal bagi mereka. Jangan khawatir, tidak akan ada matematika 3D yang rumit - hanya hati, gambar, panah, dan banyak hal menarik!

Catatan: tutorial ini ditujukan untuk pengguna yang terbiasa dengan Unity IDE dan memiliki beberapa pengalaman pemrograman dalam C #. Jika Anda tidak memiliki pengetahuan seperti itu, maka pertama-tama pelajari tutorial Pengantar UI Unity dan Pengantar Script Unity .

Anda membutuhkan versi Unity tidak lebih rendah dari 2017.3.1. Versi terbaru dari Unity dapat diunduh di sini . Tutorial ini menggunakan editor khusus, dan Anda dapat mempelajari lebih lanjut tentang mereka dari tutorial Memperluas Editor Persatuan .

Mulai bekerja


Untuk memulai, berkenalanlah dengan istilah dasar grafik 3D, yang akan memungkinkan Anda untuk lebih memahami tutorial.

Persyaratan teknis dasar grafik 3D:

  • Verteks : Setiap titik adalah titik dalam ruang 3D.
  • Mesh : berisi semua simpul, tepi, segitiga, normal, dan data UV model.
  • Filter Mesh : menyimpan data model mesh.
  • Mesh Renderer : Membuat data mesh dalam adegan.
  • Normals : Vektor dari suatu vertex atau permukaan. Ini diarahkan ke luar, tegak lurus ke permukaan mesh.
  • Garis / Tepi : Garis tak terlihat yang menghubungkan simpul satu sama lain.
  • Segitiga : dibentuk dengan menghubungkan tiga puncak.
  • Peta UV : Melampirkan material ke suatu objek, menciptakan tekstur dan warna untuknya.

Anatomi objek 3D dimulai dengan mesh-nya. Penciptaan jala ini dimulai pada puncaknya. Garis tak terlihat yang menghubungkan simpul-simpul ini membentuk segitiga yang menentukan bentuk dasar objek.


Kemudian data normals dan UV mengatur naungan, warna dan tekstur. Data mesh disimpan dalam filter mesh, dan mesh renderer menggunakan data ini untuk menggambar objek di tempat kejadian.

Artinya, pseudocode untuk membuat model 3D terlihat seperti ini:

  • Buat jaring baru yang disebut "myMesh".
  • Tambahkan data ke properti verteks dan segitiga myMesh.
  • Buat filter mesh baru yang disebut "myMeshFilter".
  • Atur properti mesh myMeshFilter ke myMesh.

Setelah Anda menguasai dasar-dasarnya, unduh proyek , unzip file, dan jalankan benda kerja proyek di Unity. Lihatlah struktur folder di jendela Proyek :


Deskripsi folder:

  • Rak itan : berisi prefab Sphere yang akan digunakan untuk menyimpan jala 3D selama eksekusi aplikasi.
  • Adegan : berisi tiga adegan yang kami gunakan dalam tutorial ini.
  • Editor : skrip di dalam folder ini memberi kami fitur super di editor yang kami gunakan dalam pengembangan.
  • Skrip : di sini adalah skrip run-time yang melampirkan GameObject dan mengeksekusi ketika Anda mengklik Play .
  • Bahan : folder ini berisi materi untuk mesh.

Di bagian selanjutnya, kita akan membuat editor khusus untuk memvisualisasikan pembuatan jala 3D.

Ubah jala dengan Editor Kustom


Buka Demo Studi 01 Mesh yang terletak di folder Adegan . Di jendela adegan , Anda akan melihat kubus 3D:


Sebelum kita masuk ke mesh, mari kita lihat skrip editor khusus.

Mengedit skrip editor


Pilih folder Editor di jendela Proyek . Skrip dalam folder ini menambahkan fungsionalitas ke editor (Editor) selama pengembangan dan tidak tersedia dalam mode Build.


Buka MeshInspector.cs dan lihat kode sumber. Semua skrip Editor harus mengimplementasikan kelas Editor , atribut CustomEditor memberi tahu kelas Editor untuk objek apa objek itu. OnSceneGUI() adalah metode acara yang memungkinkan rendering di jendela Scene; OnInspectorGUI() memungkinkan Anda untuk menambahkan elemen GUI tambahan ke Inspektur.

Di MeshInspector.cs, sebelum memulai kelas MeshInspector tambahkan berikut ini:

 [CustomEditor(typeof(MeshStudy))] 

Penjelasan Kode: Atribut CustomEditor memberi tahu Unity jenis objek yang dapat diubah oleh kelas editor kustom.

Di OnSceneGUI() sebelum EditMesh() tambahkan berikut ini:

 mesh = target as MeshStudy; Debug.Log("Custom editor is running"); 

Penjelasan kode: Kelas Editor memiliki variabel target standar. Di sini, target adalah konversi ke MeshStudy . Sekarang editor khusus akan menggambar semua GameObjects di jendela Scene dan MeshStudy.cs terlampir. Menambahkan pesan debug memungkinkan Anda memverifikasi di konsol bahwa editor khusus benar-benar berjalan.

Simpan file dan kembali ke Unity. Buka folder Script dan seret MeshStudy.cs ke GameObject Cube di Hierarchy untuk melampirkannya.


Sekarang pesan "Editor kustom sedang berjalan" harus ditampilkan di konsol, dan ini berarti bahwa kami melakukan semuanya dengan benar! Anda dapat menghapus pesan debug agar tidak mengganggu kami di konsol.

Mengkloning dan membuang mesh


Saat bekerja dengan jala 3D dalam mode Edit menggunakan editor khusus, berhati-hatilah untuk tidak menimpa jala Unity default. Jika ini terjadi, Anda harus memulai ulang Unity.

Untuk mengkloning jala dengan aman tanpa menimpa bentuk asli, buat salinan jala dari properti MeshFilter.sharedmesh dan tetapkan ke filter jala lagi.

Untuk melakukan ini, klik dua kali pada MeshStudy.cs di folder Scripts untuk membuka file di editor kode. Script ini mewarisi dari kelas MonoBehaviour , dan fungsi Start() tidak dijalankan dalam mode Edit.

Di MeshStudy.cs, sebelum memulai kelas MeshStudy tambahkan berikut ini:

 [ExecuteInEditMode] 

Penjelasan kode: setelah menambahkan atribut ini, fungsi Start() akan dieksekusi baik dalam mode Putar dan dalam mode Edit. Sekarang kita dapat instantiate objek mesh pertama dan mengkloningnya.

Di InitMesh() tambahkan kode berikut:

 oMeshFilter = GetComponent<MeshFilter>(); oMesh = oMeshFilter.sharedMesh; //1 cMesh = new Mesh(); //2 cMesh.name = "clone"; cMesh.vertices = oMesh.vertices; cMesh.triangles = oMesh.triangles; cMesh.normals = oMesh.normals; cMesh.uv = oMesh.uv; oMeshFilter.mesh = cMesh; //3 vertices = cMesh.vertices; //4 triangles = cMesh.triangles; isCloned = true; Debug.Log("Init & Cloned"); 

Penjelasan Kode:

  1. Mendapat jala oMesh asli dari komponen MeshFilter .
  2. Salin cMesh ke cMesh mesh baru.
  3. Menetapkan filter jala yang disalin lagi.
  4. Memperbarui variabel lokal.

Simpan file dan kembali ke Unity. Pesan "Init & Kloning" harus ditampilkan di konsol debug. Pilih GameObject Cube di Hierarchy dan periksa propertinya di Inspektur . Filter Mesh harus menampilkan aset mesh yang disebut clone . Hebat! Ini berarti bahwa kami telah berhasil mengkloning jala.


Di folder Editor, navigasikan ke MeshInspector.cs . Di OnInspectorGUI() , setelah baris kode kedua, tambahkan berikut ini:

 if (GUILayout.Button("Reset")) //1 { mesh.Reset(); //2 } 

Penjelasan Kode:

  1. Kode ini menarik tombol Reset di Inspektur .
  2. Saat ditekan, ia memanggil fungsi Reset() di MeshStudy.cs .

Simpan file, buka MeshStudy.cs dan tambahkan kode berikut ke fungsi Reset() :

 if (cMesh != null && oMesh != null) //1 { cMesh.vertices = oMesh.vertices; //2 cMesh.triangles = oMesh.triangles; cMesh.normals = oMesh.normals; cMesh.uv = oMesh.uv; oMeshFilter.mesh = cMesh; //3 vertices = cMesh.vertices; //4 triangles = cMesh.triangles; } 

Penjelasan Kode:

  1. Memverifikasi keberadaan sumber dan kloning jala.
  2. Setel ulang cMesh ke mesh asli.
  3. Tugas untuk cMesh oMeshFilter .
  4. Memperbarui variabel lokal.

Simpan file dan kembali ke Unity. Di Inspektur, klik tombol Edit Tes untuk mendistorsi jaring kubus. Selanjutnya, klik tombolReset ; kubus harus kembali ke bentuk aslinya.


Penjelasan simpul dan segitiga di Unity


Jaring terdiri dari simpul-simpul yang dihubungkan oleh tepi-tepi dalam segitiga. Segitiga menentukan bentuk dasar objek.

Kelas Jala:

  • Verteks disimpan sebagai array nilai Vector3 .
  • Segitiga disimpan sebagai array integer yang sesuai dengan indeks array verteks.

Yaitu, dalam Quad mesh sederhana, yang terdiri dari empat simpul dan dua segitiga, data mesh akan terlihat seperti ini:


Pemetaan vertex


Di sini kita ingin menampilkan simpul kubus sebagai titik biru.

Di MeshInspector.cs kita akan masuk ke fungsi EditMesh() dan tambahkan yang berikut:

 handleTransform = mesh.transform; //1 handleRotation = Tools.pivotRotation == PivotRotation.Local ? handleTransform.rotation : Quaternion.identity; //2 for (int i = 0; i < mesh.vertices.Length; i++) //3 { ShowPoint(i); } 

Penjelasan Kode:

  1. handleTransform mendapat nilai Transform dari mesh .
  2. handleRotation mendapatkan mode Rotasi dari sambungan saat ini.
  3. ShowPoint() simpul jaring dan gambar titik menggunakan ShowPoint() .

Dalam fungsi ShowPoint() , segera setelah //draw dot comment, tambahkan berikut ini:

 Vector3 point = handleTransform.TransformPoint(mesh.vertices[index]); 

Penjelasan Kode: Baris ini mengubah posisi lokal titik menjadi koordinat di ruang dunia.

Dalam fungsi yang sama, di blok if , segera setelah baris kode baru saja ditambahkan, tambahkan berikut ini:

 Handles.color = Color.blue; point = Handles.FreeMoveHandle(point, handleRotation, mesh.handleSize, Vector3.zero, Handles.DotHandleCap); 

Penjelasan Kode:

  1. Mengatur warna, ukuran, dan posisi suatu titik menggunakan kelas Penolong Handles .
  2. Handles.FreeMoveHandle() menciptakan manipulator gerakan tanpa batas yang menyederhanakan operasi seret dan lepas, yang berguna bagi kita di bagian selanjutnya.

Simpan file dan kembali ke Unity. Periksa properti kubus di Inspektur dan pastikan opsi Pindahkan Titik Titik diaktifkan. Anda sekarang harus melihat bahwa jala di layar ditandai dengan beberapa titik biru. Inilah mereka - bagian atas jala kubus! Coba lakukan ini dengan objek 3D lainnya dan amati hasilnya.


Pindahkan satu titik


Mari kita mulai dengan langkah paling sederhana memanipulasi mesh - memindahkan satu titik.

Pergi ke MeshInspector.cs . Di dalam fungsi ShowPoint() , tepat setelah //drag comment dan tepat sebelum tanda kurung blok if , tambahkan berikut ini:

 if (GUI.changed) //1 { mesh.DoAction(index, handleTransform.InverseTransformPoint(point)); //2 } 

Penjelasan Kode:

  1. GUI.changed melacak semua perubahan yang terjadi dengan titik, dan bekerja dengan baik bersama dengan Handles.FreeMoveHandle() untuk mengenali operasi seret dan lepas.
  2. Untuk simpul yang dapat diseret, fungsi mesh.DoAction() menerima indeks dan nilai Transform sebagai parameter. Karena nilai Transform dari vertex berada di ruang dunia, kami mengonversinya ke ruang lokal menggunakan InverseTransformPoint() .

Simpan file skrip dan pergi ke MeshStudy.cs . Di DoAction() , setelah tanda kurung buka, tambahkan berikut ini:

 PullOneVertex(index, localPos); 

Kemudian tambahkan berikut ini ke fungsi PullOneVertex() :

 vertices[index] = newPos; //1 cMesh.vertices = vertices; //2 cMesh.RecalculateNormals(); //3 

Penjelasan Kode:

  1. Kami memperbarui vertex target dengan nilai newPos .
  2. cMesh.vertices nilai titik yang diperbarui kembali ke cMesh.vertices .
  3. Di RecalculateNormals() menghitung ulang dan menggambar ulang jala sehingga cocok dengan perubahan.

Simpan file dan kembali ke Unity. Coba seret poin pada kubus; apakah Anda melihat jala yang rusak?


Tampaknya beberapa simpul memiliki posisi yang sama, jadi ketika kita menyeret hanya satu, simpul yang tersisa tetap berada di belakangnya, dan jala putus. Di bagian selanjutnya, kami akan memperbaiki masalah ini.

Menemukan semua simpul serupa


Secara visual, mesh kubus terdiri dari delapan simpul, enam sisi, dan 12 segitiga. Mari kita periksa apakah ini benar.


Buka MeshStudy.cs , lihat di depan fungsi Start() dan cari variabel vertices . Kita akan melihat yang berikut ini:

 [HideInInspector] public Vector3[] vertices; 

Penjelasan Kode: [HideInInspector] menyembunyikan variabel yang dibagi dari jendela Inspektur .

Komentar atribut ini:

 //[HideInInspector] public Vector3[] vertices; 

Catatan: menyembunyikan nilai titik membantu [HideInInspector] dengan jerat 3D yang lebih kompleks. Karena ukuran array vertex dapat mencapai ribuan elemen, ini dapat menyebabkan penghambatan Persatuan ketika mencoba untuk melihat nilai array di Inspektur.

Simpan file dan kembali ke Unity. Pergi ke Inspektur . Sekarang, di bawah komponen skrip Studi Mesh , properti simpul telah muncul. Klik ikon panah di sebelahnya; sehingga Anda Vector3 array elemen Vector3 .


Anda dapat melihat bahwa ukuran array adalah 24, yaitu, ada simpul yang memiliki posisi yang sama! Sebelum melanjutkan, pastikan untuk [HideInInspector] komentar [HideInInspector] .

Mengapa ada 24 simpul?
Ada banyak teori tentang hal ini. Tetapi jawaban yang paling sederhana adalah: kubus memiliki enam sisi, dan setiap sisi terdiri dari empat simpul yang membentuk sebuah bidang.

Oleh karena itu, perhitungannya adalah sebagai berikut: 6 x 4 = 24 simpul.

Anda dapat mencari jawaban lain. Tetapi untuk sekarang, cukup sederhana untuk mengetahui bahwa beberapa jerat akan memiliki simpul yang memiliki posisi yang sama.

Di MeshStudy.cs, ganti semua kode di dalam fungsi DoAction() dengan yang berikut:

 PullSimilarVertices(index, localPos); 

Mari kita PullSimilarVertices() ke fungsi PullSimilarVertices() dan tambahkan yang berikut:

 Vector3 targetVertexPos = vertices[index]; //1 List<int> relatedVertices = FindRelatedVertices(targetVertexPos, false); //2 foreach (int i in relatedVertices) //3 { vertices[i] = newPos; } cMesh.vertices = vertices; //4 cMesh.RecalculateNormals(); 

Penjelasan Kode:

  1. kita mendapatkan posisi vertex target, yang akan digunakan sebagai argumen ke metode FindRelatedVertices() .
  2. Metode ini mengembalikan daftar indeks (sesuai dengan simpul) yang memiliki posisi yang sama dengan simpul target.
  3. Loop melewati seluruh daftar dan mengatur simpul yang sesuai ke newPos .
  4. cMesh.vertices vertices diperbarui kembali ke cMesh.vertices . Lalu kami memanggil RecalculateNormals() untuk menggambar ulang jala dengan nilai-nilai baru.

Simpan file dan kembali ke Unity. Seret salah satu simpul; sekarang mesh harus mempertahankan bentuknya dan tidak runtuh.


Sekarang kita telah menyelesaikan langkah pertama dalam memanipulasi jerat, simpan adegan dan lanjutkan ke bagian selanjutnya.

Manipulasi jala


Di bagian ini, Anda akan belajar tentang memanipulasi jerat secara real time. Ada banyak cara, tetapi dalam tutorial ini kita akan melihat jenis manipulasi mesh paling sederhana, yaitu memindahkan simpul mesh yang sebelumnya dibuat.

Mengumpulkan indeks yang dipilih


Mari kita mulai dengan memilih simpul yang akan kita gerakkan secara real time.

Buka Adegan 02 Buat Heart Mesh dari folder Adegan . Di jendela Adegan, Anda akan melihat bola merah. Pilih Sphere di Hirarki dan pergi ke Inspektur . Anda akan melihat bahwa komponen skrip Heart Mesh terpasang ke objek.

Sekarang kita perlu skrip Editor untuk objek ini untuk menampilkan simpul dari mesh di jendela Scene. Buka folder Editor dan klik dua kali pada HeartMeshInspector.cs .

Dalam fungsi ShowHandle() , di dalam blok if , tambahkan berikut ini:

 Handles.color = Color.blue; if (Handles.Button(point, handleRotation, mesh.pickSize, mesh.pickSize, Handles.DotHandleCap)) //1 { mesh.selectedIndices.Add(index); //2 } 

Penjelasan Kode:

  1. Mengatur dan menampilkan simpul dari mesh sebagai tipe Handles.Button . Handles.Button .
  2. Ketika diklik, itu menambah indeks yang dipilih ke daftar indeks ditekan, mesh.selectedIndices .

Di OnInspectorGUI() , sebelum braket penutup, tambahkan berikut ini:

 if (GUILayout.Button("Clear Selected Vertices")) { mesh.ClearAllData(); } 

Penjelasan kode: ini adalah bagaimana kami menambahkan tombol Reset ke Inspektur untuk memanggil mesh.ClearAllData() .

Simpan file dan buka HeartMesh.cs dari folder Scripts . Dalam fungsi ClearAllData() , tambahkan berikut ini:

 selectedIndices = new List<int>(); targetIndex = 0; targetVertex = Vector3.zero; 

Penjelasan Kode: Kode ini membersihkan nilai dalam targetIndex dan targetIndex selectedIndices . Ini juga mengatur ulang targetVertex .

Simpan file dan kembali ke Unity. Pilih Sphere dan pergi ke Inspektur untuk komponen skrip HeartMesh . Luaskan Indeks yang Dipilih dengan mengklik ikon panah di sebelahnya. Ini akan memungkinkan kita untuk melacak setiap titik yang ditambahkan ke daftar.

Enable Is Edit Mode menggunakan kotak centang di sebelahnya. Karena ini, simpul dari mesh akan ditarik di jendela Scene. Mengklik pada titik biru di Indeks yang Dipilih harus mengubah nilai yang sesuai. Juga uji tombol Hapus Seleksi Verteks untuk memastikannya menghapus semua nilai.


Catatan: di Inspektur kustom yang dimodifikasi, kami memiliki opsi untuk menampilkan / menyembunyikan manipulator transform menggunakan Show Transform Handle . Jadi, jangan panik jika Anda tidak menemukan manipulator Transform di adegan lain! Nyalakan sebelum keluar.

Mengubah bola menjadi hati


Mengubah simpul jala secara real time pada dasarnya terdiri dari tiga langkah:

  1. Salin simpul mesh saat ini (sebelum animasi) ke mVertices .
  2. mVertices perhitungan dan mengubah nilai dalam mVertices .
  3. Perbarui simpul mesh saat ini dengan mVertices ketika mengubah pada setiap langkah dan biarkan Unity secara otomatis menghitung normals.

Buka HeartMesh.cs dan variabel berikut ini sebelum fungsi Start() :

 public float radiusofeffect = 0.3f; //1 public float pullvalue = 0.3f; //2 public float duration = 1.2f; //3 int currentIndex = 0; //4 bool isAnimate = false; float starttime = 0f; float runtime = 0f; 

Penjelasan Kode:

  1. Jari-jari area dipengaruhi oleh vertex target.
  2. Seret kekuatan.
  3. Durasi animasi.
  4. Indeks saat ini dari daftarIndeks yang selectedIndices .

Dalam fungsi Init() , sebelum blok if , tambahkan berikut ini:

 currentIndex = 0; 

Penjelasan kode: pada awal permainan, currentIndex ke 0, indeks pertama dari daftarIndeks yang selectedIndices .

Dalam fungsi Init() sama, sebelum braket penutup blok else , tambahkan berikut ini:

 StartDisplacement(); 

Penjelasan kode: jalankan fungsi StartDisplacement() jika isEditMode salah.

Di dalam fungsi StartDisplacement() , tambahkan berikut ini:

 targetVertex = oVertices[selectedIndices[currentIndex]]; //1 starttime = Time.time; //2 isAnimate = true; 

Penjelasan Kode:

  1. Pilih targetVertex untuk memulai animasi.
  2. Tetapkan waktu mulai dan ubah nilai isAnimate menjadi true.

Setelah fungsi StartDisplacement() , buat fungsi FixedUpdate() dengan kode berikut:

 void FixedUpdate() //1 { if (!isAnimate) //2 { return; } runtime = Time.time - starttime; //3 if (runtime < duration) //4 { Vector3 targetVertexPos = oFilter.transform.InverseTransformPoint(targetVertex); DisplaceVertices(targetVertexPos, pullvalue, radiusofeffect); } else //5 { currentIndex++; if (currentIndex < selectedIndices.Count) //6 { StartDisplacement(); } else //7 { oMesh = GetComponent<MeshFilter>().mesh; isAnimate = false; isMeshReady = true; } } } 

Penjelasan Kode:

  1. Fungsi FixedUpdate() dijalankan dalam loop FPS tetap.
  2. Jika isAnimate salah, maka lewati kode berikut.
  3. Ubah animasi runtime .
  4. Jika runtime berada dalam duration , maka kita mendapatkan koordinat dunia targetVertex dan DisplaceVertices() , yang mencakup vertex target dengan radiusofeffect dan radiusofeffect .
  5. Kalau tidak, waktu sudah habis. Tambahkan satu currentIndex .
  6. Periksa apakah currentIndex di currentIndex selectedIndices . Pergi ke simpul berikutnya dalam daftar menggunakan StartDisplacement() .
  7. Jika tidak, di akhir daftar, ubah data oMesh ke mesh saat ini dan isAnimate to false untuk menghentikan animasi.

Di DisplaceVertices() tambahkan berikut ini:

 Vector3 currentVertexPos = Vector3.zero; float sqrRadius = radius * radius; //1 for (int i = 0; i < mVertices.Length; i++) //2 { currentVertexPos = mVertices[i]; float sqrMagnitute = (currentVertexPos - targetVertexPos).sqrMagnitude; //3 if (sqrMagnitute > sqrRadius) { continue; //4 } float distance = Mathf.Sqrt(sqrMagnitute); //5 float falloff = GaussFalloff(distance, radius); Vector3 translate = (currentVertexPos * force) * falloff; //6 translate.z = 0f; Quaternion rotation = Quaternion.Euler(translate); Matrix4x4 m = Matrix4x4.TRS(translate, rotation, Vector3.one); mVertices[i] = m.MultiplyPoint3x4(currentVertexPos); } oMesh.vertices = mVertices; //7 oMesh.RecalculateNormals(); 

Penjelasan Kode:

  1. Kuadrat dari jari-jari.
  2. Kami loop melalui setiap simpul mesh.
  3. sqrMagnitude antara currentVertexPos dan targetVertexPos .
  4. Jika sqrMagnitude melebihi sqrRadius , maka pergi ke simpul berikutnya.
  5. Jika tidak, lanjutkan dengan menentukan nilai falloff , yang tergantung pada distance simpul saat ini dari titik pusat lingkup.
  6. Vector3 posisi Vector3 baru dan terapkan Transform ke vertex saat ini.
  7. Saat Anda keluar dari loop, kami menetapkan nilai mVertices diubah ke mVertices , dan memaksa Unity untuk menghitung ulang normals.

Sumber Teknologi Falloff
Rumus asli diambil dari file paket aset Contoh Prosedural , yang dapat diunduh secara gratis dari Unity Asset Store.

Simpan file dan kembali ke Unity. Pilih Sphere , buka komponen HeartMesh dan coba tambahkan beberapa simpul ke properti Indeks Pilihan . Nonaktifkan Apakah Edit mode dan klik Mainkan untuk melihat hasil pekerjaan Anda.


Eksperimen dengan nilai Radiusofeffect , Pullvalue, dan Duration untuk mendapatkan hasil yang berbeda. Saat Anda siap, ubah pengaturan sesuai dengan tangkapan layar di bawah ini.


Klik Play . Apakah bola Anda berubah menjadi hati?


Selamat! Di bagian selanjutnya, kami akan menyimpan jaring sebagai cetakan untuk penggunaan di masa depan.

Menyimpan jala secara real time


Untuk menyimpan mesh prosedural berbentuk hati dalam mode Play, Anda harus menyiapkan prefab yang anaknya akan menjadi objek 3D, dan kemudian ganti aset mesh-nya dengan yang baru menggunakan skrip.

Di jendela Proyek, cari CustomHeart di folder Rak itan . Klik ikon panah untuk memperluas isinya dan pilih Anak . Anda sekarang melihat objek Sphere di jendela pratinjau Inspektur . Ini adalah cetakan yang akan menyimpan data untuk mesh baru.


Buka HeartMeshInspector.cs . Di dalam fungsi OnInspectorGUI() , sebelum braket penutup, tambahkan berikut ini:

 if (!mesh.isEditMode && mesh.isMeshReady) { string path = "Assets/Prefabs/CustomHeart.prefab"; //1 if (GUILayout.Button("Save Mesh")) { mesh.isMeshReady = false; Object pfObj = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)); //2 Object pfRef = AssetDatabase.LoadAssetAtPath (path, typeof(GameObject)); GameObject gameObj = (GameObject)PrefabUtility.InstantiatePrefab(pfObj); Mesh pfMesh = (Mesh)AssetDatabase.LoadAssetAtPath(path, typeof(Mesh)); //3 if (!pfMesh) { pfMesh = new Mesh(); } else { pfMesh.Clear(); } pfMesh = mesh.SaveMesh(); //4 AssetDatabase.AddObjectToAsset(pfMesh, path); gameObj.GetComponentInChildren<MeshFilter>().mesh = pfMesh; //5 PrefabUtility.ReplacePrefab(gameObj, pfRef, ReplacePrefabOptions.Default); //6 Object.DestroyImmediate(gameObj); //7 } } 

Penjelasan Kode:

  1. Menyetel path ke jalur ke objek pabrikan CustomHeart.
  2. Membuat dua objek dari prefab CustomHeart, satu untuk membuat instance sebagai GameObject ( pfObj ), dan yang kedua sebagai tautan ( pfRef ).
  3. Membuat instance pfMesh pfMesh mesh pfMesh . Jika tidak ditemukan, buat mesh baru, jika tidak maka bersihkan data yang ada.
  4. pfMesh dengan data mesh baru, dan kemudian menambahkannya sebagai aset ke CustomHeart .
  5. Mengisi aset jala di gameObj nilai pfMesh .
  6. Mengganti CustomHeart dengan gameObj mencocokkan koneksi yang sudah ada sebelumnya.
  7. Seketika menghancurkan gameObj .

Simpan file dan pergi ke HeartMesh.cs . Dalam metode SaveMesh() umum, setelah membuat instance nMesh tambahkan berikut ini:

 nMesh.name = "HeartMesh"; nMesh.vertices = oMesh.vertices; nMesh.triangles = oMesh.triangles; nMesh.normals = oMesh.normals; 

Penjelasan Kode: Mengembalikan aset mesh dengan nilai dari mesh berbentuk hati.

Simpan file dan kembali ke Unity. Klik Mainkan . Setelah animasi selesai, tombol Save Mesh akan muncul di Inspektur . Klik tombol untuk menyimpan jala baru, dan kemudian hentikan pemain.

Buka folder Rak itan dan lihat prefab CustomHeart. Anda harus melihat bahwa sekarang di objek pabrikan CustomHeart terdapat jaring berbentuk hati yang benar-benar baru.


Kerja bagus!

Menyatukan semuanya


Dalam adegan sebelumnya, fungsi DisplaceVertices() menggunakan rumus Falloff untuk menentukan gaya seret yang diterapkan ke setiap titik dalam radius yang diberikan. Titik "jatuh", di mana gaya drag mulai berkurang, tergantung pada jenis Falloff yang digunakan: Linear, Gaussian atau Needle. Setiap jenis menghasilkan hasil yang berbeda di jala.


Di bagian ini, kita akan melihat cara lain untuk memanipulasi simpul: menggunakan kurva yang diberikan. Mengambil aturan bahwa kecepatan sama dengan jarak yang dibagi oleh waktu (d = (v / t)), kita dapat menentukan posisi vektor, mengacu pada jaraknya dibagi dengan waktu.


Menggunakan Metode Kurva


Simpan adegan saat ini dan buka 03 Customize Heart Mesh dari folder Scenes . Anda akan melihat contoh Hirarki dari prefab CustomHeart. Klik ikon panah di sebelahnya untuk membuka kontennya dan pilih Child .

Lihat propertinya di Inspektur .Anda akan melihat komponen Filter Mesh dengan Aset Heart Mesh . Lampirkan skrip Custom Heart ke Child sebagai komponen . Sekarang aset tersebut harus berubah dari HeartMesh ke clone .


Selanjutnya, buka CustomHeart.cs dari folder Scripts . Sebelum fungsi, Start()tambahkan berikut ini:

 public enum CurveType { Curve1, Curve2 } public CurveType curveType; Curve curve; 

Penjelasan kode: di sini enum umum dibuat dengan nama CurveType, setelah itu tersedia dari Inspektur .

Pergi ke CurveType1()dan tambahkan berikut ini:

 Vector3[] curvepoints = new Vector3[3]; //1 curvepoints[0] = new Vector3(0, 1, 0); curvepoints[1] = new Vector3(0.5f, 0.5f, 0); curvepoints[2] = new Vector3(1, 0, 0); curve = new Curve(curvepoints[0], curvepoints[1], curvepoints[2], false); //2 

Penjelasan Kode:

  1. Kurva sederhana terdiri dari tiga titik. Tetapkan poin untuk kurva pertama.
  2. Kami menghasilkan kurva pertama dengan bantuan Curve()dan menetapkan nilainya curve. Kurva yang ditarik dapat ditampilkan dalam pratinjau jika Anda menentukan true sebagai parameter terakhir.

Pergi ke CurveType2()dan tambahkan berikut ini:

 Vector3[] curvepoints = new Vector3[3]; //1 curvepoints[0] = new Vector3(0, 0, 0); curvepoints[1] = new Vector3(0.5f, 1, 0); curvepoints[2] = new Vector3(1, 0, 0); curve = new Curve(curvepoints[0], curvepoints[1], curvepoints[2], false); //2 

Penjelasan Kode:

  1. Tetapkan poin untuk kurva kedua.
  2. Kami menghasilkan kurva kedua dengan Curve()dan menetapkan nilainya curve. Kurva yang ditarik dapat ditampilkan dalam pratinjau jika Anda menentukan true sebagai parameter terakhir.

B StartDisplacement(), sebelum braket penutup, tambahkan yang berikut:

 if (curveType == CurveType.Curve1) { CurveType1(); } else if (curveType == CurveType.Curve2) { CurveType2(); } 

Penjelasan kode: di sini kami memeriksa opsi yang dipilih oleh pengguna curveTypedan menghasilkannya sesuai curve.

B DisplaceVertices(), di dalam pernyataan loop forsebelum tanda kurung tutup, tambahkan berikut ini:

 float increment = curve.GetPoint(distance).y * force; //1 Vector3 translate = (vert * increment) * Time.deltaTime; //2 Quaternion rotation = Quaternion.Euler(translate); Matrix4x4 m = Matrix4x4.TRS(translate, rotation, Vector3.one); mVertices[i] = m.MultiplyPoint3x4(mVertices[i]); 

Penjelasan Kode:

  1. Kami mendapatkan posisi kurva pada yang diberikan distancedan kalikan nilainya ydengan forceuntuk mendapatkan increment.
  2. Buat tipe data baru Vector3untuk menyimpan posisi baru dari vertex saat ini dan terapkan Transformasinya.

Simpan file dan kembali ke Unity. Periksa sifat-sifat komponen CustomHeart permainan objek anak . Anda akan melihat daftar drop-down di mana Anda dapat memilih Jenis Kurva . Dari daftar turun bawah Edit Type , pilih Add Indices atau Remove Indices untuk memperbarui daftar simpul dan bereksperimen dengan pengaturan yang berbeda.


Untuk melihat hasil terperinci untuk berbagai jenis kurva, masukkan nilai sesuai dengan tangkapan layar:


Untuk daftar Jenis Kurva , pilih Curve1 , pastikan Tidak Ada yang dipilih untuk Jenis Edit, dan klik Mainkan . Anda harus melihat jala yang menyimpang ke dalam pola. Gulung model untuk melihatnya dalam tampilan samping dan bandingkan hasilnya untuk kedua jenis kurva. Di sini Anda melihat bagaimana Jenis Kurva yang dipilih memengaruhi offset jala.



Itu saja!Anda dapat mengklik Bersihkan Verteks yang Dipilih untuk mereset Indeks yang Dipilih dan bereksperimen dengan pola Anda sendiri. Namun jangan lupa bahwa ada faktor lain yang akan mempengaruhi hasil akhir mesh, yaitu:

  • Nilai jari-jari.
  • Distribusi simpul di daerah tersebut.
  • Posisi pola dari simpul yang dipilih.
  • Metode yang dipilih untuk offset.

Ke mana harus pergi selanjutnya?


File dari proyek yang sudah selesai ada di arsip proyek tutorial.

Jangan berhenti di situ! Cobalah teknik yang lebih canggih yang digunakan dalam tutorial Generasi Prosedural Labirin .

Saya harap Anda menikmati tutorial ini dan menemukan informasinya bermanfaat. Terima kasih khusus saya mengucapkan Jasper Flick dari seperti kucing Coding untuk tutorial yang sangat baik nya yang membantu saya merakit sebuah demo untuk proyek saya.

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


All Articles