Medan Voxel yang Halus

13

Sebagai proyek pribadi, saya mencoba membuat generator medan yang akan membuat medan tampak seperti medan halus Castle Story.

Jika Anda belum pernah melihatnya, di sini: masukkan deskripsi gambar di sini

Jadi seperti yang Anda lihat, itu kombinasi blok dan blok "halus".

Apa yang saya coba lakukan untuk meniru tampilan ini adalah memberi setiap blok permukaan peta ketinggian mini. Ini biasanya berfungsi, tetapi ada beberapa masalah, menghasilkan medan seperti ini:

masukkan deskripsi gambar di sini

Masalahnya adalah bahwa setiap blok adalah 1x1x1, tetapi kadang-kadang ketinggian di lokasi tertentu negatif atau> 1. Dalam hal itu, saya klip itu dan atur tingginya menjadi 0 atau 1.

Untuk lebih menggambarkan apa yang saya maksud, inilah diagram: masukkan deskripsi gambar di sini

Untuk menghasilkan ketinggian, pada dasarnya saya lakukan:

genColumn(int x, int z)
{
    int highestBlockY = (int)noise2d(x, z);

    bool is_surface = true;

    for(int y = max_height - 1; y >= 0; y--)
    {
        Block b;

        if(is_surface)
        {
            b = Block.Grass;
            b.HasHeightMap = true;

            // generate heightmap
            for(int ix = 0; ix < 5; ix++)
            {
                for(int iz = 0; iz < 5; iz++)
                {
                    float heightHere = noise2d(x + ix / 4, z + iz / 4) - y;

                    // clip heights
                    if(heightHere > 1)
                        heightHere = 1;

                    if(heightHere < 0)
                        heightHere = 0;

                    b.HeightMap[ix][iz] = heightHere;
                }
            }

            is_surface = false;
        }
        else
        {
            b = Block.Dirt;
        }

        setBlock(x, y, z, b);
    }
}

Mungkin saya mendekati ini secara salah dengan menggunakan nilai kebisingan perlin "benar"?

Bantuan apa pun akan sangat dihargai!

tanpa judul
sumber

Jawaban:

11

Castle Story terlihat seperti ini karena kendala teknis: Jika ada peta ketinggian per masing-masing voxel di seluruh volume, daripada hanya peta tinggi per setiap voxel permukaan , biaya penyimpanan akan jauh lebih besar, berdasarkan urutan O (n ^ 3 ) yang bisa menjadi penghalang, berlawanan dengan O yang lebih menguntungkan (n ^ 2), di mana n adalah panjang sisi ruang voxel kubik yang mewakili dunia Anda. Ingatlah bahwa informasi heightmap untuk voxels bawah tanah tersirat dalam struktur grid, sehingga info heightmap hanya perlu secara eksplisit disimpan untuk voxels yang terletak di permukaan. Jadi orang-orang Castle Story telah mengambil simpul ke celah jaringan untuk menghemat biaya penyimpanan dan kompleksitas konstruksi jala ... baca terus.

Pertama, mari kita lihat opsi Anda:

masukkan deskripsi gambar di sini

(1) akan mempersulit Anda, karena dalam satu kolom voxel Anda hanya ingin informasi mini-heightmap untuk voxel teratas - lihat kembali paragraf pertama untuk alasan mengapa. Melihat (1), kolom di sebelah kanan memiliki informasi peta ketinggian untuk bagian paling atas dan kedua dari atas (dan ini bisa berlaku untuk yang ketiga dari atas dan seterusnya, jika kemiringannya cukup ekstrem.). Ini tidak baik.

(2) Mungkin itu pilihan yang lebih baik; Yaitu, memastikan bahwa sudut sudut snap ke celah voxel grid. Tetapi bagaimana kita mengatasi masalah kemiringan ekstrem? Nah, kita perlu memilih beberapa gradien di mana kita cukup snap ke kolom vertikal dan dengan demikian memastikan kita tidak memiliki gradien daripada yang bisa memotong melalui n voxel paling atas. Gradien 45 derajat adalah batas alami karena alasan yang saya jelaskan di bawah ini. Jadi alih-alih (3), kami akan memiliki (4):

masukkan deskripsi gambar di sini

