Analiza przypadku — Tworzenie galaktyki w rzeczywistości mieszanej

Przed wysłaniem Microsoft HoloLens poprosiliśmy społeczność deweloperów o to, jaka aplikacja chce zobaczyć doświadczony wewnętrzny zespół kompilacji dla nowego urządzenia. Ponad 5000 pomysłów zostało udostępnionych, a po 24-godzinnym ankiecie Twitter zwycięzca był pomysłem o nazwie Galaxy Explorer.

Andy Zibits, kierownik sztuki nad projektem, i Karim Luccin, inżynier grafiki zespołu, mówią o współpracy między sztuką a inżynierią, która doprowadziła do stworzenia dokładnej, interaktywnej reprezentacji galaktyki Drogi Mlecznej w Galaxy Explorer.

Technologia

Nasz zespół - składający się z dwóch projektantów, trzech deweloperów, czterech artystów, producenta i jednego testera — miał sześć tygodni, aby zbudować w pełni funkcjonalną aplikację, która pozwoli ludziom uczyć się i poznawać rozległość i piękno naszej Galaktyki Drogi Mlecznej.

Chcieliśmy w pełni wykorzystać możliwość renderowania obiektów 3D bezpośrednio w twojej przestrzeni życiowej, dlatego zdecydowaliśmy się stworzyć realistyczną galaktykę, w której ludzie będą mogli powiększać się blisko i widzieć poszczególne gwiazdy, z których każda ma własną trajektorię.

W pierwszym tygodniu rozwoju wymyśliliśmy kilka celów dla naszej reprezentacji Galaktyki Drogi Mlecznej: Musiało mieć głębokość, ruch i uczucie objętościowe — pełne gwiazd, które pomogą stworzyć kształt galaktyki.

Problem z tworzeniem animowanej galaktyki, która miała miliardy gwiazd, było to, że sama liczba pojedynczych elementów, które wymagają aktualizacji, będzie zbyt duża na ramkę, aby holoLens animować przy użyciu procesora CPU. Nasze rozwiązanie obejmowało złożoną mieszankę sztuki i nauki.

Za kulisami

Aby umożliwić ludziom eksplorowanie poszczególnych gwiazd, pierwszym krokiem było ustalenie, ile cząstek możemy renderować jednocześnie.

Renderowanie cząstek

Bieżące procesory SĄ doskonałe do przetwarzania zadań szeregowych i maksymalnie kilku równoległych zadań jednocześnie (w zależności od liczby rdzeni, które mają), ale procesory GPU są znacznie bardziej skuteczne w przetwarzaniu tysięcy operacji równolegle. Jednak ponieważ zwykle nie współużytkują tej samej pamięci co procesor CPU, wymiana danych między procesorem GPU procesora CPU<>może szybko stać się wąskim gardłem. Naszym rozwiązaniem było utworzenie galaktyki na procesorze GPU i musiało żyć całkowicie na procesorze GPU.

Rozpoczęliśmy testy stresu z tysiącami cząstek punktowych w różnych wzorcach. Pozwoliło nam to uzyskać galaktykę na HoloLens, aby zobaczyć, co działało i co nie.

Tworzenie pozycji gwiazd

Jeden z naszych członków zespołu napisał już kod języka C#, który wygeneruje gwiazdy na ich początkowej pozycji. Gwiazdy znajdują się na wielokropce, a ich pozycja może być opisana przez (curveOffset, ellipseSize, wysokość), gdzie curveOffset jest kątem star wzdłuż wielokropka, elipsySize jest wymiar wielokropka wzdłuż X i Z, a podniesienie właściwego podniesienia star w obrębie galaktyki. W związku z tym możemy utworzyć bufor (ComputeBuffer) aparatu Unity, który zostanie zainicjowany przy użyciu każdego atrybutu star i wysłać go na procesor GPU, w którym będzie działać w pozostałej części środowiska. Aby narysować ten bufor, używamy aparatu Unity DrawProcedural , który umożliwia uruchamianie cieniowania (kod na procesorze GPU) na dowolnym zestawie punktów bez rzeczywistej siatki reprezentującej galaktykę:

PROCESORA:

GraphicsDrawProcedural(MeshTopology.Points, starCount, 1);

GPU:

v2g vert (uint index : SV_VertexID)
{

 // _Stars is the buffer we created that contains the initial state of the system
 StarDescriptor star = _Stars[index];
 …

}

Zaczęliśmy od pierwotnych okrągłych wzorców z tysiącami cząstek. To dało nam dowód, że potrzebowaliśmy, abyśmy mogli zarządzać wieloma cząstkami i uruchomić ją z wydajnymi prędkościami, ale nie byliśmy zadowoleni z ogólnego kształtu galaktyki. Aby poprawić kształt, próbowaliśmy różnych wzorców i układów cząstek z rotacją. Początkowo obiecywały, ponieważ liczba cząstek i wydajności pozostała spójna, ale kształt rozpadł się w pobliżu centrum, a gwiazdy emitowały się na zewnątrz, co nie było realistyczne. Potrzebowaliśmy emisji, która pozwoli nam manipulować czasem i mieć cząstki poruszać się realistycznie, zapętlając się coraz bliżej środka galaktyki.

