Jak sprawić, by gracz widział bloki?

15

Piszę grę podobną do Minecrafta, używając silnika Ogre i mam problem. Muszę zoptymalizować swoją grę, ponieważ kiedy próbuję narysować 10000 bloków, mam 2 FPS ... Tak więc wpadłem na pomysł, aby wyświetlać płaszczyzny w blokach i ukrywać niewidzialne bloki. Ale mam problem - skąd mam wiedzieć, które bloki na raz są widoczne dla gracza?

I - jeśli znasz inne metody optymalizacji takiej gry, napisz, co i jak z nich korzystać w Ogre.

m4tx
źródło

Odpowiedzi:

16

Cóż, Ogre już stosuje culling (co w zasadzie nie rysuje niczego, czego nie widać z kamery), ale myślę, że twój problem jest inny.

Naprawdę nie powinieneś wyświetlać 10000 bloków, co zwykle się robi (lub przynajmniej w kilku minecraftach opartych na Ogre3d, takich jak klony, które widziałem (z których też tworzę), a w oryginale) tworzy siatkę ( niektórych fragmentów NxNxN), które mają pokazane zewnętrzne powierzchnie kostek. Oznacza to, że gdy umieścisz 2 kostki obok siebie, 2 dotykające się twarze nie będą widoczne i dlatego nie trzeba ich rysować.

Te twarze należy również narysować w taki sposób: http://www.ogre3d.org/tikiwiki/tiki-index.php?page=DynamicGrowingBuffers, ponieważ współczesne karty graficzne wolą jedną siatkę 100 000 wielokątów niż 1000 oczek 100 wielokątów.

Elva
źródło
10

Istnieje kilka aspektów tego problemu. Po pierwsze, jak rysujesz swoje 10000 bloków? Czy rysujesz je jako 10000 oddzielnych obiektów? Jeśli tak, to prawie na pewno twoja szyjka butelki, a nie brak wybijania okluzji. Powinieneś pogrupować te bloki w mniejszą liczbę oczek (być może kilka tysięcy na siatkę), aby zmniejszyć liczbę wywołań rysunkowych.

Jeśli chodzi o twoje aktualne pytanie, istnieją trzy rodzaje eliminacji okluzji, które przychodzą na myśl.

1) Bloki poza widokiem frustum. Oznacza to bloki, które są za tobą lub dwie z boku. Ogre już je usuwa poprzez ubijanie widoku frustum.

2) Bloki, które są „pod ziemią” lub całkowicie otoczone innymi blokami, dzięki czemu nie można ich zobaczyć pod żadnym kątem. Możesz je zidentyfikować, patrząc na sąsiednie bloki siz. Jeśli wszystkie są solidne, blok jest ukryty. GPU nigdy nie powinna nawet słyszeć o tych blokach - należy je pominąć, gdy budujesz siatkę reprezentującą twoją powierzchnię.

3) Bloki znajdujące się na powierzchni i widoczne z niektórych pozycji na poziomie, ale obecnie ukryte przez wzgórze (lub coś w tym rodzaju). Jest to najtrudniejszy przypadek, do którego sam się nie odniosłem, ale istnieje duża szansa, że ​​w tym przypadku można zastosować zapytania dotyczące okluzji sprzętu.

Jest to bezwstydna wtyczka, ale mam dość dojrzałą bibliotekę, z której korzysta kilka osób do tworzenia klonów Minecraft, w tym niektóre wykorzystujące Ogre. Definiujesz zawartość objętości, która generuje siatkę powierzchni, którą możesz następnie renderować. Oto strona główna:

http://www.thermite3d.org/

A oto film przedstawiający projekt, który go używa:

http://www.youtube.com/watch?v=Jju6WRPEK7o

David Williams
źródło
4

Możesz użyć wygładzania tylnej powierzchni do wyrywania wierzchołków i powiązanych z nimi pikseli, które nie są skierowane w stronę odtwarzacza. Buforowanie głębokości powinno zająć się resztą. 10k bloków to naprawdę niewiele, mój 5770 może renderować 100k verts przy 1500 fps. Myślę, że robisz coś bardzo źle.

DeadMG
źródło
Zgadzam się. Jest to prawdopodobnie problem z czymkolwiek innym.
Notabene
1

Jeśli masz 10000 oddzielnych obiektów, wąskim gardłem jest prawdopodobnie liczba pierwotna, a nie wierzchołek, wielokąt lub wypełnienie. Upiecz swoje obiekty w mniejszą liczbę obiektów o wyższych wielokątach, aby zwiększyć szybkość.

Minecraft ma pojęcie bloków kostek, ale w tej chwili nie mogę znaleźć odniesienia.

Oto moje eksperymenty na rysowaniu ton kostek różnymi technikami. Nie obejmuje pieczenia (jeszcze).

Jari Komppa
źródło
0

To, co robię, jest po utworzeniu mojej tablicy bloków, ale zanim utworzę wierzchołki, uruchamiam sub o nazwie UpdateBlockVisiblility.

Okręt podwodny po prostu sprawdza sąsiadów bloku i odpowiednio aktualizuje widoczną wartość logiczną bloków.

#define BLOCKFACE_NORTH 0

#define BLOCKFACE_SOUTH 1 

etc etc etc

if(IsBlockAt(NorthOfBlock))
  Blocks[Whatever].facevisible[BLOCKFACE_NORTH] = false;

Następnie tworzę wierzchołki tylko dla twarzy, jeśli jest ona widoczna! Prosty :)

BMW
źródło