(4) Mematahkan sudut sudut voxel ke celah jaringan terdekat adalah solusinya. Efek visual - aliasing diagonal - dapat dilihat di tangkapan layar Castle Story Anda. Kemiringan cutoff untuk voxels adalah gradien 1: 1, atau 45 derajat (seperti yang dilihat secara orthogonal). Bekerja mundur dari solusi, mari kita lihat alasannya:

  • Satu-satunya cara kita dapat memiliki kemiringan ekstrem yang tidak terputus adalah jika sebuah voxel memanjang secara vertikal ...
  • .... Tapi tidak ada jaring voxel yang dapat melebihi area pembatasnya, terlepas dari bentuknya yang halus; voxel perlu duduk di ruang yang ditentukan dalam kisi 3D yang menyumbang, jika bukan karena bentuknya yang tepat, maka setidaknya untuk kotak pembatas sumbu-rata.

Alasan lain untuk mendekatinya dengan cara ini adalah, seperti yang telah Anda temukan, tidak menggunakan gertakan (diskritisasi) mengarah ke berbagai skenario perataan permukaan yang rumit secara geometris, yang paling baik dihindari sama sekali ... permainan semacam ini umumnya tidak memerlukan tingkat akurasi yang disediakan oleh algoritma CSG yang tepat, yang merupakan alasan utama kami menggunakan voxel: Voxel membuatnya jauh lebih mudah untuk bekerja secara bertahap dengan volume, dibandingkan dengan interseksi titik-titik (kontinu) persimpangan poligon / algoritma CSG melakukan .

Insinyur
sumber
Saya baru saja mencoba mengimplementasikan ini, dan saya mengalami kebingungan - apa yang Anda maksud dengan "celah?" Apakah maksud Anda koordinat kotak integral?
tanpa judul
@ThomasBradworth. "Sebuah ruang yang mengintervensi antara hal-hal." Untuk 2D, jika Anda memiliki jaringan sel anxn, Anda akan memiliki (n + 1) x (n + 1) celah. Ini meluas langsung ke 3D. Mereka adalah "simpul" yang mengikat setiap sel, yang sebagian besar dibagi antara beberapa sel / voxel. Jika Anda merebusnya menjadi 1D (satu baris) maka jika kedua sel dan celah diwakili sebagai array, maka sel 0 dibatasi oleh celah 0 dan celah 1, sedangkan sel 1 dibatasi oleh celah 1 dan celah 2 ... dll
Insinyur
Terima kasih balasannya! Saya mencoba melakukan hal itu, tetapi saya mendapat hasil yang tidak menguntungkan. Pada awalnya, saya mencoba hanya membulatkan nilai ketinggian di tepi (ketika x adalah 0 atau 4, atau z adalah 0 atau 4), tetapi itu membuat saya: i.imgur.com/eQW7Y.png ( pastebin.com/Lr8vyyHB ) Selanjutnya, saya mencoba memuluskan poin di tengah, jadi saya menambahkan "fungsi fix heights": pastebin.com/AazQ07Xm Namun, itu juga memberi saya hasil yang lebih sudut, tetapi juga buruk: i.imgur.com/q1JVP .png Mungkin ada yang salah dengan fungsi noise saya?
tanpa judul
@ThomasBradsworth Sedihnya, saya merasa Anda hanya setengah membaca / mengerti jawaban yang saya ambil lebih dari satu jam untuk menulis dan mengedit. Lupakan kebisingan; apalagi, jika Anda tidak mengerti fungsi noise, hapus dari persamaan untuk saat ini. Masalah Anda terletak pada bagaimana masing-masing data mesh voxel dibangun, dan noise tidak ada hubungannya dengan itu, karena Anda dapat membuat peta ketinggian tanpa adanya noise. Bekerja dengan test case yang paling sederhana, yaitu hardcode array ketinggian. Kemudian lihat hasil Anda, dan atur algoritma pembuatan jala Anda. Ulangi sampai ia melakukan apa yang diharapkan. Lalu pasang kembali kebisingan, dan tinjau.
Insinyur
Apakah Anda mengatakan bahwa saya hanya harus menyimpan nilai ketinggian untuk sudut dan tidak menyimpan nilai tinggi dari titik "perantara"?
tanpa judul