Próbowaliśmy różnych wzorców i układów cząstek, które obracały się, podobnie jak te.

Próbowaliśmy różnych wzorców i układów cząstek, które obracały się, podobnie jak te.

Nasz zespół przeprowadził pewne badania nad sposobem, w jaki galaktyki działają i zrobiliśmy niestandardowy system cząstek specjalnie dla galaktyki, abyśmy mogli przenieść cząstki na wielokropek na podstawie "teorii fali gęstości", która twierdzi, że ramiona galaktyki są obszarami wyższej gęstości, ale w stałym strumieniu, jak kork. Wydaje się stabilny i solidny, ale gwiazdy rzeczywiście poruszają się i z ramion, gdy poruszają się wzdłuż odpowiednich wielokropka. W naszym systemie cząstki nigdy nie istnieją na procesorze CPU — generujemy karty i orientujemy je wszystkie na procesorze GPU, więc cały system jest po prostu początkowym stanem i czasem. Postęp wygląda następująco:

Progresja systemu cząstek z renderowaniem procesora GPU

Progresja systemu cząstek z renderowaniem procesora GPU

Po dodaniu wystarczającej liczby wielokropków i są ustawione na rotację, galaktyki zaczęły tworzyć "ramiona", gdzie ruch gwiazd zbiega się. Odstępy gwiazd wzdłuż każdej wielokropkowej ścieżki otrzymały pewną losowość, a każda star dostała trochę losowości pozycyjnej. Spowodowało to o wiele bardziej naturalny rozkład star ruchu i kształtu ramienia. Na koniec dodaliśmy możliwość napędzania koloru na podstawie odległości od środka.

Tworzenie ruchu gwiazd

Aby animować ogólny ruch star, musieliśmy dodać stały kąt dla każdej klatki i przenieść gwiazdy wzdłuż wielokropka przy stałej prędkości promieniowej. Jest to główna przyczyna użycia elementu curveOffset. Nie jest to technicznie poprawne, ponieważ gwiazdy będą poruszać się szybciej wzdłuż długich stron wielokropka, ale ogólny ruch czuł się dobrze.

Gwiazdy poruszają się szybciej na długim łuku, wolniej na krawędziach.

Gwiazdy poruszają się szybciej na długim łuku, wolniej na krawędziach.

Dzięki niemu każdy star jest w pełni opisany przez (curveOffset, ellipseSize, podniesienie, wiek), gdzie Age jest akumulacją całkowitego czasu, który minął od momentu załadowania sceny.

float3 ComputeStarPosition(StarDescriptor star)
{

  float curveOffset = star.curveOffset + Age;
  
  // this will be coded as a “sincos” on the hardware which will compute both sides
  float x = cos(curveOffset) * star.xRadii;
  float z = sin(curveOffset) * star.zRadii;
   
  return float3(x, star.elevation, z);
  
}

Pozwoliło nam to wygenerować dziesiątki tysięcy gwiazd raz na początku aplikacji, a następnie animowaliśmy pojedynczy zestaw gwiazd wzdłuż ustalonych krzywych. Ponieważ wszystko jest na procesorze GPU, system może animować wszystkie gwiazdy równolegle bez kosztów dla procesora CPU.

Oto jak wygląda podczas rysowania białych czworokątów.

Oto jak wygląda podczas rysowania białych czworokątów.

Aby każda czworokąt była twarzą kamery, użyliśmy cieniowania geometrii, aby przekształcić każdy star położenie prostokąta 2D na ekranie, który będzie zawierać naszą teksturę star.

Diamenty zamiast czworokątów.

Diamenty zamiast czworokątów.

Ponieważ chcieliśmy ograniczyć przerysowanie (liczba przetworzonych pikseli) jak najwięcej, obracaliśmy nasze czworokąta, aby miały mniejsze nakładanie się.

Dodawanie chmur

Istnieje wiele sposobów, aby uzyskać uczucie objętościowe z cząstkami — od marszu promienia wewnątrz woluminu do rysowania jak największej liczby cząstek, aby symulować chmurę. Marsz ray w czasie rzeczywistym będzie zbyt kosztowny i trudny do utworzenia, więc po raz pierwszy próbowaliśmy zbudowanie systemu imposter przy użyciu metody renderowania lasów w grach — z dużą ilością obrazów 2D drzew stojących przed kamerą. Gdy to zrobimy w grze, możemy mieć tekstury drzew renderowanych z kamery, która obraca się wokół, zapisz wszystkie te obrazy i w czasie wykonywania dla każdej karty billboardu, wybierz obraz zgodny z kierunkiem wyświetlania. Nie działa to również wtedy, gdy obrazy są hologramami. Różnica między lewym okiem a prawym okiem sprawia, że potrzebujemy znacznie wyższej rozdzielczości, lub po prostu wygląda płasko, alias lub powtarzalne.

