Smooth Voxel Terrain

13

Jako osobisty projekt staram się stworzyć generator terenu, który stworzy teren przypominający gładki teren Castle Story.

Jeśli jeszcze tego nie widziałeś, tutaj: wprowadź opis zdjęcia tutaj

Jak widać, jest to kombinacja bloków i bloków „gładkich”.

To, co próbowałem zrobić, aby naśladować ten wygląd, to nadanie każdemu blokowi powierzchniowemu mini-mapy wysokości. To ogólnie działa, ale są pewne problemy, które dają taki teren:

wprowadź opis zdjęcia tutaj

Problem polega na tym, że każdy blok ma wymiary 1x1x1, ale czasami wysokość w danym miejscu jest ujemna lub> 1. W takim przypadku przycinam go i ustawiam wysokość na 0 lub 1.

Aby lepiej zilustrować, co mam na myśli, oto schemat: wprowadź opis zdjęcia tutaj

Aby wygenerować wysokość, w zasadzie wykonuję:

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);
    }
}

Być może podchodzę do tego niepoprawnie, używając „prawdziwej” wartości hałasu perlina?

Każda pomoc byłaby bardzo mile widziana!

nieuprawny
źródło

Odpowiedzi:

11

Castle Story wygląda tak z powodu ograniczeń technicznych: Gdyby istniała mapa wysokości dla każdego woksela w całej objętości, a nie tylko mapa wysokości dla każdego woksela powierzchni , koszt przechowywania byłby znacznie większy, rzędu O (n ^ 3 ), które mogą być wygórowane, w przeciwieństwie do bardziej korzystnego O (n ^ 2), gdzie n jest długością boku sześciennej przestrzeni wokselowej reprezentującej twój świat. Należy pamiętać, że informacje o mapach wysokości dla wokseli podziemnych są ukryte w strukturze siatki, więc informacje o mapach wysokości muszą być jawnie przechowywane tylko dla wokseli leżących na powierzchni. Więc chłopaki z Castle Story zastosowali wierzchołki do szczelin siatki, aby zaoszczędzić na kosztach przechowywania i złożoności konstrukcji siatki ... czytaj dalej.

Po pierwsze, spójrzmy na twoje opcje:

wprowadź opis zdjęcia tutaj

(1) sprawi, że będzie ci trudno, ponieważ w pojedynczej kolumnie wokseli potrzebujesz tylko informacji o mini-wysokości mapy dla najwyższego woksela - powróć do pierwszego akapitu, aby dowiedzieć się, dlaczego tak jest. Patrząc na (1), kolumna po prawej stronie zawiera informacje o mapie wysokości zarówno dla najwyższego, jak i drugiego od góry (i może to dotyczyć trzeciego od góry i tak dalej, jeśli nachylenie byłoby wystarczająco ekstremalne). To nie jest dobre.

(2) Jest to prawdopodobnie lepsza opcja; to znaczy, upewniając się, że wierzchołki narożników przyciągają się do szczelin siatki wokseli. Ale w jaki sposób rozwiązujemy problem skrajnego nachylenia? Cóż, musimy wybrać jakiś gradient, w którym po prostu przyciągamy do pionowej kolumny, a tym samym upewniamy się, że nie mamy gradientów, niż można przeciąć n najwyżej wokseli. Gradient 45 stopni jest naturalnym punktem odcięcia z powodów, które wyjaśniam poniżej. Zamiast (3) mielibyśmy (4):

wprowadź opis zdjęcia tutaj

(4) Rozwiązaniem jest przyciągnięcie wierzchołka narożnika wokseli do najbliższej szczeliny siatki. Efekt wizualny - ukośne aliasing - można zobaczyć na zrzucie ekranu Castle Story. Nachylenie odcięcia wokseli wynosi gradient 1: 1 lub 45 stopni (patrząc ortogonalnie). Pracując wstecz od rozwiązania, spójrzmy na przyczyny:

  • Jedynym sposobem na uzyskanie nieprzerwanego, ekstremalnego nachylenia jest wydłużenie pionu woksela ...
  • .... Ale żadna siatka woksela nie może przekroczyć obszaru ograniczającego, niezależnie od faktycznego wygładzonego kształtu; woksel musi siedzieć w określonej przestrzeni w siatce 3D, która odpowiada, jeśli nie jest to jego dokładna forma, to przynajmniej dla jego obwiedni wyrównanej do osi.

Innym powodem takiego podejścia jest to, że, jak już odkryłeś, brak przyciągania (dyskretyzacji) prowadzi do szeregu skomplikowanych geometrycznie scenariuszy wygładzania powierzchni, których najlepiej unikać w ogóle ... gry tego rodzaju na ogół nie wymagają stopień dokładności, jaki zapewniłby właściwy algorytm CSG, i to właśnie dlatego używamy wokseli przede wszystkim: woksele znacznie ułatwiają pracę przyrostową z objętościami, niż algorytmy przecinania wieloboków zmiennoprzecinkowych (ciągłych) .

Inżynier
źródło
Właśnie próbowałem to wdrożyć i wpadłem w pewne zamieszanie - co rozumiesz przez „szczeliny”? Masz na myśli integralne współrzędne siatki?
bez tytułu
@ThomasBradworth. „Przestrzeń, która interweniuje między rzeczami”. W przypadku 2D, jeśli masz siatkę komórek anxn, będziesz mieć (n + 1) x (n + 1) szczeliny. Dotyczy to bezpośrednio 3D. Są to „wierzchołki”, które wiążą każdą komórkę, które w większości są wspólne dla wielu komórek / wokseli. Jeśli sprowadzasz go do 1D (linia), to jeśli zarówno komórki, jak i szczeliny są reprezentowane jako tablica, wówczas komórka 0 jest ograniczona przez szczelinę 0 i szczelinę 1, podczas gdy komórka 1 jest ograniczona przez szczelinę 1 i szczelinę 2 ... itp.
Inżynier
Dziękuję za odpowiedź! Próbowałem zrobić dokładnie to, ale otrzymałem kilka niekorzystnych rezultatów. Na początku próbowałem po prostu zaokrąglić wartości wysokości na krawędziach (gdy x to 0 lub 4 lub z to 0 lub 4), ale to mnie: i.imgur.com/eQW7Y.png ( pastebin.com/Lr8vyyHB ) Następnie próbowałem wygładzić punkty na środku, więc dodałem „funkcję poprawiania wysokości”: pastebin.com/AazQ07Xm , która jednak dała mi również bardziej kątowy, ale także zły wynik: i.imgur.com/q1JVP .png Być może coś jest nie tak z moją funkcją hałasu?
bez tytułu
@ThomasBradsworth Niestety, czuję, że tylko w połowie przeczytałeś / zrozumiałeś odpowiedź, którą napisałem i zredagowałem w ciągu godziny. Zapomnij o hałasie; ponadto, jeśli nie rozumiesz funkcji szumu, na razie usuń ją z równania. Twój problem polega na tym, jak konstruowane są poszczególne dane siatki wokseli, a hałas nie ma z tym nic wspólnego, ponieważ można utworzyć mapę wysokości przy braku hałasu. Pracuj z najprostszym przypadkiem testowym, tj. Zakoduj tablicę wysokości. Następnie wyświetl wyniki i popraw algorytm generowania siatki. Powtarzaj, dopóki nie spełni oczekiwań. Następnie włóż hałas z powrotem i sprawdź.
Inżynier
Czy mówisz, że powinienem po prostu przechowywać wartości wysokości w rogach, a nie przechowywać wartości wysokości punktów „pośrednich”?
bez tytułu