Czy można zbudować sześcian o mniej niż 24 wierzchołkach

14

Mam świat oparty na kostkach, taki jak Minecraft i zastanawiam się, czy istnieje sposób na zbudowanie kostki z mniej niż 24 wierzchołkami, aby zmniejszyć zużycie pamięci.

Wydaje mi się to niemożliwe z dwóch powodów: normalne nie wyszłyby dobrze, a tekstury na twarz nie działałyby.

Czy tak jest, czy się mylę? Może jest jakaś nowa, wymyślna technologia DX11, która może pomóc?

Edycja: Żeby wyjaśnić, mam 2 wymagania: potrzebuję normałów powierzchni dla każdej powierzchni kostki, aby wykonać odpowiednie oświetlenie i potrzebuję sposobu na zajęcie się innym indeksem w tablicy tekstur dla każdej powierzchni kostki

Telanor
źródło
1
Czy chcesz zmniejszyć zużycie pamięci karty graficznej lub pamięci RAM ?
doppelgreener
1
Dane wierzchołków są teraz przechowywane w pamięci RAM i na GPU, więc zmniejszenie ich zmniejszy oba.
Telanor

Odpowiedzi:

9

Jeśli potrzebujesz tylko normalnych na twarz, a jeśli twoje texcoords dla twarzy są ściśle 0/0, 0/1, 1/0, 1/1 (lub podobne do twojego układu), możesz zbudować sześcian z 8 wierzchołkami oraz indeksy 30 (pasek z restartem) lub 36 (lista). Pobierz normalne i tekstowe przy użyciu stałego wyszukiwania tablicowego na podstawie SV_VertexID w swoim module cieniującym wierzchołki.

Oznacza to, że nie musisz nawet umieszczać tekstów ani normałów w buforze wierzchołków, co zapewni jeszcze więcej oszczędności pamięci.

Idąc dalej, nadal możesz przejść do 24 wierzchołków na kostkę, ale także użyć instancji. Każda kostka miałaby stały rozmiar w buforze wierzchołków (1x1x1) i miałbyś współczynnik skalowania i pozycję (zakładając, że twoje kostki się nie obracają, a jeśli macie, to macierz) jako dane dla instancji. W przypadku nieobrotowego jednorazowy koszt wynosi 24 wierzchołki, ale wtedy każda kostka potrzebuje tylko 6 pływaków, aby w pełni określić. W obrotowej obudowie patrzysz na 16 liczb zmiennoprzecinkowych, ale nawet to jest znaczną oszczędnością (w tym przypadku bardziej prawdopodobne jest wąskie gardło po stronie procesora w przypadku transformacji macierzowych - w przypadku nieobrotowej obudowy budującej matrycę w locie w twój moduł cieniujący wierzchołki - nawet jeśli jest zrobiony dla jednego wierzchołka, jest tak głupio szybki, że nawet nie musisz się tym martwić).

W przypadku tekstur na twarz wystarczy użyć tablicy tekstur. Musisz oczywiście upewnić się, że każda taka tekstura w tablicy ma ten sam rozmiar, i nadal będziesz musiał przerwać bieżącą partię, jeśli sama tablica musi się zmienić, ale w przeciwnym razie dobrze sobie poradzi. Dodaj trzeci tekstowy tekst do definicji wierzchołka, który określa plasterek tablicy do użycia dla każdej twarzy.

Nie potrzebujesz GS z tym i powinien on działać szybciej niż przy użyciu jednego, ponieważ włączenie etapu modułu cieniującego geometrię spowoduje dodatkowe własne obciążenie.

W swoim silniku mam kod porównawczy, który po prostu rysuje kilka kostek za pomocą tej metody, i mogę łatwo przeżuć ponad 300 000 kostek, wciąż czyszcząc 60 klatek na sekundę na stosunkowo niskiej jakości GPU i nie robiąc nic innego, aby zoptymalizować proces . Wprawdzie nie jestem ich oświetleniem ani teksturowaniem, ale mam włączone mieszanie alfa, wyłączone wygładzanie tła i ogólnie równoważy to z moją częścią „nie robienia niczego innego w celu optymalizacji”, więc powinno dać ci rozsądne wyobrażenie o rodzaju boisko można uderzyć tą metodą.