Podczas drugiej próby próbowaliśmy mieć jak najwięcej cząstek. Najlepsze wizualizacje zostały osiągnięte, gdy dodawaliśmy cząstki i rozmyliśmy je przed dodaniem ich do sceny. Typowe problemy z tym podejściem były związane z liczbą cząstek, które mogliśmy wyciągnąć w jednym czasie i ile obszaru ekranu pokryli, zachowując jednocześnie 60fps. Rozmycie wynikowego obrazu w celu uzyskania tego poczucia chmury było zwykle bardzo kosztowną operacją.

Bez tekstury jest to, jak chmury wyglądają z nieprzezroczystością 2%.

Bez tekstury jest to, jak chmury wyglądają z nieprzezroczystością 2%.

Bycie dodatkiem i posiadanie wielu z nich oznacza, że będziemy mieli kilka czworokątów na sobie, wielokrotnie cieniując ten sam piksel. W środku galaktyki ten sam piksel ma setki czworokątów na sobie i to miało ogromny koszt, gdy odbywa się pełny ekran.

Robienie chmur pełnoekranowych i próba rozmycia ich byłoby złym pomysłem, więc zamiast tego postanowiliśmy pozwolić sprzętowi wykonać pracę dla nas.

Najpierw trochę kontekstu

W przypadku używania tekstur w grze rozmiar tekstury rzadko pasuje do obszaru, w jakim chcemy go używać, ale możemy użyć innego rodzaju filtrowania tekstury, aby uzyskać kartę graficzną, aby interpolować kolor, który chcemy z pikseli tekstury (filtrowanie tekstury). Filtrowanie, które nas interesuje, to filtrowanie dwuliniowe , które oblicza wartość dowolnego piksela przy użyciu 4 najbliższych sąsiadów.

Oryginał przed filtrowaniem

Wynik po filtrowaniu

Korzystając z tej właściwości, widzimy, że za każdym razem staramy się narysować teksturę w obszar dwa razy większy, rozmywa wynik.

Zamiast renderowania na pełnym ekranie i utraty tych cennych milisekund możemy wydać na coś innego, renderujemy do maleńkiej wersji ekranu. Następnie, kopiując tę teksturę i rozciągając ją przez współczynnik 2 kilka razy, wracamy do pełnego ekranu podczas rozmycia zawartości w procesie.

X3 z powrotem przeskaluj do pełnej rozdzielczości.

X3 z powrotem przeskaluj do pełnej rozdzielczości.

Pozwoliło nam to uzyskać część chmury z tylko ułamkiem pierwotnego kosztu. Zamiast dodawać chmury w pełnej rozdzielczości, malujemy tylko 1/64 pikseli i po prostu rozciągamy teksturę z powrotem do pełnej rozdzielczości.

Po lewej stronie, ze skalowaniem z 1/8 do pełnej rozdzielczości; i prawo, z 3 skalowania w górę przy użyciu mocy 2.

Po lewej stronie, ze skalowaniem z 1/8 do pełnej rozdzielczości; i prawo, z 3 skalowania w górę przy użyciu mocy 2.

Pamiętaj, że próba przejścia z 1/64 rozmiaru do pełnego rozmiaru w jednym przejściu będzie wyglądać zupełnie inaczej, ponieważ karta graficzna nadal będzie używać 4 pikseli w naszej konfiguracji, aby zacienić większy obszar, a artefakty zaczynają się pojawiać.

Następnie, jeśli dodamy pełne gwiazdy rozdzielczości z mniejszymi kartami, uzyskamy pełną galaktykę:

Niemal ostateczny wynik renderowania galaktyk przy użyciu gwiazd pełnej rozdzielczości

Gdy byliśmy na właściwej ścieżce z kształtem, dodaliśmy warstwę chmur, zamieniliśmy tymczasowe kropki z tymi, które malowaliśmy w Photoshopie i dodaliśmy dodatkowy kolor. Wynik był Milky Way Galaxy nasze zespoły artystyczne i inżynieryjne czuły się dobrze i spełniły nasze cele posiadania głębokości, objętości i ruchu — wszystko bez opodatkowania procesora CPU.

Nasza ostatnia Galaktyka Drogi Mlecznej w 3D.

Nasza ostatnia Galaktyka Drogi Mlecznej w 3D.

Więcej do eksplorowania

Utworzyliśmy kod dla aplikacji Galaxy Explorer i udostępniliśmy go w usłudze GitHub , aby deweloperzy mogli korzystać z niej.

Chcesz dowiedzieć się więcej na temat procesu programowania dla Galaxy Explorer? Zapoznaj się ze wszystkimi naszymi wcześniejszymi aktualizacjami projektu na kanale Microsoft HoloLens YouTube.

Informacje o autorach

Zdjęcie Karima Luccina przy biurku Karim Luccin jest inżynierem oprogramowania i fantazyjnymi wizualizacjami. Był inżynierem grafiki dla Galaxy Explorer.
Zdjęcie prowadzić sztuki Andy Zibits Andy Zibits jest liderem sztuki i entuzjastą kosmicznym, który zarządzał zespołem modelowania 3D dla Galaxy Explorer i walczył o jeszcze więcej cząstek.

Zobacz też