Generowanie rzeźby terenu

Po wybraniu struktury danych do przechowywania informacji i po pierwszych wizualizacjach nadszedł czas na dopracowanie rzeźby terenu.

25.11.2017 12:00 WorldGen

Jeśli czytałeś mój poprzedni artykuł w którym opisywałem moje próby z wykorzystaniem tablic trójwymiarowych i widziałeś efekt wizualizacji możesz sobie pomyśleć: "No tak, niby wszystko fajnie, ale to wcale nie przypomina żadnego ternu! Nie jest do niego nawet podobne.". To prawda, muszę się z tym zgodzić. Pierwsze próby nie były udane jeśli chodzi o rzeźbę terenu. Po pierwszych generacjach były to raczej wysokie słupy ziemi, które nie za bardzo dawały możliwość poruszania się po nich w rozsądny sposób (chyba, że ma się latającą kamerę :P). Kiedy wizualizacja oraz wczytywanie kolejnych części świata była już całkiem sprawna przyszła kolej na ulepszenie wyglądu terenu.

Oczywiście od razu narzuca się pytanie: "Jak można wygenerować w miarę rozsądnie wyglądający teren?". Otóż żeby dopowiedzieć na to pytanie najpierw należałoby wiedzieć w jaki sposób ogólnie można go generować, a następnie można zastanowić się jak można wpływać na generację i co można w niej zmienić. To właśnie postaram opisać się w tym artykule :)

Tak jak wspomniałem, po pierwsze należy zapoznać się z możliwymi metodami generowania powierzchni świata. W grach w których generowanie musi zachodzić w czasie rzeczywistym (no bo kto by czekał z pół godziny zanim wczyta mu się kolejny kawałek świata XP), powierzchnie generuje się zazwyczaj przy użyciu odpowiednich funkcji szumu dwuwymiarowego. Używanie funkcje mają tą cechę, że generowane przez nie wartości nie są całkowicie losowe, ale zmieniają się stopniowo przez co teren nie staje się losowymi słupami ziemi, jak miało to miejsce w przypadku moich pierwszych testów.

Do generowania rzeźby terenu można także wykorzystać funkcje szumu trójwymiarowego. Takie funkcje generują naprawdę imponujące tereny z uwzględnieniem takich rzeczy jak np. jaskinie. Niestety takie funkcje nie są za często wykorzystywanie w grach, ponieważ działają zbyt wolno i generowanie świata przy ich wykorzystaniu zabierałoby całą przyjemność z gry. Gdyby świat był generowany w całości na początku i jeśli ktoś byłby dostatecznie cierpliwy, żeby poczekać z kilka dni na wygenerowanie, mógłby rzeczywiście cieszyć się bardzo ciekawym i zawierającym wiele szczegółów światem. Niestety na to nie bardzo można liczyć dlatego tutaj raczej zajmę się szumem dwuwymiarowym i to jego postanowiłem użyć w moim projekcie.

Jak zatem działa generowanie takiego terenu przy pomocy szumu? Otóż jest to w miarę prosty proces. Przy pomocy funkcji szumu dwuwymiarowego uzyskujemy wartości zależne od naszego położenia X oraz Y. Wartości te następnie możemy wykorzystać jako graniczne dla naszej współrzędnej Z i np. wszystko poniżej danej wartości wypełnić ziemią, a wszystko powyżej powietrzem. Jest to oczywiście bardzo uproszczony schemat, ale ja taki właśnie wykorzystałem na początku generowania terenu.

Użycie takiej funkcji szumu niestety nie zupełnie może być wystarczające. Jak szybko się okazuje przy próbie wykorzystania funkcji szumu nadal to co uzyskujemy nie przypomina za bardzo nic ciekawego. Aby uzyskać bardziej realistyczny rezultat używa się nieco innej techniki (chociaż bazującej na tym podstawowym założeniu). Polega ona na sumowaniu wartości szumu z wielu oktaw i wykorzystywaniu tej ostatecznej wartości. W każdej oktawie szum ma inną, zwykle większą, częstotliwość. Powoduje to, że teren staje się bardziej zniekształcony co zwiększa jego realizm. Ale zaraz, zaraz. Przecież użycie zwykłej funkcji szumu już jest dostatecznie bardzo zniekształcone, prawda? Tak, ale wszystko zależy od częstotliwości jaką wybierzemy.

Dobranie dobrej częstotliwości było dla mnie bardzo ciężkie i naprawdę dużo czasu poświęciłem na szukanie jaka częstotliwość byłaby odpowiednia. Okazało się, że dobre rezultaty dają naprawdę bardzo małe częstotliwości takie jak np. 0.006, 0.0035 itp. Wydają się to bardzo niewielkie wartości, dlatego sam nie za szybko wpadłem na pomysł, żeby takie właśnie wybrać. Kiedy jednak wybierzemy dobrą częstotliwość okazuje się, że nasz świat jest bardzo idealnie gładki. A dokładniej przypomina funkcję matematyczną która ma swoje minima i maksima lokalne, tylko w trójwymiarze. Zdecydowanie nie jest to efekt pożądany. I w tym właśnie momencie przydaje się poprzednio wspomniana technika z dodawaniem oktaw.