Maximus Minimus
źródło
1
Używałem już instancji i działa świetnie dla mniej niż 40 tysięcy kostek. Ale mam co najmniej 256 tys. Kostek, a instancja też tego nie obsługiwała. Jednak użycie SV_VertexID przy wyszukiwaniu wydaje się bardzo obiecujące.
Telanor
Jak duży był Twój bufor na instancję? Próba umieszczenia ich wszystkich w ogromnym buforze może skończyć się zadławieniem GPU; Generalnie przechowuję bufory dla poszczególnych instancji w wystarczającej ilości miejsca dla 64k obiektów (w razie potrzeby dzielę wywołania losowania), używam wzorca discard / no-overwrite i piszę bezpośrednio do odwzorowanego wskaźnika zamiast kopiowania z tablicy pośredniej, która działa bardzo dobrze .
Maximus Minimus
Niezbędne jest także utrzymanie niskiej liczby map. Mapuj / pisz jedną kostkę / odkrywaj 40k razy będzie znacznie wolniej niż mapuj / zapisuj 40k kostek / odkrywaj tylko raz. Jeśli robiłeś to pierwsze, spróbuj przełączyć się na drugie.
Maximus Minimus
15

Myślę, że główna optymalizacja, jaką możesz wykonać, polega na tym, że nie każda kostka faktycznie potrzebuje wszystkich 24 wierzchołków . W rzeczywistości jedynymi sześcianami, które potrzebują 24 wierzchołków, są te, które unoszą się w powietrzu, co jest prawdopodobnie rzadkim zjawiskiem.

Zasadniczo generuj quady tylko dla twarzy mających kontakt z powietrzem . Oznacza to, że jeśli dwa sześciany się stykają, nie trzeba generować żadnych wierzchołków dla twarzy, do której się dotykają.

Poniższy obraz pokazuje tę koncepcję, ale w 2D dla łatwiejszego zrozumienia. Na obrazie znajduje się 11 zajętych bloków (reprezentowanych przez wypełnione szare kółka), które normalnie wymagałyby reprezentacji 4 x 11 = 44 krawędzi (4, ponieważ jest to kwadrat, a nie sześcian). Ale jak widać, naprawdę musisz narysować krawędzie tylko wtedy, gdy stykają się z pustym kwadratem, który w tym przypadku ma tylko 8 krawędzi.

wprowadź opis zdjęcia tutaj

Jeśli tak prostemu przykładowi w 2D udało się zmniejszyć 44 krawędzie do 8 krawędzi, wyobraź sobie korzyści w dużym świecie 3D ...

Takie podejście opisano w tym artykule , które polecam przeczytać, mimo że jest skierowane do OpenGL. Koncepcje powinny być jednak dość uniwersalne.

Prawdopodobnie możesz również użyć modułu cieniującego geometrię do generowania wierzchołków w locie na GPU, co eliminuje potrzebę przechowywania ich w pamięci, ale nie mam z tym doświadczenia, ani nie wiem, jak dobrze by to działało w przypadku dużych świat.

David Gouveia
źródło
1
Bardzo ciekawy artykuł. Robię już optymalizację krawędzi, co z pewnością bardzo pomaga. Spróbuję shaderów geometrii i zobaczę, czy to się uda.
Telanor
Czy masz na myśli, użyj modułu cieniującego geometrię i iloczynu krzyżowego, aby obliczyć normalne? Zastanawiałem się nad tym, jak stworzyć osobny program dla płaskich powierzchni (nie interesują mnie tekstury).
dreta
@dreta Nie tylko to, ale przechodząc do punktu, w którym wysyłasz tylko centroidy kostki jako listę punktów, a wszystkie wierzchołki są emitowane przez GS. Być może zakoduj sąsiednie informacje w punktach, aby moduł cieniujący generował tylko te twarze, które są naprawdę potrzebne, choć nie zastanawiałem się, jak to zrobić.
David Gouveia
Jeśli chcesz wydajności, nie używaj modułu cieniującego geometrię ... Prawie zawsze. Całkowicie zepsuły rurociąg. Jeśli chcesz wygenerować geometrię na GPU, użyj shadera obliczeniowego lub openCL
Robert Fraser