Najszybszy sposób na stworzenie prostego efektu cząsteczkowego

12

Szukam najszybszego sposobu na stworzenie naprawdę prostego efektu cząsteczkowego, który będzie spamowany jak diabli w grze ...

Zasadniczo moja gra wygląda jak gra vectrex, zbudowana głównie z linii ... Chcę dokonać niewielkich eksplozji, które będą naprawdę powszechne.

Czy jest coś szybszego niż poruszanie się po niektórych punktach i renderowanie za pomocą GL_Point?

ścigacz
źródło
+1 tylko za odniesienie do Vectrex. Jako dziecko spędziłem kilka godzin zabawy na Scramble i Tempest na początku lat 80. Bez tego prawdopodobnie nie skończyłbym dzisiaj jako programista gier.
Kylotan
Tak, Tempest jest niesamowity: D
ścigający
Jak mam powiedzieć, że żaden nie jest poprawny?
ścigający

Odpowiedzi:

13

Naprawdę nie ma potrzeby przechowywania pamięci dla każdej cząstki i animowania każdej cząstki osobno. Możesz to zrobić proceduralnie, odtwarzając położenie cząstki podczas rysowania, używając klasycznego równania fizyki. s = ut + 1 / 2.at ^ 2

Prosty przykład (bez stałego przyspieszania cząstek):


void drawExplosion(ExplosionParameters& s)
{
  Random rng;
  rng.seed(s.startSeed);
  glBegin(GL_POINTS);
  for (int i = 0; i < s.numParticles; i++)
  {
    vec3 vel = rng.getRandomVector(-1.0f, 1.0f) * s.explosionSpeed;
    float timeBias = rng.getRandom(0, s.particleTimeBias);
    vec3 pos = s.explosionCentre + (vel * (s.timeElapsed + timeBias));
    glPoint3fv(&pos);
  }
  glEnd();
}

Następnie po prostu zwiększasz s.timeElapsed przy każdej iteracji pętli aktualizacji.

Jest również całkowicie podatny na implementację na GPU, uwalniając w ten sposób procesor od wykonywania jakiejkolwiek pracy. Implementacja GPU może wyglądać następująco:

void drawExplosion(ExplosionParameters& s)
{
    //bind Vertex Shader If Not Already Bound();
    ...
    // bindVertexBuffer of Zeroes If Not AlreadyBound();
    glVertexPointer(...)
    //uploadShaderUniformsForExplosion(s);
    glUniform3f(...)
    ...
    glDrawArrays(GL_POINTS, 0, s.numParticles);
} 

Moduł cieniujący wierzchołki GPU rekonstruowałby następnie pozycję cząstki za pomocą równania fizyki, a mundury / stałe zostałyby do niej przekazane - podobnie jak wersja procesora.

Aby dodać trochę wariancji, możesz użyć większej liczby jednoczesnych eksplozji z nieco różniącymi się parametrami, animując kolory / alfa, wybierając różne pozycje początkowe. itp.

jpaver
źródło
Ponadto można użyć przewidywalności liczb pseudolosowych do wygenerowania wszystkich wektorów początkowych cząstek, tworząc setki cząstek z danych o wartości kilku int. Użycie GPU do tworzenia quadów to naprawdę dobry pomysł na proste cząstki.
Skizz
Przez lata tworzyłem układy cząstek w tradycyjny sposób, stosując tablice klas, które traktują cząstki jako pół-inteligentne byty i zawsze wydawało się to marnotrawstwem i wzdęciem. Ten sposób jest znacznie lepszy w przypadku podstawowych cząstek, które nie robią nic więcej, jak wyrzucanie na ekran.
Piku
7

Zrobiłem kilka testów, a NAJSZYBSZY sposób (nie najszybszy do zakodowania) to cząstki wykonane z GL_LINE, które znały swoją pozycję i prędkość, i użyłem tego jako punktów podczas renderowania (więc im szybciej cząstka idzie, tym bardziej „linia” staje się, wolniej, staje się punktem).

Efekt jest NAPRAWDĘ fajny (spójrz na wideo z wojen geometrycznych, aby go zobaczyć), i NAPRAWDĘ szybki. Wykop bzdury z quadów (szczególnie, że quady zmusiłyby mnie do obliczenia podwójnej liczby wierzchołków)

Jest to także lepsze niż użycie już wykonanego układu cząstek, ponieważ chciałem określonego i SZYBKIEGO efektu, układy cząstek zwykle obsługują wiele funkcji, z proporcjonalną ilością narzutu.

ścigacz
źródło
2
+1 za wyjaśnienie, co zrobiłeś, chociaż chętnie usłyszę więcej szczegółów na temat twoich testów. =)
leander
Btw: Wszystko to było w trybie natychmiastowym (to jedyna rzecz, którą umiem kodować, a wczoraj nauczyłem się tej nazwy ...)
speeder
6