Wszystko będzie łatwiej zrozumieć kiedy będzie można zobaczyć wizualny efekt. Zanim jednak pokażę i wytłumaczę jak poszczególne parametry wpływają na generowaną powierzchnię muszę przedstawić mniej więcej deklarację funkcji jaką napisałem do generowania szumu. Funkcja ta wygląda następująco:

int genNoise(glm::vec2 pos, int octaves, float startFreq, float persistance, float low, float high);

Postaram się krótko opisać jej argumenty, a następnie wytłumaczę w jaki sposób wpływają one na generowany teren (z obrazkami :D).

pos - pozycja dwuwymiarowa na podstawie której generowana będzie wartość szumu. octaves - liczba oktaw które będą wpływały na końcową wartość (w każdej oktawie zwiększa się częstotliwość). startFreq - początkowa częstotliwość. persistance - wartość która mówi o tym o ile zmniejsza się amplituda szumu w każdej oktawie (powinien to być ułamek < 1). low - najmniejsza możliwa wartość szumu. high - największa możliwa wartość szumu.

Wartości poza tym, że są generowane i sumowane w każdej oktawie są na koniec jeszcze normalizowane tak, aby przyjmowały najmniejszą wartość jako low, a największą wartość jako high co pozwala łatwo generować teren o różnych skokach wysokości i bazowej wysokości.

Teraz skoro widać już jak wygląda funkcja, której używam i jakie ma argumenty mogę przedstawić wpływ danych argumentów na generowaną rzeźbę terenu.

Na pierwszy ogień pójdzie częstotliwość. Wraz ze zmianą częstotliwości teren staje się mniej lub bardziej górzysty. Czym większa częstotliwość, tym teren jest bardziej zniekształcony, a czym mniejsza tym teren będzie bardziej gładki. Lepiej zilustrują to kolejne trzy przykłady.

Pierwszy przykład to teren wygenerowany dla częstotliwości 0.1 z jedną oktawą. Wynik wygląda tak:

Drugi przykład to teren wygenerowany dla częstotliwości 0.007, także z jedną oktawą. Teren wygląda już o wiele lepiej, ale wydaje się, hmmm, zbyt idealnie gładki...

Trzeci przykład to teren wygenerowany dla częstotliwości 0.0018. Jak widać teraz góry są o wiele bardziej "rozciągnięte" i mniej strome:

Kolejnym współczynnikiem którego zmianom chciałbym się przyjrzeć jest ilość oktaw. Im więcej oktaw tym bardziej teren będzie zniekształcony, ale tym bardziej realistycznie będzie wyglądał. Dla ustalenia we wszystkich trzech przykładach częstotliwość to 0.007, a trwałość (persistance) to 0.5

Pierwszy przykład został wygenerowany przy użyciu czterech oktaw. Oto rezultat (porównaj go sobie z przykładem dla częstotliwości 0.007, ma on tą samą częstotliwość, ale tylko jedną oktawę):

Drugi przykład wykorzystuje już osiem oktawy. Jak widać różnica jest bardzo istotna:

Trzeci przykład używa aż dwunastu oktaw. Jak widać po przekroczeniu pewnej granicy zwiększanie liczby oktaw nie daje już dużej zmiany rzeźby terenu (ale istotnie spowalnia czas generacji!):

Ostatnim współczynnikiem do omówienia jest trwałość (persistance). Zmiana tego współczynnika mniej więcej odpowiada zmianą częstotliwości. Im trwałość jest mniejsza (małe wartości np. 0.001) tym teren jest bardziej gładki, natomiast im jest większa (duże wartości np. 0.9) tym teren jest bardziej stromy i zniekształcony. W poniższych dwóch przykładach pokażę mniej więcej skrajne wartości dla porównania. Dla obydwu przykładów częstotliwość to 0.007, a liczba oktaw to 4.

Pierwszy przykład ilustruje małą wartość trwałości (dokładnie jest to 0.1). Wynik widać poniżej:

Drugi przykład pokazuje dużą wartość trwałości. Jest ona równa 0.9. Wynik jest następujący:

Uff i wreszcie dobrnęliśmy do końca :D Po tym wspaniałym pokazie, który był bogato ilustrowany, pora na krótkie podsumowanie. Jak widać generowanie rzeźby terenu nie musi być wcale aż takie trudne, a co więcej może okazać się całkiem fajną zabawą :) Zachęcam abyście sami pobawili się takim generowaniem gdyż naprawdę potrafi to dać sporo satysfakcji.

Mając już opracowane jak współczynniki wpływają na rzeźbę terenu mogę wziąć się za myślenie o strefach klimatycznych. O tym napiszę w następnym artykule, który pewnie nie pojawi się tak szybko jak ten, ale postaram się, aby nie był też opóźniony o parę miesięcy XD Dziękuję za przeczytanie tego co udało mi się wymyślić i mam nadzieję, że już niedługo zajrzysz tutaj z powrotem, aby przeczytać kolejny tekst który przygotuję :)