Membangun Oktree untuk generasi medan

9

Saya sebelumnya telah menerapkan marching cubes / tetrahedra untuk membuat IsoSurface. Ini berhasil ( YouTube ), tetapi kinerjanya sangat buruk karena saya tidak pernah menerapkan variabel Tingkat Detail berdasarkan jarak tampilan (atau bahkan menghapus potongan lama yang jauh).

Saya memutuskan untuk mencoba lagi dan melakukannya dengan benar kali ini. Saya sudah mulai dengan membuat OctreeNode yang berfungsi sebagai berikut ketika Build()dipanggil.

  • Jika potongan terlalu kecil untuk dibangun, segera kembali.
  • Berolahraga jika permukaan melewati volume chunk ini.
  • Jika demikian, maka putuskan apakah kita ingin menaikkan LOD (karena kamera dekat)
  • Jika demikian, maka bibit 8 anak dan memanggil proses yang sama pada mereka
  • Jika tidak, bangun mesh menggunakan dimensi node saat ini

Beberapa PseudoCode:

OctNode Build() {
    if(this.ChunkSize < minChunkSize) {
        return null;
    }
    densityRange = densitySource¹.GetDensityRange(this.bounds);
    if(densityRange.min < surface < densityRange.max) {
        if(loDProvider.DesiredLod(bounds > currentLoD) {
            for(i 1 to 8) {
                if(children[i] == null) {
                    children[i] = new OctNode(...)
                }
                children[i] = children[i].Build();
            }
        } else {
            BuildMesh();
        }
        return this;
    }
}

¹ Selain mengembalikan kerapatan pada suatu titik, sumber kerapatan dapat menentukan kisaran kerapatan yang mungkin untuk volume tertentu.

² Penyedia LoD mengambil kotak pembatas dan mengembalikan max yang diinginkan berdasarkan posisi kamera / frustrasi, pengaturan pengguna, dll ...

Jadi ... Ini semua bekerja dengan cukup baik. Menggunakan bola sederhana sebagai sumber Kepadatan, dan menampilkan semua node:

Oktaf penuh

Dan hanya daunnya saja:

Oktree hanya menunjukkan daun

Namun, ada beberapa masalah:

  • Saya harus mendefinisikan volume pembatas awal (dan semakin besar itu, semakin banyak pemrosesan yang harus saya lakukan)
  • Pada akar pohon, saya tidak tahu seberapa dalam daunnya, jadi penomoran LoD saya dimulai pada kualitas terendah (root) dan meningkat ketika potongan semakin kecil. Karena LoD sekarang relatif terhadap volume awal, itu tidak banyak digunakan ketika saya ingin melakukan hal-hal pada ukuran / kualitas tertentu.

Saya telah memikirkan beberapa opsi tetapi keduanya tampak cacat:

  • Pelihara koleksi Octrees dan tambah / hapus tergantung jarak. Tidak dapat melihat bagaimana saya menyatu dengan baik¹, ditambah lagi saya membutuhkan daftar node yang dikenal-kosong, terutama jika saya ingin permukaan 3D sewenang-wenang (untuk menghindari penghitungan ulang volume kosong berulang kali)
  • Tambahkan induk Node ke root saat ini, lalu tambahkan tujuh saudara kandung untuk simpul asli. Ini akan bekerja dan sesuai permintaan tetapi tampaknya rumit untuk menyusut kembali dengan masuk akal ketika pemain bergerak melalui lanskap. Itu juga akan membuat angka LoD menjadi kurang berarti.

¹ [Dalam klarifikasi ke Q di bawah] Saat ini, jika 2 node yang berdekatan secara fisik di pohon berada di LOD yang berbeda, saya memiliki beberapa kode untuk memaksa verts sehingga tidak ada jahitan saat jerat dihasilkan. Saya dapat melakukan ini dengan mengetahui kepadatan untuk beberapa node di sekitarnya. Dalam skenario di mana saya memiliki 2 oktober independen berdampingan, saya tidak punya cara mudah untuk mengambil informasi ini, menghasilkan jahitan.

Apa cara optimal untuk mendekati ini?

Dasar
sumber

Jawaban:

1

Saya tidak yakin menjawab pertanyaan yang tepat, jadi saya akan menjawab dalam segmen, dan merasa bebas untuk menjawab dalam komentar jika ada kesalahpahaman tentang rincian pertanyaan tertentu.

Saya harus mendefinisikan volume pembatas awal (dan semakin besar itu, semakin banyak pemrosesan yang harus saya lakukan)

Sepertinya ini bukan masalahnya. Karena kenaikan granularitas pada bulan Oktober secara eksponensial, penambahan beberapa level di bagian atas seharusnya merupakan peningkatan bersih yang sangat kecil dalam pencapaian kinerja.

Pada akar pohon, saya tidak tahu seberapa dalam daunnya, jadi penomoran LoD saya dimulai pada kualitas terendah (root) dan meningkat ketika potongan semakin kecil. Karena LoD sekarang relatif terhadap volume awal, itu tidak banyak digunakan ketika saya ingin melakukan hal-hal pada ukuran / kualitas tertentu.

Jika Anda memperbaiki octree root Anda ke beberapa "nilai cukup besar" maka "LoD relatif terhadap volume awal" seharusnya tidak menjadi masalah. Dan seperti yang disebutkan di atas, saya tidak berpikir memiliki level ekstra di atas akan memengaruhi kinerja secara keseluruhan.

Pelihara koleksi Octrees dan tambah / hapus tergantung jarak. Tidak dapat melihat bagaimana saya menyatu dengan baik, ditambah saya membutuhkan daftar node yang dikenal-kosong, terutama jika saya ingin permukaan 3D sewenang-wenang (untuk menghindari penghitungan ulang volume kosong berulang kali)

Seperti yang saya pahami, solusi yang diusulkan ini adalah tentang menurunkan LoD ketika pindah dari area yang sebelumnya dirinci. Saya pikir itu akan terlihat sangat mirip dengan jalur kode "peningkatan LoD":

if (loDProvider.DesiredLod(bounds) <(is a lot less than)< currentLoD) { 
    for(i = 1 to 8) { 
        children[i].Destroy();
    }
    BuildMesh();
}

Kemudian, Anda tidak menghabiskan terlalu banyak waktu memeriksa node yang jauh karena Anda dapat mengandalkan kenyataan bahwa sementara jauh, tidak ada terlalu banyak "aktif" node, karena semua node resolusi tinggi akan dihapus.


Dengan asumsi simpul-simpul kecil berskala batu, itu berarti berpotensi lusinan atau bahkan ratusan level saat saya melakukan perjalanan melintasi benua

Saya pikir skala logaritmik dari octree membuatnya masih layak. Jika level tertinggi Anda adalah 1.000,0000.000 m lebar (ini akan menjadi 25 kali lebih luas dari Bumi asli, dan dengan 625x luas permukaan) dan bit level terendah Anda adalah 10cm, itu adalah 32 level dalam octree, yang mungkin cukup mudah dikelola. Jika Anda menginginkan sebuah planet 100 kali lebih luas dari Bumi (dan dengan luas permukaan 10.000 kali lebih banyak), itu hanya tambahan 3-4 tingkat dalam octree Anda. Pada titik ini akan dibutuhkan pemain ratusan tahun untuk berjalan melintasi dunia, dan jika Anda menggunakan matematika floating point naif, dunia akan mengumpulkan kesalahan presisi.

Pelihara koleksi Octrees dan tambah / hapus tergantung jarak. Tidak dapat melihat bagaimana saya menyatu dengan baik¹, ditambah lagi saya membutuhkan daftar node yang dikenal-kosong, terutama jika saya ingin permukaan 3D sewenang-wenang (untuk menghindari penghitungan ulang volume kosong berulang kali)

Bukankah ini pada dasarnya setara dengan memiliki milyaran selebar 1 km tetapi menyimpan daftar petunjuk untuk setiap, katakanlah, blok 1 km? Kemudian "menyatu" hanya akan mengandalkan node berukuran 2 km. Menyimpan referensi lokal untuk setiap "blok besar" tingkat menengah juga membuat Anda tidak perlu beralih melalui node tingkat atas, jika Anda khawatir tentang "kemungkinan lusinan tingkat tambahan oktan"

Jimmy
sumber
Terimakasih telah menjawab. Saya tidak bisa hanya memilih volume awal yang besar karena medan saya tidak terbatas (itulah tujuan saya). Tonton videonya untuk mendapat ide. Dengan demikian, pohon node saya akan semakin tinggi. Dengan asumsi simpul-simpul kecil berskala batu, itu berarti berpotensi lusinan atau bahkan ratusan level saat saya melakukan perjalanan melintasi benua. Re: Menyambung di seberang, izinkan saya menambahkan beberapa detail ke pertanyaan [Selesai]
Dasar
sejauh menyangkut pemain, "satu miliar mil" cukup dekat dengan "tak terbatas". Lebih banyak argumen untuk volume awal tetap ditambahkan untuk menjawab.
Jimmy
Saya masih tidak yakin. Mengapa memiliki lebih dari 30 lapisan pemrosesan yang tidak berguna? Itu tidak elegan, apalagi efisien. Saya mengambil poin Anda tentang waktu untuk menyeberang, tetapi kita hanya berbicara tentang generasi medan. Tidak ada yang mengatakan saya harus memusatkan pada titik asal, atau terbang dengan kecepatan tinggi tidak mungkin (walaupun saya tidak akan bertautan dengan kecepatan itu!). FWIW Saya menggunakan ganda secara internal untuk menghindari masalah presisi.
Dasar