Łączenie geometrii / siatki bez utraty korzyści

11

W Three.js możemy po prostu scalić geometrię, aby ograniczyć liczbę wywołań losowania, a tym samym zwiększyć wydajność. W prostym teście z jednym materiałem mogłem narysować 50 000 kostek + cienie @ 60 fps na moim GPU GTX660. Bez scalenia geometrii problem spowodował już 5000 kostek.

Zastanawiam się, jak zachować korzyści wynikające z renderowania każdej siatki sześcianu na własną rękę. Na przykład, jak wybrać siatkę sześcianu, gdy wszystko jest scalone w jedną geometrię? Domyślnie nie jest to oczywiście możliwe.

Czy istnieje jakaś wspólna technika dla tego problemu? W końcu mam wszystkie nierozproszone obiekty siatki nawet po scaleniu. Więc musi być jakiś sposób na wykorzystanie ich do zbierania?

Co chcę robić w pigułce

  • SimCity jak gra do nauki
  • Każdy dom jest siatką sześcianu
  • Chcesz wyrenderować 50 000 domów i mieć możliwość dodawania i usuwania domów
  • Wybór domu za pomocą kursora myszy (kompletacja) musi być możliwy
użytkownik990827
źródło
Nie jestem pewien, czy jest to dla ciebie przydatne, ale wspominam o tym dla kompletności. Simplygon ma model wyceny oparty na opłatach licencyjnych dla niezależnych programistów i może wykonać wiele takich operacji łączenia i partycjonowania siatki w czasie projektowania.
steeveeet,

Odpowiedzi:

11

Ok, rozumiem. Po scaleniu całej geometrii nadal mam pojedyncze siatki w tablicy. Mogę więc po prostu użyć tych siatek do rastrowania, nawet jeśli nie są nawet renderowane. Zajęło mi to trochę czasu, aby to zrozumieć.

wprowadź opis zdjęcia tutaj

Do kompletacji używam tej implementacji oktty: http://threejs.org/examples/#webgl_octree_raycasting

Zmniejsza to liczbę testów przecięcia na aktualizację z 50 000 do ~ 500. Bez oktetu liczba klatek na sekundę znacznie spadnie.

Pomarańczowy kadłub zbierający, który widzisz, jest w rzeczywistości renderowaną siatką (wywołanie +1) ze zmienionym materiałem i zmodyfikowanym rozmiarem.

wprowadź opis zdjęcia tutaj

Myślę, że następnym krokiem jest zaimplementowanie jakiegoś rodzaju partycjonowania mapy. To znaczy, podziel scaloną geometrię na kilka części. Powodem tego jest to, że scalona geometria ma dużą liczbę wierzchołków. Oznacza to, że jeśli przesunę mapę o 99% poza ekran, karta graficzna nadal będzie musiała przetwarzać wszystkie wierzchołki, ponieważ geometria jest nadal widoczna, przynajmniej 1%. Więc jeśli jest rozbity, tylko widoczne fragmenty muszą zostać zrenderowane.

użytkownik990827
źródło
Dziękuję bardzo za ten wgląd. Próbowałem również znaleźć sposób, aby to zrobić, i myślę, że twoje rozwiązanie tutaj jest najbardziej doskonałe! Szybkie pytanie: jakie właściwości są wymagane do działania rayCaster.intersectObjects () na lokalnej liście obiektów (np. Three.Object3D)?
AlvinfromDiaspar
Bardzo ładnie wykonane.
ClassicThunder
Mam podobny problem, ale jakoś nie mogę uzyskać rastrowania z r70. Czy zrobiłeś coś specjalnego podczas tworzenia i łączenia pudeł? Używam następującego kodu ( pastebin.com/PStaAF3P ) do tworzenia i łączenia węzłów, ale może brakuje czegoś, aby uruchomić raycaster?
fhahn
Szybkie pytanie: Robię coś bardzo podobnego do ciebie (mapa 3D oparta na danych geoJSON). Za pomocą tej metody, za każdym razem, gdy obracasz kamerę, czy musisz również obracać istniejące wcześniej siatki budynków? A może po prostu dodajesz poszczególne pola do sceny, ale ich nie renderujesz?
Spencer,
@Spencer Nie trzeba obracać. Trzymam pojedyncze pola w globalnej tablicy i dodam tylko scaloną geometrię do sceny. Następnie możesz wykonać raycasting z obiektem w globalnej tablicy, ponieważ raycaster zależy od matrycy kamery i położenia każdego pola. Najprawdopodobniej nie najlepszy sposób, był to dla mnie tylko dowód koncepcji. W tym momencie nie robię już trzech.js.
user990827,
1

Aby wybrać, możesz również renderować identyfikatory dla każdej kostki do innego celu renderowania i po prostu sprawdź, jaka wartość identyfikatora znajduje się na kursorze. Zaletą jest to, że kompletacja jest idealna w pikselach i działa skutecznie również w przypadku bardziej złożonej geometrii.

Jeśli wszystkie obiekty mają tę samą geometrię, możesz użyć renderowania instancji. Jeden strumień określa geometrię, podczas gdy inny określa właściwości na wystąpienie (np. Transformacja). W celu eliminacji frustum należy zbudować strumień instancji dla każdej ramki na podstawie testu widoczności. Jeśli masz dużą liczbę obiektów, możesz je umieścić w luźnej oktecie lub w celu przyspieszenia ubijania.

JarkkoL
źródło
0

Nie jestem pewien co do szczegółów pliku Three.js, ale w ogóle przychodzą mi na myśl dwa możliwe świnie wydajnościowe OpenGL:

  1. Czy rozważałeś wystąpienie? Będziesz potrzebował tylko jednego połączenia losowania i zużyjesz mniej pamięci VRAM.
  2. Czy poważnie przyjrzałeś się algorytmowi kompletacji? Jeśli na przykład kostki mają objętości graniczne na liście zamiast drzewa, to wyjaśniałoby to różnicę tej wielkości.
bogglez
źródło
0

Innym podejściem, jakie możesz zastosować, jest wbudowanie atrybutu wierzchołka do geometrii i umieszczenie logiki podświetlania w module cieniującym fragmenty. Jest to niezwykle przydatne, gdy nie chcesz mieć dwóch kopii danych w pamięci, a będziesz mieć większą kontrolę nad sposobem realizacji wyróżnienia.

HaoCS
źródło