Saya mencoba menulis mesin voxel kecil karena menyenangkan, tetapi berjuang untuk menemukan cara terbaik untuk menyimpan voxel yang sebenarnya. Saya sadar saya akan membutuhkan beberapa jenis sehingga saya tidak perlu memiliki seluruh dunia dalam memori, dan saya sadar saya perlu membuat mereka dengan kinerja yang masuk akal.
Saya membaca tentang oktaf dan dari apa yang saya pahami dimulai dengan 1 kubus, dan dalam kubus itu bisa 8 kubus lagi, dan 8 kubus itu bisa 8 kubus, dll. Tapi saya rasa ini tidak cocok dengan mesin voxel saya karena kubus / item voxel saya semua akan memiliki ukuran yang sama persis.
Jadi pilihan lain adalah dengan hanya membuat array ukuran 16 * 16 * 16 dan memilikinya menjadi satu potongan, dan Anda mengisinya dengan item. Dan bagian di mana tidak ada item akan memiliki nilai 0 sebagai (0 = udara). Tapi saya khawatir ini akan menghabiskan banyak memori dan tidak akan terlalu cepat.
Kemudian opsi lain adalah vektor untuk setiap potongan, dan mengisinya dengan kubus. Dan kubus memegang posisinya di chunk. Ini menghemat memori (tidak ada blok udara), tetapi membuat mencari kubus di lokasi tertentu jauh lebih lambat.
Jadi saya tidak bisa menemukan solusi yang baik, dan saya berharap seseorang dapat membantu saya dengan itu. Jadi apa yang akan Anda gunakan dan mengapa?
Tetapi masalah lain adalah rendering. Hanya membaca setiap potongan dan mengirimkannya ke GPU menggunakan OpenGL itu mudah, tetapi sangat lambat. Menghasilkan satu mesh per chunk akan lebih baik, tetapi itu berarti setiap kali saya memecahkan satu blok, saya harus membangun kembali seluruh chunk yang bisa memakan sedikit waktu menyebabkan cegukan kecil tapi nyata, yang jelas saya tidak mau. Jadi itu akan lebih sulit. Jadi bagaimana saya membuat kubus? Cukup buat semua kubus dalam satu dhuwur buffer per chunk dan render itu dan mungkin mencoba untuk meletakkannya di thread lain, atau apakah ada cara lain?
Terima kasih!
Jawaban:
Menyimpan blok sebagai posisi dan nilai sebenarnya sangat tidak efisien. Bahkan tanpa overhead yang disebabkan oleh struct atau objek yang Anda gunakan, Anda perlu menyimpan 4 nilai berbeda per blok. Masuk akal untuk menggunakannya di atas metode "menyimpan blok dalam array tetap" (yang Anda jelaskan sebelumnya) adalah ketika hanya seperempat dari blok yang solid, dan dengan cara ini Anda bahkan tidak mengambil metode optimasi lainnya ke dalam Akun.
Oktaf sebenarnya bagus untuk permainan berbasis voxel, karena mereka berspesialisasi dalam menyimpan data dengan fitur yang lebih besar (misalnya tambalan dari blok yang sama). Untuk mengilustrasikan hal ini, saya menggunakan quadtree (pada dasarnya octrees dalam 2d):
Ini adalah set awal saya yang berisi ubin 32x32, yang akan sama dengan nilai 1024:
Menyimpan ini sebagai 1024 nilai terpisah sepertinya tidak efisien, tetapi begitu Anda mencapai ukuran peta yang mirip dengan game, seperti Terraria , memuat layar akan membutuhkan waktu beberapa detik. Dan jika Anda meningkatkannya ke dimensi ketiga, itu mulai menggunakan semua ruang dalam sistem.
Quadtrees (atau octrees dalam 3d) dapat membantu situasi. Untuk membuat satu, Anda bisa pergi dari ubin dan kelompokkan bersama-sama, atau pergi dari satu sel besar dan Anda membaginya sampai Anda mencapai ubin. Saya akan menggunakan pendekatan pertama, karena lebih mudah untuk divisualisasikan.
Jadi, dalam iterasi pertama Anda mengelompokkan semuanya menjadi sel 2x2, dan jika sel hanya berisi ubin dari jenis yang sama, Anda menjatuhkan ubin dan hanya menyimpan jenisnya. Setelah satu iterasi, peta kita akan terlihat seperti ini:
Garis merah menandai apa yang kami simpan. Setiap kotak hanya memiliki 1 nilai. Ini membawa ukuran turun dari nilai 1024 ke 439, itu penurunan 57%.
Tapi Anda tahu mantra . Mari selangkah lebih maju dan kelompokkan ini ke dalam sel:
Ini mengurangi jumlah nilai yang disimpan menjadi 367. Itu hanya 36% dari ukuran aslinya.
Anda jelas perlu melakukan pembagian ini sampai setiap 4 sel yang berdekatan (8 blok berdekatan dalam 3d) di dalam chunk disimpan di dalam satu sel, pada dasarnya mengubah chunk menjadi satu sel besar.
Ini juga memiliki beberapa manfaat lain, terutama ketika melakukan tabrakan, tetapi Anda mungkin ingin membuat octree terpisah untuk itu, yang hanya peduli apakah satu blok solid atau tidak. Dengan begitu, alih-alih memeriksa tabrakan untuk setiap blok di dalam chunk, Anda bisa melakukannya melawan sel.
sumber
Ada octrees untuk menyelesaikan masalah yang Anda uraikan dengan tepat, memungkinkan penyimpanan data yang padat tanpa waktu pencarian yang besar.
Fakta bahwa voxel Anda memiliki ukuran yang sama hanya berarti bahwa octree Anda memiliki kedalaman yang tetap. misalnya. untuk potongan 16x16x16, Anda membutuhkan paling banyak 5 level pohon:
Ini berarti Anda memiliki paling banyak 5 langkah untuk mencari tahu apakah ada voxel pada posisi tertentu di chunk:
Jauh lebih pendek daripada memindai bahkan 1% dari jalan melalui array hingga 4.096 vox!
Perhatikan bahwa ini memungkinkan kita memampatkan data di mana pun ada oktan penuh dengan nilai yang sama - apakah nilai itu semua udara atau semua batu atau apa pun. Hanya di mana oktan mengandung nilai campuran yang perlu kita bagi lagi, hingga batas node daun voxel tunggal.
Untuk mengatasi anak-anak dari sepotong, biasanya kami akan melanjutkan dalam urutan Morton , kira-kira seperti ini:
Jadi, navigasi simpul Octree kami mungkin terlihat seperti ini:
sumber