OpenGL (15.) - Ucelený částicový systém - pokračování
V minulém článku jsem popsal, jak by měl vypadat takový manager částicového systému. Dnes budu pokračovat v tom, jak vytvořit samotný systém.
Particle System
Tak jsem napsal první článek o částicovém systému, ale ještě jsem se ani nezmínil co to částice (particles) vůbec jsou. Jedná se vlastně o čtverec nebo jiný tvar, na který naneseme černobílou texturu hvězdy, kapky deště nebo, zapneme průhlednost tak, aby černé kraje textury byly průhledné a prostředek, kde je textura bílá necháme neprůhledný, popř. ho dobarvíme.
Částicový systém je systém, který se stará o částice. Vytváří je, počítá jejich pozici, barvu a po uplynutí jejich životnosti je vymaže.
Manager se stará o částicové systémy. Je-li potřeba, vytvoří nový nebo uvolní starý. K jednotlivým systémům přistupujeme přes ParticleManager.
Samotný částicový systém má trochu složitější strukturu než jeho manager. Jednotlivé parametry jsou snadno pochopitelné podle názvu: Jméno systému, typ, max. počet částic, aktivita, směr a síla větru, velikost gravitace, pozice systému, směr emitování částic, jejich rychlost a doba jejich viditelnosti, barvy, velikosti a materiál, ze kterého jsou částice složeny. Aby se částice neemitovaly jedním směrem v řadě za sebou, je třeba nastavit také maximální odchylku od zvoleného směru a dobu života částic. Samotné částice jsou uchovány v poli particles.
![]() | ![]() |
| Takovéto částice si můžete jednoduše vytvořit třeba v Adobe Photoshopu. | |
type
ParticleSystemC = class
private
public
Name: string;
SystemType: TParticleSystemType;
MaxParticlesInSystem: integer;
Active: boolean;
Wind: TAffineVector;
Gravity: single;
//Particle physical features:
Direction: TAffineVector;
Speed: single;
LifeTime: single;
Position: TAffineVector;
StartColor, EndColor: TColorRGBAs;
StartSize, EndSize: single;
Material: MaterialC;
// K hodnotám direction a lifetime připočítáváme také náhodnou odchylku která
// je v rozsahu 0..127 - 127=max.
DirectionError, LifeTimeError: byte;
Particles: Array of TParticle;
procedure Render(Camera: CameraC);
constructor Create;
end;
Snad bych se jen pozastavil u vlastnosti SystemType. Tou definujeme základní vlastnost částicového systému. psSmoke znamená, že částice budou vždy tvaru čtverce-budou mít stejnou víšku i šířku. psSpark znamená, že budou tvaru obdelníku, kde začátek bude v aktuální pozici částice a konec bude v předešlé pozici částice. To vytvoří efekt odlétajících jisker.
type
TParticleSystemType = (
psSpark, //Jiskry za sebou zanechávají stopu
psSmoke, //Částice mají stejnou šířku i výšku
{..});
![]() |
| Takto vypadá systém bez použití blendingu. Jeho největší výhodou je velká rychlost. |
Také už dnes budu pracovat se strukturou částic, tak ji pro jistotu uvedu zde:
type
TParticle = record
Position, Direction, OldPosition: TAffineVector;
EndTime: single;
end;
![]() | ![]() |
| Takto může vypadat třeba oheň nebo plyn, který uniká z barelu. | |
Protože třída ParticleSystemC má jen konstruktor a jednu proceduru pro vykreslení systému, nebudu se dlouho zdržovat a uvádím zde jejich výpis:
constructor KParticleSystemC.Create;
begin
Active := true;
SystemType := psSmoke;
Wind := AffineVectorMake(0,0,0);
Gravity := 0.01;
Speed := 2;
Direction := VectorNormalize(AffineVectorMake(0,1,0.6));
DirectionError := 30;
LifeTime := 4;
LifeTimeError := 127;
Position := AffineVectorMake(2,0,2);
StartColor := clrOrange;
EndColor := clrBlack;
StartSize := 2;
EndSize := 2;
MaxParticlesInSystem := 50;
setlength(Particles,MaxParticlesInSystem-1);
end;
procedure KParticleSystemC.Render(Camera: KCameraC);
var
i: integer;
Time: single;
u, v, c: TAffineVector;
W, X, Y, Z: TAffineVector;
AmbientStart, AmbientEnd, Ambient: TAffineVector;
size: single;
begin
Time := GetTickCount/100;
if (length(Particles) <> MaxParticlesInSystem) then
SetLength(Particles, MaxParticlesInSystem-1);
AmbientStart := AffineVectorMake(StartColor.r,StartColor.g,StartColor.b);
AmbientEnd := AffineVectorMake(EndColor.r,EndColor.g,EndColor.b);
if (SystemType=psSpark) then begin
for i:=0 to length(Particles)-1 do
if (Particles[i].EndTime >= Time) then begin
size := lerp(StartSize, EndSize, 1-(Particles[i].EndTime-Time)/LifeTime);
// Získáme směrový vektor
u := VectorNormalize(
VectorSubstract(
Particles[i].Position,
Particles[i].OldPosition));
// Získáme vektor kamera-částice
v := VectorNormalize(VectorAdd(
Particles[i].Position,
AffineVectorMake(
Camera.Position.X,
Camera.Position.Y,
Camera.Position.Z)));
// Získáme vektor kolmý k předešlým dvěma vektorům
c := VectorCrossProduct(u,v);
NormalizeVector(c);
ScaleVector(c,size);
W := VectorAdd(Particles[i].Position, c);
X := VectorAdd(Particles[i].OldPosition, c);
Y := VectorSubstract(Particles[i].Position, c);
Z := VectorSubstract(Particles[i].OldPosition, c);
Ambient := VectorLerp(AmbientStart, AmbientEnd,1-(Particles[i].EndTime-Time)/LifeTime);
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,@Ambient);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glBegin(GL_TRIANGLE_STRIP);
glColor3f(255,0,0);
glTexCoord2f(0,1);
glVertex3f(W[0], W[1], W[2]);
glTexCoord2f(1,1);
glVertex3f(X[0], X[1], X[2]);
glTexCoord2f(0,0);
glVertex3f(Y[0], Y[1], Y[2]);
glTexCoord2f(0,1);
glVertex3f(Z[0], Z[1], Z[2]);
glEnd;
end;
end else
if (SystemType=psSmoke) then begin
for i:=0 to length(Particles)-1 do
if Particles[i].EndTime >= Time then begin
size := lerp(StartSize, EndSize, 1-(Particles[i].EndTime-Time)/LifeTime);
// Získáme směrový vektor
u := VectorNormalize(
VectorSubstract(
Particles[i].Position,
Particles[i].OldPosition));
// Získáme vektor kamera-částice
v := VectorNormalize(
VectorAdd(
Particles[i].Position,
AffineVectorMake(
Camera.Position.X,
Camera.Position.Y,
Camera.Position.Z)));
// Získáme vektor kolmý k předešlým dvěma vektorům
c := VectorCrossProduct(u,v);
NormalizeVector(c);
ScaleVector(c,size);
ScaleVector(u,size);
W := VectorAdd(VectorAdd(Particles[i].Position, c),u);
X := VectorSubstract(VectorAdd(Particles[i].Position, c),u);
Y := VectorAdd(VectorSubstract(Particles[i].Position, c),u);
Z := VectorSubstract(VectorSubstract(Particles[i].Position, c),u);
Ambient := VectorLerp(AmbientStart, AmbientEnd,1-(Particles[i].EndTime-Time)/LifeTime);
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,@Ambient);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ZERO);
glBegin(GL_TRIANGLE_STRIP);
glColor3f(255,0,0);
glTexCoord2f(0,1);
glVertex3f(W[0], W[1], W[2]);
glTexCoord2f(1,1);
glVertex3f(X[0], X[1], X[2]);
glTexCoord2f(0,0);
glVertex3f(Y[0], Y[1], Y[2]);
glTexCoord2f(0,1);
glVertex3f(Z[0], Z[1], Z[2]);
glEnd;
glDisable(GL_BLEND);
end;
end;
end;
Funkce Lerp(start, stop, t) vypočítá lineární interpolaci mezi body start a stop v bodě 0<t<1. Tuto funkci potřebujeme pro vypočítání velikosti a barvy každé částice. Jak získáme všechny čtyři body částice? To je velmi jednoduché. Stačí vypočítat směrový vektor u (nemůžeme použít vlastnost částice direction, protože v ní není započítáno působení gravitace a větru) odečtením staré pozici částice od pozice nové. Poté vypočítáme vektor v mezi kamerou a danou částicí (Pro zvýšení rychlosti bychom mohli počítat vektor mezi kamerou a pozicí celého systému - dopouštěli bychom se ale toho, že by vzdálenější částice nebyly natočeny kolmo ke kameře) a nakonec vypočítáme (vektorovým součinem) vektor c kolmý k předešlým dvěma vektorům. Jeho využijeme při počítání rohů částice. Všechny potřebné funkce pro práci s vektory jsou k disposici v knihovně geometry.pas.
Teď, když přičteme nebo odečteme vektory c nebo u k souřadnici částice, dostaneme 4 rohy částice. Vynásobíme-li tyto vektory c a u proměnnou size, dostaneme částici buď zvětšenou nebo zmenšenou parametrem size. Tímto docílíme efektu psSmoke. Chceme-li, aby částice byly protáhlé ve směru, kam letí, nepotřebujeme parametr u, ale využijeme staré pozice částice. Změna je pouze v tom, že k pozici a ke staré pozici přičteme a odečteme vektor c.
![]() | ![]() |
| Zde je vidět, že použití většího počtu menších částic je také velmi pěkné (... ale náročné). | |
Tento článek má sloužit jako poradce při návrhu vlastního částicového systému. Je napsán tak, aby byla popsána hlavně struktura a základní chování částicového systému. Zbytek si už musí napsat každý sám. Pokud vám nebude něco jasné nebo najdete větší či menší chybu, napište mi to prosím do diskuse nebo na mejl
.Vyšlo 09.08.2002, v blogu: 0 1 2 3 4 5 6 7 8
Děkuji, že jste se rozhodl(a) přečíst tento článek. Budu rád i za komentář. Pokud Vás tento článek zaujal a rádi byste jej doporučili ostatním, podpořte mně prosím tím, že věnujete minutku svého času a uděláte mi reklamu na linkuj.cz, vybrali.sme.sk či jagg.cz. Přeji příjemné čtení
Poslední články
- Zobrazení terénu ve 3D grafice
- Engine (2.) - Timing
- Engine (1.) - Logování
- OpenGL (17.) - Light mapping - úvod
- OpenGL (16.) - Fading
- Herní grafické enginy (3.) - GLScene
- Herní grafické enginy (2.) - Pythian Project
- OpenGL (15.) - Ucelený částicový systém - pokračování
- OpenGL (14.) - Ucelený částicový systém
- OpenGL (13.) - Nastavení OpenGL v jazyce C/C++
- 3D Studio MAX (13.) - Popis modifikačních funkcí ve 3D Studiu MAX
- OpenGL (12.) - visualizační plugin pro WinAMP
- Delphi (10.) - knihovna FMOD
- Herní grafické enginy (1.) - MEngine od Mister Group
- Delphi (9.) - Download 2






