IV Ogólnopolska Konferencja Inżynierii Gier Komputerowych, Siedlce 2007 Zaawansowane i efektywne systemy cząsteczkowe w grach komputerowych. Michał Mocarski Politechnika Wrocławska Streszczenie Referat opisuje systemy cząsteczkowe jako narzędzie do generowania efektów specjalnych w grach komputerowych. Omówione zostaną zastosowania, sposoby przedstawienia reprezentacji graficznej i fizycznej cząstek, techniki animacji cząstek i nietypowe podejścia do systemów cząsteczkowych. 1. Wstęp Gry komputerowe od zawsze starały się o atrakcyjną oprawę graficzną w związku z tym grafika komputerowa potrzebowała sposobu na wyświetlanie efektów specjalnych takich jak ogień, wybuchy czy efekty atmosferyczne. Wszystkie powyższe mają wspólną cechę efekt graficzny tworzy duża ilość małych cząstek dlatego właśnie w grafice komputerowej używa się do ich reprezentacji systemów cząsteczkowych 1
Michał Mocarski Zaawansowane I efektywne systemy cząsteczkowe w grach komputerowych 2. Czym są systemy cząsteczkowe? Efekty cząsteczkowe pozwalają na reprezentację wielu zjawisk występujących w otaczającym nas świecie. Zaliczamy do nich: - ogień - dym - wystrzały - śnieg - deszcz - wybuchy - gwiazdy itp. Efekty cząsteczkowe stanowią nieodłączną część obecnie implementowanych silników graficznych. W podstawowych wersjach są one niesamowicie elastyczne. Opisujemy je zazwyczaj używając cech takich jak: - pozycja aktualna - prędkość - przyspieszenie - czas życia - aktualny kolor 3. Sposób reprezentacji graficznej poszczególnych cząstek 3.1 Quady Poszczególne cząsteczki mogą być bardzo zróżnicowane zwykły punkt jest przeważnie niewystarczający, jednak przeważnie są stosunkowo małe i płaskie. Możemy je zatem wyświetlać za pomocą zbioru quadów (Rys 3.1) umieszczonych w vertex buforach. Rozwiązanie takie jest stosunkowo proste i bardzo elastyczne. 6 1 2 5 Rys. 3.1. Schemat quadu 4 3 2
IV Ogólnopolska Konferencja Inżynierii Gier Komputerowych, Siedlce 2007 Niestety w jego przypadku musimy skupić się na pozycji wierzchołków muszą one być za każdym razem aktualizowane by znajdowały się w takiej samej odległości od środka cząsteczki i żeby leżały na płaszczyźnie, która jest prostopadła do kierunku patrzenia kamery. 3.2 Point sprite y Innym sposobem jest użycie tzw. Point sprite ów. Są one bardzo wygodnym i dosyć optymalnym spodobem na renderowanie cząstek, gdyż umożliwiają nam łatwe renderowanie cząsteczki przy pomocy jednego oteksturowanego punktu karta graficzna zajmuje się wygenerowaniem dodatkowych wierzchołków, skopiowaniem wartości koloru i przypisaniem im koordynat teksturowania tak, by można było osiągnąć efekt taki jak przy renderowaniu zwykłego quadu. Wydaje się to świetnym rozwiązaniem, jednak okazuje się iż ma pewne wady wszystkie wartości wierzchołka źródłowego są kopiowane do nowo utworzonych przez co nie mamy wpływu na informacje o kolorze poszczególnych rogów punktu i wierzchołki są nierozróżnialne. Ponadto koordynaty teksturowania i pozycje nowych wierzchołków są generowane dynamicznie, bez naszego wpływu na nie. Powoduje to, iż na samym starcie część bardziej zaawansowanych technik jak obrót cząsteczek czy uzyskanie specjalnych cech dla każdego wierzchołka jest niemożliwe. Dochodzą do tego dodatkowe problemy teoretycznie nie każdy sprzęt musi obsługiwać point sprite y (a część urządzeń realizuje je w sterownikach mimo iż zgłaszają, że wspierają je) a ponadto maksymalna wielkość cząsteczek określana jest przez kartę graficzną i może się różnić między modelami. Kolejną niedogodnością jest różnica między PointSprites w DirectX, a rozszerzeniem arb_point_sprites w OpenGL. Windows DDK nakazuje nadmienić koordynaty teksturowania liniowo generowanymi współrzędnymi (lewy górny róg [0,0] a prawy dolny [1,1]) jednak nie opisuje on które współrzędne mają być nadpisane, ponadto DirectX nie umożliwia ich wskazania, przez co nadpisywane są profilaktycznie wszystkie. Uniemozliwia to zastosowanie bardziej zaawansowanych technik, gdyż na drodze między Vertex Shaderem a Pixel Shaderem zostają nadpisane wszystkie współrzędne teksturowania. Nieco lepiej sytuacja wygląda w OpenGL rozszerzenie arb_point_sprites używa flag do oznaczenia współrzędnych teksturowania. Druga różnica między OpenGL em a DirectX em to sposób odrzucania niewidocznych punktów. Tutaj lepiej wypada DirectX, gdyż WindowsDDK nakazuje odrzucać karcie punkty których wszystkie wierzchołki wypadają poza viewport. OpenGL przycina według środka punktu, więc może on nagle zniknąć. 3
Michał Mocarski Zaawansowane I efektywne systemy cząsteczkowe w grach komputerowych Tabela 3.1 - porównanie MaxPointSize Vendor Device MaxPointSize 3Dfx Voodoo3 1.0 Ati Mobility Radon X800GT 256.0 Ati Radon 9600 256.0 Ati Radon 9000 256.0 Intel i815 256.0 Matrox G550 128.0 Nvidia GeForce 6800 8,192.0 Nvidia GeForce FX 5200 8,192.0 Nvidia GeForce4 MX 440 64.0 Nvidia GeForce2 MX 400 64.0 Nvidia Riva TNT2 M64 1.0 S3 ViRGE DX 1.0 3.3 Geometry Shaders Najnowsze karte graficzne wspierające Shader Model 4.0 oferują jednostki geometry shaders i technikę stream out. W kartach tych wierzchołki transformowane są najpier za pomocą jednostek vertex shader, następnie całe prymitywy przetwarza geometry shader, a po rasteryzacji fragmentami zajmuje się pixel shader. Jest to bardzo elastyczne, szczególnie, że geometry shader umożliwia nam generowanie i usuwanie geometrii. Jak mogą korzystać particle systemy pod Shader Model 4.0? Renderowalibyśmy bufor wierzchołków które byłyby punktami. Jednostka vertex shader zajmowałaby się animacją naszych punktów. Przetransformowane punkty trafiałyby do geometry shadera. Jednostka ta miałaby zdefiniowane wyjście generowałaby 2 trójkąty tworząc w locie quad. Nad procesem mamy pełną kontrolę możemy obracać nasz quad, wyginać i robić cokolwiek nam się podoba. Wygenerowany quad podlegałby rasteryzacji, a gotowe punkty moglibyśmy per-pixel oświetlić, ukryć itp. Jak widać sposób ten jest najelastyczniejszy, wydajny i odzwierciedla dokładnie sposób w jaki myślimy o tworzeniu pojedynczej cząsteczki. 4
IV Ogólnopolska Konferencja Inżynierii Gier Komputerowych, Siedlce 2007 4. Animowanie cząsteczek 4.1 Systemy stanowe Systemy stanowe zakładają, że w każdym momencie mamy dostępny szereg informacji o cząsteczce (np.pozycja, kolor, prędkość, przyspieszenie, czas życia) w każdym momencie. Dodatkowo aktualizację tych informacji przeprowadzamy w sposób rekurencyjny aby określić nowy stan cząsteczki potrzebujemy stanu poprzedniego. Takie rozwiązanie jest bardzo elastyczne, szczególnie gdy CPU ma dostęp do tych danych wtedy cząsteczki mogą wchodzić w interackję ze światem np. odbijać się od ścian. W jaki sposób zrealizować takie systemy? 4.1.1 Realizacja na CPU Standardowe rozwiązanie implikuje aktualizowanie bufora wierzchołków i przesyłanie go do karty co aktualizację. Niestety takie rozwiązanie wymaga aby CPU przetwarzał wszystkie wierzchołki, a bufor był przesyłany do karty z każdą aktualizacją. Powoduje to, iż takie systemy mimo że są bardzo elastyczne, mają niską wydajność. Istnieje jednak sposób na rozwiązanie tego problemu. 4.1.2 Realizacja na GPU Shader Model 3.0 udostępnia opcję vertex texture fetch, która umożlwia odczyt tekstury w jednostce vertex shader. Podobnie sytuacja wygląda w Shader Model 4.0 (tam nawet jednostki geometry shader mają możliwośc odcyztu tekstur). Aby wykorzystać wyłącznie GPU do przetwarzania wierzchołków musimy rozbić ich renderowanie na co najmniej 2 przebiegi. Pierwszy uaktualniający i drugi rysujący. Pierwszy będzie odczytywał z tekstury dane na temat wierzchołka, przetwarzał je i zapisywał do tekstury, a drugi po prostu rysował korzystając z pozycji zapisanych w teksturze. Teraz nasuwają się dwa pytania co z kolizjami i alpha blendingiem. Oczywiście kolizje można policzyć na karcie graficznej używając dodatkowych przebiegów, które przeliczałyby kolizje z prostymi prymitywami (kule, sześciany) lub bardziej skomplikowanymi (heightfield). Rysunek 4.1 Pokazuje sytuację odbicia od heightfieldu. Mamy tam pole i cząsteczkę, która za chwilę z nim będzie kolidować. Generalne podejście wygląda tak. Wektor C jest wektorem wirtualnej kamery, który jest prostopadły do płaszczyzny zawierającej naszego height fielda. Teraz wystarczy, że stworzymy macierz projekcji ortagonalnej i kamerę o wielkości heightfieldu, która patrzy w kierunku C. 5
Michał Mocarski Zaawansowane I efektywne systemy cząsteczkowe w grach komputerowych C V N V Rys.4.1 Odbicie cząsteczki od heightfieldu W układzie tym renderujemy najpierw nasz heightfield do tekstury, zachowując wartość wektora normalnego w każdym z wyrenderowanych punktów i współrzędną z, która będzie odpowiadała po przetransformowanie przez macierz kamery, odległości danego punktu od kamery(r,g,b -> współrzędne wektora normlnego, A-> z). Mając te dane możemy teraz wyrenderować nasze punkty każdy z nich transformujemy do naszego układu. Zauważmy, że współrzędne x,y będą odpowiadały pozycji na płaszyźnie, co możemy użyc jako współrzędne teksturowania, a współrzędna z jak poprzednio będzie odpowiadała odległości od kamery. Gdy będzie ona mniejsza od odczytanej z tekstury, to musimy odbić nasz wektor prędkości względem wektora normalnego odczytanego z tekstury. Oczywiście opisany algorytm jest bardzo skomplikowaną, ogólną wersją i w zależności od potrzeb można zastosować wiele uproszczeń (np. korzystać z gotowego heightfielda i tekstury z normalnymi dla niego i po prostu rzutować wierzchołki na płaszczyznę go opisującą, jednak opisany przeze mnie sposób będzie wykorzystany w daleszej części prezentacji). Nie jest to rozwiązanie elastyczne w 100%, ale stosunkowo optymalne i co więcej w całości wykonywane na karcie graficznej. Kolejną kwestią jest sortowanie cząsteczek. Gdy używamy alpha blendingu, to wymagane jest, by cząsteczki były narysowane w kolejności od 6
IV Ogólnopolska Konferencja Inżynierii Gier Komputerowych, Siedlce 2007 najbardziej odległej w stosunku do kamery, do tej najbliższej. Często, gdy nie korzystamy z alpha blendingu, bądź fragmenty przezroczyste są znikome i nie będzie widać błędów alpha-blendingu, sytuację możemy zignorować. W przeciwnym wypadku pozostaje nam implementacja particle systemu na CPU, lub Sortowanie przy pomocy GPU. Istnieje algorytm bitonic sort, umożliwiający GPU sortowanie równoległe. Niestey odbija się to dodatkowo na wydajności i komplikuje sytuację. 4.2 Systemy bezstanowe Opisane systemy stanowe zapewniają wysoką elastyczność, jednak są stosunkowo kosztowne. Ponadto większość systemów cząsteczkowych jest stosunkowo prosta np. ogień, deszcz, śnieg, wystrzały proszuają się ruchami, które można opisać prostymi równaniami, a ich interackja z otoczeniem jest minimalna. Powyższe fakty implikują, że stan danej cząsteczki możemy określić znając tylko i wyłącznie stan początkowy i ilość czasu, który minął od początku animacji. W przypadku takim nie musimy modyfikować bufora wierzchołków, a animację możemyw całości przeprowadzić na GPU w jednostkach vertex shader. Przykładem może być zaimplementowany przeze mnie śnieg, którego ruch opisany jest równaniem ruchu jednostajnie przyspieszonego w 3 płaszczyznach x,y i z. Pozycję wyraża się tam w następujący sposób: x = x 0 + v 0 *t + 0,5*a*t 2 (4.2.1) analogicznie w płaszczyznach y i z. Ponadto aby uatrakcyjnić wygląd parametry są w pewnym zakresie losowe, a równanie modulowane jest funkcją sinus. Nasuwa się pytanie w jaki sposób utrzymać ciągłość spadania cząsteczek? Odpowiedź jest prosta możemy modyfikować bufor wierzchołków, by zmienić parametry początkowe co jakiś czas, albo użyć funkcji okresowej. W mojej implementacji używam operacji dzielenia modulo przez okres funkcji czyli średni czas potrzebny cząsteczce na przebycie drogi od stanu początkowego do końcowego (tutaj do najniższego punktu na levelu). Istotną kwestią jest też odpowiednie rozrzucenie cząsteczek w pionie(przykładowo dodanie każdej cząsteczce losowego offsetu z zakresu [0,T], gdzie T jest okresem i dodanie powyższego offsetu do aktualnej różnicy czasu) i zróżnicowanie parametrów prędkości, by cząsteczki nie spadały jednostajnymi falami tylko w sposób ciągły wizualnie. Taki system umożliwia uzyskanie wydajności rzędu setek tysięcy cząsteczek, więc można go stosować na dużych przestrzeniach i symulować nim efekty atmosferyczne. Jednak należy uciec się do pewnej sztuczki kamera powinna przy każdym zbliżeniu/oddaleniu obejmować obszar na którym występują nasze cząsteczki, wtedy można dokonywać ich translacji przez 7
Michał Mocarski Zaawansowane I efektywne systemy cząsteczkowe w grach komputerowych macierz obrotu kamery. Jak uzyskać złudzenie ruchu względem cząsteczek? Najprościej wyznaczyć wektor ruchu kamery i dodać wektor odwrotny do niego, do wektorów opisujących równanie ruchu cząsteczek. Rozwiązanie takie daje naprawdę przy wysokiej wydajności w stosunku do klasycznych systemów cząsteczkowych. Dodatkowo bezstanowy system cząsteczkowy można wyposażyć w podstawową detekcję kolizji (np. żeby śnieg nie padał w domu). Polegałoby to na wykorzystaniu techniki detekcji kolizji podobnej do tej zaprezentowanej przy stanowym systemie cząsteczkowym. Musimy wyznaczyć prostą najlepszego dopasowania, która interpolować będzie ruch we wszystkich 3 płaszczyznach. Posłuży ona jako kierunek kamery renderującej głębokość całej sceny z jej punktu widzenia. Teraz wystarczy że przy renderowaniu cząsteczek ich pozycję przeniesiemy do układu współrzędnych naszej depth kamery i odczytamy wartość głębokości z tekstury (w jednostce vertex shader w sprzęcie >SM3.0 lub pixel shader w jednostce >SM2.0). Jeśli będzie ona mniejsza od głębokości aktualnej cząsteczki, to cząsteczka nie jest rysowana. 5. Zaawansowane techniki 5.1 Miękkie cząsteczki Cząsteczki twarde przenikają przez geometrię tworząc twarde krawędzie które psują wrażenie objętości cząstek. Rozwiązaniem może być zmniejszenie wielkości cząstek, jednak to wprowadza konieczność proceduralnego opisywania skomplikowanych kształtów i zwiększa obciążenie. Lepszym rozwiązaniem jest więc próba wygładzenia miejsca styku cząsteczek z otoczeniem. Jeśli wyrenderujemy głębokości sceny z punktu widzenia kamery, to będziemy mogli porównywać wartość głębokości sceny, z głębokością którą miałby dany piksel cząsteczki. Porównując je i używając drobnej histerezy możemy modyfikować przezroczystość cząsteczki gdy głębokości te będą podobne (wtedy następuje kolizja cząsteczki ze sceną). Efekt renderingu jest o wiele lepszy od tego dawanego przez twarde cząsteczki. 5.2 Cząsteczki wolumetryczne Cząsteczki miękkie wyglądają stosunkowo dobrze, jednak ciągle nie nadają się do reprezentacji kształtów objętościowych chmur, kłębów dymów itp. Można temu jednak zaradzić. Możemy wokół billboarda naszej cząsteczki roztoczyć wirtualną sferę i przygotować teksturę 3D (perlin noise) opisującą kolor cząsteczki w danym punkcie przestrzeni. Jeśli poprowadzimy 8
IV Ogólnopolska Konferencja Inżynierii Gier Komputerowych, Siedlce 2007 promień od kamery, do aktualnie renderowanego punktu to możemy wyznaczyć dwa punkty w których promień przecina naszą sferę. Jeśli głębokość sceny będzie mniejsza od głębokości naszego promienia, to musimy przyciąć odpowiednio punkt końcowy naszego promienia, by nie wykraczał on poza geometrię sceny. Teraz najistotniejsza część używamy punktu początkowego i wyliczonego końcowego aby liniowo interpolować wzdłuż promienia i wybrać na nim kilka punktów (8, 9, w zależności od potrzeb i wydajności sprzętu można dobrać) w których próbkujemy wartość naszej tekstury 3D i odczytane wartości dodajemy do siebie, biorąc pod uwagę odległość od obserwatora. Innymi słowy całkujemy funkcję 3D opisującą naszą teksturę po odległości. W ten sposób uzyskujemy bardzo naturalne i efektywne efekty objętościowe, które mogą służyć do tworzenia lokalnej mgły itp. 5.3 Cząsteczki renderowane w screen-space Interesującą perspektywą może być renderowanie np. deszczu w fazie post-processingu. Jest to możliwe gdy w każdym punkcie w którym znajduje się kamera pada deszcz, lub gdy możemy łatwo określić w buforze szablonowym gdzie rysować deszcz, a gdzie nie. Wtedy naszym zadaniem będzie wyrenderowanie znikomej ilości cząsteczek od offscreen bufora, bądź użycie animowanej tekstury i ostateczne nałożenie deszczu na wyrenderowaną scenę. W taki sposób postąpili programiści tworzący demo Toy Shop. 6. Zakończenie Systemy cząsteczkowe są szeroko stosowane w grafice 3D. Celem tego referatu było przybliżenie technik stosowanych do uatrakcyjnienia ich wyglądu oraz zwiększenia wydajności. Część tych technik dotyczy różnych płaszczyzn, więc można je łączyć. Dzięki temu możemy uzyskać zaskakujące efekty w czasie rzeczywistym. Bibliografia [1] Microsoft Windows DDK, http://www.osronline.com/ddkx/ddk2.htm [2] Microsoft DiectX SDK, http://msdn.microsoft.com/directx, Luty 2007 [3] ARB_point_sprite, http://oss.sgi.com/projects/ogl-sample/registry/arb/point_sprite.txt [4] Natalya Tatarchuk, ATI ToyShop Revealed(Eurographics Animation Festival) [5] Lutz Latta, Building a Million Particle System (Games Developer Conference 2004) 9
Michał Mocarski Zaawansowane I efektywne systemy cząsteczkowe w grach komputerowych Advanced and effective particle systems in computer games Abstract Paper focuses on particie systems as a source of special effects in computer games. It describes applications, methods of presenting graphical and physical representation of particles, techniques of animation and unusual approaches to particle systems. 10