Wydajna metoda renderowania masywnego terenu w XNA


10

Tworzę grę XNA, która wymaga dużej przestrzeni dla graczy. Obecnie używana mapa wysokości testu to 4096 x 4096 i jest zapisywana jako 4-bitowy BMP.

Próbuję wziąć ten ogromny plik mapy wysokości i wyrenderować go w grze. Problem, na który wpadam, polega na tym, że nieefektywne jest ładowanie całego terenu na raz do pamięci, ponieważ zużywa on większość dostępnej pamięci.

Innym problemem, na jaki natknąłem się, jest to, że nie mogę renderować terenu w jednym prymitywnym z powodu twardego limitu ustawionego w XNA.

Powiedziawszy to, natknąłem się na szereg rozwiązań, z których wszystkie wymieniłem poniżej:

  • Renderowanie oparte na bieżącej lokalizacji użytkownika - w zasadzie rysowanie kwadratu wokół użytkownika bez względu na jego orientację w świecie. Tego też nie chciałem, ponieważ nadal renderujesz przestrzeń, której użytkownik nie widzi.
  • Renderowanie oparte na orientacji i pozycji użytkownika - znalazłem formułę do pobrania trójkąta, który powinien zawierać piksele mapy wysokości, które mają być renderowane, ale okazało się to bardzo trudne.
  • Dzielenie terenu na wiele fragmentów i renderowanie tych, które są najbliżej użytkownika - Nadal mało wydajne, ponieważ nadal renderujesz fragmenty, których ludzie nie zobaczą. Jest to pracochłonne, ponieważ muszę podzielić mapę wysokości na kilka części, a skalowalność staje się dużym problemem.

Po wypróbowaniu tych rozwiązań mam dość pomysłów na to, co robić. Otrzymałem odpowiedzi, w których ludzie mówią mi, żebym robił te skomplikowane algorytmy, ale po prostu nie mam pojęcia, jak podejść do ich wykonania.

Zasadniczo więc proszę o prosty, prosty sposób renderowania ogromnych terenów w XNA z najwyższą wydajnością.

Ogólnie jestem raczej nowy w tworzeniu gier, ale jestem gotów zbadać, czy wydaje się to obiecujące.

Aktualizacja 1: Po zbadaniu metody geoclipmapping zacząłem ją kodować. Mam całą matematykę, a gra działa. Jest to jednak wyjątkowo nieefektywne - co prawdopodobnie jest złym kodowaniem z mojej strony. Działa z prędkością 2 klatek na sekundę i wykorzystuje cały rdzeń mojego procesora. Spróbuję ulepszyć kod, ale myślę, że będę potrzebować dodatkowej pomocy, więc oto Pastebin kodu dla klasy menedżera terenu. Wrócę później z większą ilością wyników, jeśli kiedykolwiek będę mieć większą wydajność.


1
Co ciekawe, technika, o której mówisz, wydaje się podobna do tej, z której korzysta ID Software w swojej nadchodzącej grze, Rage. Używają „megatexture”, a następnie przesyłają strumieniowo wymagane części do GPU. Wygłosił o tym rozmowę, ale tutaj jest artykuł w Wikipedii, może być inspirujący: en.wikipedia.org/wiki/MegaTexture

Odpowiedzi:


5

Zazwyczaj stosuje się podejście do porcji. Rzadko można testować każdy trójkąt z setek tysięcy, aby sprawdzić, czy należy go renderować. Zamiast tego większość algorytmów renderowania terenu wykorzystuje strukturę danych przestrzennych do dynamicznego renderowania widocznych części terenu.

Łatwa do zaimplementowania struktura danych nazywa się quadtree . Krótko mówiąc, aby użyć kwadratu, zobaczysz frustum gracza, które przecina się z najwyższym poziomem kwadratu, a dla wszystkich części, które są częściowo widoczne (tj. Płaszczyzny frustum przecinają fragment), dzielisz i testujesz wszystkie dzieci kawałki, pomijając te poza frustum. To da całkiem dokładne przybliżenie do rzeczywistej widocznej geometrii z zaledwie kilkoma poziomami rekurencji.

Bardziej zaawansowane renderery terenu używają algorytmu, aby dostroić nie tylko widoczną geometrię, ale także szczegóły tej geometrii. Geomipmapping (i jego względne geoclipmapping) jest obecnie stosunkowo popularny, ale nie jest to trywialna rzecz do zaimplementowania.

edytuj: Oto porządny opis zarówno geoclippingu, jak i wybijania frustum.

Mam również wątpliwości, czy 4 bity dla mapy wysokości są w rzeczywistości wystarczające do stworzenia ładnie wyglądającego terenu, chyba że wykonujesz dużo wygładzania wyniku.


Rzuciłem okiem na ten artykuł i zdecydowałem, że najpierw zastosuję metodę geoclipmapping, ponieważ wygląda na to, że byłby najbardziej wydajny w wyświetlaniu dużej ilości terenu. Wrócę z wynikami.

3

Każde podejście, które wymaga wykonania pracy dla pojedynczej ramki w celu załadowania danych do GPU, będzie wadliwe.

Oto ogólny zarys jednego podejścia, które powinno się dobrze sprawdzać:

Powinieneś dzielić swój teren na (dość duże) fragmenty, ładując je do stałych buforów wierzchołków (głębokość bitowa mapy wysokości nie ma znaczenia!). Te bufory wierzchołków będą po prostu siedzieć w pamięci GPU, czekając na ich renderowanie. Będziesz musiał poeksperymentować z odpowiednim rozmiarem, ale 128x128 to być może dobre miejsce na rozpoczęcie.

W przypadku terenu o wymiarach 4096 x 4096 jesteś trochę poza limitem tego, co byłoby wygodne ładowanie na GPU naraz - prawdopodobnie jest to kilkaset MB danych wierzchołków (chociaż możesz to zmniejszyć do ~ 64 MB, jeśli jesteś sprytny). Może być więc konieczne ładowanie i rozładowywanie buforów wierzchołków z GPU w tle.

(Jeśli zaimplementujesz ładowanie fragmentów w tle, powinno to być wyjątkowo skalowalne!)

Gdy masz już dane wierzchołków na GPU, nadszedł odpowiedni czas, aby wykonać redukcję widoczności dla poszczególnych porcji . Nie ma potrzeby wysyłania polecenia renderowania fragmentu, jeśli wiesz, że znajduje się on za kamerą.

Prawie nigdy nie powinieneś robić procesorów na trójkącie !

Procesor graficzny wytrąci trójkąty, które są poza ekranem znacznie szybciej niż kiedykolwiek będziesz w stanie.

Aby uzyskać więcej informacji na temat wydajności, spójrz na tę odpowiedź w witrynie Game Dev.


0

W żadnym wypadku nie jestem ekspertem w XNA, więc poprawcie mnie, jeśli się mylę, ale miałem wrażenie, że istnieje optymalizacja dla takich sytuacji. Wiem, że możesz ustawić odległość renderowania i po tym punkcie nic nie renderuje, w twoim przypadku byłby to pozostały teren. Jednak pozostawia to dość nieatrakcyjną przewagę renderowanemu światu, więc musiałbyś wdrożyć coś takiego jak zamglenie, które ma większość gier z otwartym światem.


Istnieją wbudowane rozwiązania, ale problem, na który natrafiłem, polegał na tym, że próbowałem renderować jedną dużą prymityw, który przekroczył limit wielokątów dla prymitywów. Dlatego nie rysuje, po prostu rzuca wyjątek.
sammarks
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.