OpenGL (14.) - Ucelený částicový systém

Protože na českém internetu je jen velmi málo informací ohledně programování uceleného částicového systému, rozhodl jsem se navrhnout základní strukturu, kterou lze využít pro většinu efektů s částicemi - Plápolající oheň s dýmem, jiskry ve zkratu na vedení, tryskající gejzír vody, oheň za raketou nebo její explose, déšt, sníh nebo rozstříknutí krve po zabitém nepříteli. Věřím, že tyto informace budou pro většinu z vás přínosem. Protože se jedná o poměrně rozsálné téma, rozhodl jsem se jej rozdělit i do několika příštích článků.

Particle Manager

Jak začít? Je třeba vytvořit nějaký Particle manager, který se bude starat (vytvářet, rušit, nastavovat) o jednotlivé částicové systémy. Jeho datová struktura je zde:

type
  ParticleManagerC = class
    private
      ParticleSystem: Array of ParticleSystemC;
    public
      Camera: CameraC;
      procedure AddParticleSystem(Name: string);
      procedure RemoveParticleSystem(Name: string);
      function FindParticleSystem(Name: string): ParticleSystemC;
      procedure Update;
      procedure Render;
      constructor Create;
  end;

Vše budeme psát do samostatné unity, kterou uložíme jako ParticleManagerU.pas. Konstruktor Create vytvoří objekt ParticleManager, destructor ho opět uvolní z paměti. Procedura AddParticleSystem vytvoří nový částicový systém a nastaví mu defaultní hodnoty, RemoveParticleSystem odstraní požadovaný systém. Funkcí FindParticleSystem vybereme systém a můžeme změnit jeho chování. Třídou CameraC oznamujeme manageru, jakou souřadnici má kamera v prostoru. To využijeme při zobrazování samotných částic - jsou otočeny vždy kolmo ke kameře. Místo této třídy můžeme vkládat jen tyto samotné souřadnice. Procedura Update se stará o aktualizování pozice, přidávání nových a rušení starých částic. Procedurou Render Všechny aktivní částice vykreslíme.

Podobné efekty lze vytvořit jedině v precizně naprogramovaných systémech.

Potom do zdrojového kódu programu, který využívá částicový systém stačí přidat:

uses
  ParticleManagerU;

var
  ParicleManager: ParticleManagerC;

implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  ParticleManager := ParticleManagerC.Create;

  ParticleManager.AddParticleSystem('Fire');
  ParticleManager.Camera := Camera;
end;

Podrobný popis funkcí je zde:

constructor ParticleManagerC.Create;
begin
end;

destructor ParticleManagerC.Free;
begin
end;


procedure ParticleManagerC.AddParticleSystem(Name:string);
begin
  setlength(ParticleSystem,length(ParticleSystem)+1);
  ParticleSystem[length(ParticleSystem)-1] := ParticleSystemC.Create;
  ParticleSystem[length(ParticleSystem)-1].Name := Name;
  ParticleSystem[length(ParticleSystem)-1].Active := true;
end;



procedure ParticleManagerC.RemoveParticleSystem(Name: string);
var
  i: integer;
begin
  for no:=1 to length(ParticleSystem)-1 do begin
    if ParticleSystem[i].Name = Name then begin
      //zde vymažeme ParticleSystem[i] a všechny další
      //posuneme o jeden dopředu...
    end;
  end;
end;



function ParticleManagerC.FindParticleSystem(Name: string): ParticleSystemC;
var
  i: integer;
begin
  for i:=1 to length(ParticleSystem)-1 do begin
    if ParticleSystem[i].Name = Name then begin
      result := ParticleSystem[i];
    end;
  end;
end;
Toto je nejjednoduší aplikace částicového systému.
procedure ParticleManagerC.Update;
var
  i, j: integer;
  Time: single;
  CountNew: integer;
begin
  Time := GetTickCount/100;

  //Pro aktivní každý částicový systém...
  for i:=0 to length(ParticleSystem)-1 do with ParticleSystem[i] do begin
    if Active = true then begin

      CountNew := 0;
      //...a pro každou částici dělej:
      for j:=0 to length(Particles)-1 do begin

        //Pokud vyhasla...
        if Particles[j].EndTime <= time then begin

          if CountNew>10 then continue;
          //Vygeneruj novou částici...
          Particles[j].Position := Position;
          Particles[j].OldPosition := Position;

          //Nastavíme náhodný rozptyl každé nové částice
          Particles[j].Direction := VectorAdd(
            Direction,
            AffineVectorMake(
              (random(DirectionError)-DirectionError/2)/127,
              (random(DirectionError)-DirectionError/2)/127,
              (random(DirectionError)-DirectionError/2)/127));

          //... a nastav její životnost náhodně v rozmězí 1 krát až 1,5 krát LifeTime.
          Particles[j].EndTime := Time+Lifetime*(1+random(LifeTimeError)/512);

          inc(CountNew);

        //Pokud nevyhasla, vypočítej její novou pozici.
        end else begin
          Particles[j].OldPosition := Particles[j].Position;
          Particles[j].Direction[1] := Particles[j].Direction[1] - Gravity/100;
          Particles[j].Position :=
            VectorAdd(
              Particles[j].Position,
              VectorScale(
                VectorScale(
                  Particles[j].Direction,
                  Speed),
                (Particles[j].EndTime-Time)/LifeTime));
        end;
      end;
    end;
  end;
end;

procedure ParticleManagerC.Render;
var
  i: integer;
begin
 //Pro aktivní každý částicový systém...
  for i:=0 to length(ParticleSystem)-1 do with ParticleSystem[i] do begin
    if Active = true then begin
      Material.Activate;
      ParticleSystem[i].Render(Camera);
      Material.DeActivate;
    end;
  end;
end;

Vyšlo 07.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

Diskuse k blogu

Zatím nikdo nevložil komentář. Chcete být první? Přidání příspěvku
©PC-guru.cz 2000-2008 | Optimalizováno pro 1024*768