Zwykle myślę, że robiłbyś cząstki jako quady z mapą tekstury. Zasadniczo traktuj je jako duszki 2D i stopniowo zanikaj, niszcząc je, gdy są niewidoczne. Co więcej, ponownie wykorzystuj stare, kiedy tworzysz nowe, aby nie niszczyć pamięci o tych rzeczach.

Jeśli użyjesz wstępnie pomnożonej alfa w sztuce, możesz z łatwością obsługiwać światła, ogień, dym i wiele innych za pomocą jednego rodzaju operacji mieszania.

Kylotan
źródło
Hum ... punkty nie są SZYBCIEJ niż tekstury?
ścigający
2
Sprzęt graficzny jest specjalnie zoptymalizowany pod kątem rasteryzacji tekstur do bufora ramki. Jeśli punkty są szybsze, prawdopodobnie będzie to niewielka ilość, a ty stracisz wszystkie możliwości, jakie masz dzięki teksturowaniu.
Kylotan
jak co? Pamiętaj, że nie tworzę w pełni funkcjonalnego układu cząsteczkowego, to tylko specyficzny efekt (małe eksplozje, głównie dla sprzężenia zwrotnego z gry, że coś
trafiłeś
Jeśli chcesz po prostu użyć punktów lub linii, to w porządku. Mogę jedynie komentować to, co większość ludzi robi dla cząstek. Może niewypełniony trójkąt byłby ładną cząsteczką.
Kylotan
4

W OpenGL ES 2.0, ES 1.X z rozszerzeniem i OpenGL => 2.1 możesz używać GL_POINT_SPRITES. GL_POINT_SPRITES są jak quady zawsze przed kamerą.

W shaderach fragmentów możesz:

  • Zdefiniuj rozmiary duszka za pomocą gl_PointSize w module cieniującym wierzchołki
  • użyj gl_PointCoord (współrzędne UV) w module cieniującym fragmenty

Możesz używać tekstury z alfą, aby rysować sprite'y ...

Samouczek dla duszków punktowych

Ellis
źródło
Unikam rozszerzeń, te głupie, z których już korzysta silnik (których nie zrobiłem), są wystarczające, aby kilka osób narzekało, że gra nie działa ...
Speeder
1

Większość systemów efektów cząsteczkowych, jakie widziałem, zamiast rysować ogromną liczbę punktów, rysuje stosunkowo mniejszą liczbę tekstur billboardów, przy czym każda z nich wygląda trochę jak eksplozja. Chyba że twój styl artystyczny naprawdę temu przeszkadza, prawdopodobnie będziesz szczęśliwszy, idąc tą drogą. Pozwoli to zminimalizować ilość cząstek potrzebnych do indywidualnej animacji i renderowania, jednocześnie zapewniając duży efekt wizualny.

hojny
źródło
1
To prawda, ale dąży do stylu Vectrex, działałby tam gorzej.
Kaj
1
Dokładnie to, co powiedział Kaj ... byłoby bezcelowe ORAZ zwiększyłoby rozmiar pobierania (przełączam najwięcej grafiki, jaką mogę z sprite'a na prawdziwe wektory, więc mogę zmniejszyć rozmiar plików)
szybszy
1

Dla schludnego, małego sposobu radzenia sobie z spawnowaniem / usuwaniem / aktualizacją cząstek, zakładając, że masz prosty zestaw cząstek - Cząstki [MAX_PARTICLES]:

Śledź aktywne cząstki (zaczynając od NumActiveParticles = 0)

Nowe cząstki są zawsze dodawane na końcu tablicy:

pNewParticle = &Particles[NumActiveParticles++];

Sprytny bit - Podczas usuwania „martwej” cząstki - zamień ją na ostatnią aktywną cząsteczkę i zmniejsz NumActiveParticles:

if ( DeadParticle < NumActiveParticles-1 )
{
  Particles[ DeadParticle ] = Particles[ NumActiveParticles-1 ];
}
NumActiveParticles--;

Zapobiega to wyszukiwaniu „nieużywanych cząstek” podczas odradzania i pozwala uniknąć skanowania przez tablicę MAX_PARTICLES, jeśli żadna z nich nie jest używana.

Zauważ, że działa to tylko wtedy, gdy kolejność aktualizacji / renderowania jest nieistotna (jak ma to miejsce w przypadku wielu efektów cząsteczkowych, które wykorzystują mieszanie addytywne) - ponieważ ta metoda usuwania cząsteczek ponownie porządkuje tablicę

bluescrn
źródło
-1

Najszybszym sposobem, jaki można założyć, jest znalezienie silnika cząstek i wykorzystanie go do uzyskania efektów. Tu jest kilka:

RCIX
źródło