Warning: Undefined array key "translationlc" in /usr/www/users/fabook/_diggets/doc/v2/lib/plugins/translation/action.php on line 237
Warning: Cannot modify header information - headers already sent by (output started at /usr/www/users/fabook/_diggets/doc/v2/lib/plugins/translation/action.php:237) in /usr/www/users/fabook/_diggets/doc/v2/inc/Action/Export.php on line 104
Warning: Cannot modify header information - headers already sent by (output started at /usr/www/users/fabook/_diggets/doc/v2/lib/plugins/translation/action.php:237) in /usr/www/users/fabook/_diggets/doc/v2/inc/Action/Export.php on line 104
Warning: Cannot modify header information - headers already sent by (output started at /usr/www/users/fabook/_diggets/doc/v2/lib/plugins/translation/action.php:237) in /usr/www/users/fabook/_diggets/doc/v2/inc/Action/Export.php on line 104
====== Using the ParticleSystem ======
{{::particles1.jpg?nolink|}}
Gorilla3D provides an integrated particle system for rendering complex and individual particle effects.
A particle effect is produced by a so-called emitter represented by the basic **TGorillaParticleEmitter** class.
Extend this class to build your own effect.
Gorilla3D already supplies some of the most popular effects, like: fire, smoke, rain, snow, waterfall, eruption, explosion.
{{::particles2.jpg?nolink|}}
It is possible to manipulate each particle by the so-called influencers.
The framework already provides a lot of the basic influencer types, like: linear movement, spiral movement, gravity, wind, particle color, trailed movement, traktor movement and physics.
===== Features =====
* Randomizable particle properties by presets
* Cachable particles
* Count limitation
* Auto emittance
* Interactive emmittance
* Endless or limited emmittance
* Physically based particle collision detection with other scene objects (not with particles!)
* Autosorting of particles depending on assigned camera
===== Shader / Material =====
The particle emitter expects a pointsprite compatible material source to be applied.
Gorilla3D therefor provides the **TGorillaParticleMaterialSource** as default material.
It supports rendering a single texture, texture-atlas (for animated particles) and colored particles on pointsprite basis.
Have a look at [[materials|Materials]]
Of course you can write your own shader if those features do not suit your needs.
===== Shader Attributes =====
To allow extended particle functionality Gorilla3D changes the default values of some vertex attributes, because at the moment it is not possible to declare our own vertex attributes.
In the following table we show the attribute settings for each particle, when using a TGorillaParticleEmitter:
^ Vertex-Attribute ^ Value ^
| a_Position | position |
| a_Normal | velocity |
| a_Color0 | current color|
| a_TexCoord0 | current texture or texture atlas offset |
| a_Binormal | X = size, Y = angle, Z = weight |
| a_Tangent | X = age, Y = life time, Z = delta time |
===== Influencers =====
Influencers are helper classes to manipulate particles at runtime.
===== Physics Particle Support =====
{{::particles3.jpg?nolink|}}
Our particles system can be linked to the physics system for particle collision detection.
In the following example we use the rain particle emitter as basis.
uses
[...]
Gorilla.Material.Particle,
Gorilla.Particle.Emitter,
Gorilla.Particle.Influencer,
Gorilla.Particle.Rain,
Gorilla.Particle.Spot,
Gorilla.Physics,
Gorilla.Physics.Q3.Body;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
protected
FViewport : TGorillaViewport;
FCamera : TGorillaCamera;
FPhysics : TGorillaPhysicsSystem;
FParticles : TGorillaRainParticleEmitter;
FInfluencer : TGorillaPhysicsInfluencer;
FSplashes : TGorillaSpotParticleEmitter;
procedure DoOnGorillaPhysicsNotifyContact(const ABodyA, ABodyB : TQ3Body);
[...]
end;
[...]
procedure TForm1.DoOnGorillaPhysicsNotifyContact(const ABodyA, ABodyB : TQ3Body);
begin
// collision detected - create splashes on particle-sphere/box/terrain/mesh collision
// not on particle-particle collision (too much)
if (PTypeInfo(ABodyA.UserDataType) = TypeInfo(PGorillaParticle))
and (PTypeInfo(ABodyB.UserDataType) = TypeInfo(PGorillaParticle)) then
Exit;
if (PTypeInfo(ABodyA.UserDataType) = TypeInfo(PGorillaParticle)) then
FSplashes.EmitParticle(
PGorillaParticle(ABodyA.UserData)^.Position
)
else if (PTypeInfo(ABodyB.UserDataType) = TypeInfo(PGorillaParticle)) then
FSplashes.EmitParticle(
PGorillaParticle(ABodyB.UserData)^.Position
);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
[...]
// create physics system with contact callback function to display splashes
FPhysics := TGorillaPhysicsSystem.Create(FViewport);
FPhysics.OnBeginContact := DoOnGorillaPhysicsNotifyContact;
// create rain particle emitter
FParticles := TGorillaRainParticleEmitter.Create(FViewport);
FParticles.Parent := FViewport;
FParticles.Camera := FCamera;
FParticles.EmitParticles := 25;
// preconfigure particles
FParticles.Colored.StartColor := TAlphaColorF.Create( TAlphaColorRec.Blue );
FParticles.Colored.EndColor := TAlphaColorF.Create( TAlphaColorRec.Blueviolet );
FParticles.ParticleSize := TParticlePreset.Create(20, 20, 1, false);
FParticles.ParticleGrowth := TParticlePreset.Create(0, 0, 1, false);
FParticles.Colored.Enabled := false;
FParticles.Wind.Enabled := false;
// create a physics influencer
FInfluencer := TGorillaPhysicsInfluencer.Create(FParticles);
FInfluencer.Emitter := FParticles;
// link to physics system component
FInfluencer.Physics := FPhysics;
FInfluencer.Enabled := true;
// another particle emitter to simulate rain drop splashes when they hit an obstacle
FSplashes := TGorillaSpotParticleEmitter.Create(FViewport);
FSplashes.Parent := FViewport;
FSplashes.Camera := FCamera;
FSplashes.LoadTexture('splash.png');
// activate physics
FPhysics.Active := true;
FParticles.Start();
FSplashes.Start();
end;
===== Remarks =====
Point rendering is in some cases hardware dependent.
We've detected rendering problems with onboard-gpu's like **Intel HD Graphics**. Here pointsize is clamped by hardware integration.
In effect particle will only be scaled within a specific size range.
===== Example =====
==== Fire effect ====
procedure TForm1.FormCreate(Sender: TObject);
var LParticles := TGorillaFireParticleEmitter;
LParticleMat : TParticleMaterialSource;
begin
LParticles := TGorillaFireParticleEmitter.Create(FGorilla);
LParticles.Parent := FGorilla;
LParticles.Camera := FCamera;
// a fire effect contains multiple parts: a front and back flame and smoke
LParticleMat := LParticles.Back.MaterialSource as TParticleMaterialSource;
LParticleMat.Texture.LoadFromFile('fire2.png');
LParticles.LoadTexture('fire.png');
LParticles.Smoke.LoadTexture('smoke.png');
LParticles.Scale.Point := Point3D(5, 5, 5);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// on some constellations you will need an interval to update the viewport
FGorilla.Invalidate();
end;
==== Smoke effect with wind influencer ====
procedure TForm1.FormCreate(Sender: TObject);
var LParticles := TGorillaSmokeParticleEmitter;
LParticleMat : TParticleMaterialSource;
LWind : TGorillaWindParticleInfluencer;
begin
LParticles := TGorillaSmokeParticleEmitter.Create(FGorilla);
LParticles.Parent := FGorilla;
LParticles.Camera := FCamera;
// load smoke texture atlas
LParticles.LoadTexture('smoke.png');
// randomize particle size and growth
LParticles.ParticleSize := TParticlePreset.Create(16, 16, 1, false);
LParticles.ParticleGrowth := TParticlePreset.Create(4, 8, 1, false);
LWind := TGorillaWindParticleInfluencer.Create(LParticles);
LWind.Origin := TPoint3D.Create(5, 0, 0);
LWind.Size := TPoint3D.Create(5, 3, 3);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// on some constellations you will need an interval to update the viewport
FGorilla.Invalidate();
end;
==== Eruption effect with color influencer ====
procedure TForm1.FormCreate(Sender: TObject);
var LParticles : TGorillaEruptionParticleEmitter;
LColorInfl : TGorillaColoredParticleInfluencer;
begin
LParticles := TGorillaEruptionParticleEmitter.Create(FGorilla);
LParticles.Parent := FGorilla;
LParticles.Camera := FCamera;
LColorInfl := TGorillaColoredParticleInfluencer.Create(LParticles);
LColorInfl.StartColor := TAlphaColorF.Create(0, 0, 1, 1);
LColorInfl.EndColor := TAlphaColorF.Create(0, 0, 0, 0);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// on some constellations you will need an interval to update the viewport
FGorilla.Invalidate();
end;
==== Rain effect ====
procedure TForm1.FormCreate(Sender: TObject);
var LParticles : TGorillaRainParticleEmitter;
begin
LParticles := TGorillaRainParticleEmitter.Create(FGorilla);
LParticles.Parent := FGorilla;
LParticles.Camera := FCamera;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// on some constellations you will need an interval to update the viewport
FGorilla.Invalidate();
end;
==== Snow effect ====
procedure TForm1.FormCreate(Sender: TObject);
var LParticles : TGorillaSnowParticleEmitter;
begin
LParticles := TGorillaSnowParticleEmitter.Create(FGorilla);
LParticles.Parent := FGorilla;
LParticles.Camera := FCamera;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// on some constellations you will need an interval to update the viewport
FGorilla.Invalidate();
end;
==== Mouse interaction ====
var
FParticles : TGorillaParticleEmitter;
procedure TForm1.FormCreate(Sender: TObject);
var LParticleMat : TParticleMaterialSource;
LVPreset : TParticleVectorPreset;
LColorInfl : TGorillaColoredParticleInfluencer;
begin
// create the particle material shader
LParticleMat := TParticleMaterialSource.Create(FGorilla);
LParticleMat.Parent := FGorilla;
LParticleMat.UseTexture := false;
LParticleMat.IsTextureAtlas := false;
// create particle emitter for spraying effect
FParticles := TGorillaParticleEmitter.Create(FGorilla);
FParticles.Parent := FGorilla;
// connect particle shader and emitter
LParticleMat.Emitter := FParticles;
// limit number of particles
FParticles.EmitParticles := 100;
FParticles.MaxParticles := 10000;
// disable auto emittance, becaus we want only to emit on mouse click
FParticles.AutoEmit := false;
// enable particle caching
FParticles.Reuse := true;
// randomize particle properties
// 1) random position of particles
LVPreset := TParticleVectorPreset.Create(0, 0, 1000, Point3D(1, 1, 1), [axX, axY, axZ]);
FParticles.ParticlePosition := LVPreset ;
// 2) random velocity of particles
LVPreset := TParticleVectorPreset.Create(5, 10, 1000, Point3D(1, 2, 1), [axX, axY, axZ]);
LVPreset.RangeY.Negative := false;
FParticles.ParticleVelocity := LVPreset;
// 3) the rest of properties
FParticles.ParticleSize := TParticlePreset.Create(2, 3, 1, false);
FParticles.ParticleAngle := TParticlePreset.Create(0, 360, 1, false);
FParticles.ParticleWeight := TParticlePreset.Create(1, 1, 1, false);
FParticles.ParticleGrowth := TParticlePreset.Create(0, 0, 1, false);
FParticles.ParticleLifeTime := TParticlePreset.Create(500, 5000, 1000, false);
// create a color influencer for a starting and end color
LColorInfl:= TGorillaColoredParticleInfluencer.Create(FParticles);
LColorInfl.StartColor := TAlphaColorF.Create(0, 1, 0, 1);
LColorInfl.EndColor := TAlphaColorF.Create(0, 0, 1, 0);
end;
var
FLatest : TPointF;
FMouseMove : Boolean = false;
FClickPt : TPoint3D;
procedure TForm1.DoOnViewportMouseUp(ASender : TObject; AButton : TMouseButton;
AShift : TShiftState; X, Y : Single);
begin
FMouseMove := false;
end;
procedure TForm1.DoOnViewportMouseDown(ASender : TObject; AButton : TMouseButton;
AShift : TShiftState; X, Y : Single);
var I : Integer;
begin
if (ssLeft in AShift) then
begin
FMouseMove := true;
FLatest := PointF(X, Y);
// emit particles at mouse position
FClickPt := FGorilla.ScreenToWorld(Point(round(X), round(Y)));
for I := 0 to (FParticles.EmitParticles - 1) do
FParticles.EmitParticle(FClickPt);
end;
end;
procedure TForm1.DoOnViewportMouseMove(ASender : TObject; AShiftState : TShiftState;
X, Y : Single);
var lDiff : TPointF;
I : Integer;
lOrigin : TPoint3D;
begin
if (ssLeft in AShiftState) then
begin
// emit particles at mouse position
FClickPt := FGorilla.ScreenToWorld(Point(round(X), round(Y)));
for I := 0 to (FParticles.EmitParticles - 1) do
FParticles.EmitParticle(FClickPt);
end;
if FMouseMove then
begin
FLatest := PointF(X, Y);
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// on some constellations you will need an interval to update the viewport
FGorilla.Invalidate();
end;
Next step: [[physics|Physics]]