Wcześniej zaimplementowałem marszowe kostki / czworościany do renderowania IsoSurface. Działało ( YouTube ), ale wydajność była tragiczna, ponieważ nigdy nie wdrożyłem do wdrażania zmiennej Poziomu Szczegółowości na podstawie odległości widzenia (lub nawet usuwania starych, odległych fragmentów).
Tym razem postanowiłem zrobić kolejny krok i zrobić to poprawnie. Zacząłem od utworzenia OctreeNode, który działa w następujący sposób po Build()
wywołaniu.
- Jeśli fragment jest zbyt mały, aby go zbudować, natychmiast wróć.
- Sprawdź, czy powierzchnia przechodzi przez objętość tego fragmentu.
- Jeśli tak, to zdecyduj, czy chcemy podnieść LOD (ponieważ kamera jest blisko)
- Jeśli tak, to spawnuj 8 dzieci i wywołaj na nich ten sam proces
- Jeśli nie, zbuduj siatkę, używając wymiarów bieżącego węzła
Niektóre PseudoCode:
OctNode Build() {
if(this.ChunkSize < minChunkSize) {
return null;
}
densityRange = densitySource¹.GetDensityRange(this.bounds);
if(densityRange.min < surface < densityRange.max) {
if(loDProvider.DesiredLod(bounds)² > currentLoD) {
for(i 1 to 8) {
if(children[i] == null) {
children[i] = new OctNode(...)
}
children[i] = children[i].Build();
}
} else {
BuildMesh();
}
return this;
}
}
¹ Oprócz gęstości zwracanej w punkcie, źródło gęstości może określać możliwy zakres gęstości dla danej objętości.
² Dostawca LoD przyjmuje ramkę ograniczającą i zwraca maksymalną pożądaną wartość LoD na podstawie położenia kamery / frustum, ustawień użytkownika itp.
Więc ... To wszystko działa całkiem dobrze. Używając prostej kuli jako źródła gęstości i pokazując wszystkie węzły:
I tylko liście:
Istnieje jednak kilka problemów:
- Muszę zdefiniować początkowy wolumin ograniczający (im większy, tym więcej przetwarzania muszę wykonać)
- U korzenia drzewa nie mam pojęcia, jak głębokie będą liście, więc moja numeracja LoD zaczyna się od najniższej jakości (korzenia) i rośnie wraz ze zmniejszaniem się kawałków. Ponieważ LoD jest teraz w stosunku do początkowej objętości, nie ma większego zastosowania, gdy chcę robić rzeczy w określonych rozmiarach / jakościach.
Myślałem o kilku opcjach, ale obie wydają się wadliwe:
- Zachowaj kolekcję oktetów i dodawaj / usuwaj w zależności od odległości. Nie widzę, jak ładnie się zestawiłbym w siatkę¹, a ponadto potrzebowałbym listy znanych pustych węzłów, szczególnie jeśli chcę dowolnych powierzchni 3D (aby uniknąć wielokrotnego ponownego obliczania pustych objętości)
- Dodaj węzeł nadrzędny do bieżącego katalogu głównego, a następnie dodaj siedem rodzeństwa dla oryginalnego węzła. To działałoby i byłoby dostępne na żądanie, ale wydaje się, że rozsądne zmniejszenie się rozsądnie, gdy gracz porusza się po krajobrazie. Sprawiłoby to, że liczby LoD byłyby jeszcze mniej znaczące.
¹ [W wyjaśnieniu do Q poniżej] Obecnie, jeśli 2 fizycznie sąsiadujące węzły w drzewie znajdują się w różnych LOD, mam trochę kodu, aby zmusić wierzchołki tak, aby nie było szwu podczas generowania siatek. Jestem w stanie to zrobić, znając gęstość wielu otaczających węzłów. W scenariuszu, w którym mam 2 niezależne oktawy obok siebie, nie miałbym łatwego sposobu na odzyskanie tych informacji, co spowodowałoby szwy.
Jaki jest optymalny sposób na to?