Experimental Particle System
This adds a new "Particles" slide to viewer, that allows
editing, loading, and saving particle effects. All of the
particle system code is in modules/particles.
There are many rough edges and some not-yet-finished changes
to generalize the model[1]. A rough overview:
- SkReflected.h implements a lightweight reflection system
for classes derived from SkReflected. Adding a new class
involves deriving from SkReflected, adding a macro to the
class declaration, and implementing visitFields(), which
simply calls a virtual on an SkFieldVisitor for each field.
Currently, emitters and affectors use this mechanism.
- SkParticleSerialization.h demonstrates two useful field
visitors - for serializing to and from JSON. The driver
code that uses those is directly in ParticlesSlide.
- SkParticleData.h and SkCurve.h define a variety of helper
types for talking about particles, both for parameterizing
individual values, and communicating about the state of a
particle among the effect, affectors, and emitters.
- SkParticleEffect.h defines the static data definition of
an effect (SkParticleEffectParams), as well as a running
instance of an effect (SkParticleEffect). The effect has
simple update() and draw() methods.
- ParticlesSlide.cpp adds a third field visitor to generate
GUIs for interactively editing the running effect.
---
1: The critical change I'd like to make is to remove all
special case behavior over time and at spawn (setting sprite
frames, size over time, color over time, etc...). Integration
is the only fixed function behavior. Everything else is driven
by two lists of affectors. One is applied at spawn time, using
the effect's lifetime to evaluate curves. This allows spawning
particles with different colors as the effect ages out, for
example. The second list is applied every frame to update
existing particles, and is driven by the particle's lifetime.
This allows particles to change color after being spawned, for
example.
With a small set of affectors using a single expressive curve
primitive (keyframed list of cubic curve segments), we can
have affectors that update color, size, velocity, position,
sprite frame, etc., and implement many complex behaviors.
Bug: skia:
Change-Id: Id9402bef22825d55d021c5a2f9e5e41791aabaf4
Reviewed-on: https://skia-review.googlesource.com/c/181404
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
2019-02-12 18:27:51 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2019 Google LLC
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef SkParticleData_DEFINED
|
|
|
|
#define SkParticleData_DEFINED
|
|
|
|
|
2019-04-23 17:05:21 +00:00
|
|
|
#include "include/core/SkColor.h"
|
|
|
|
#include "include/core/SkPoint.h"
|
|
|
|
#include "include/core/SkRSXform.h"
|
|
|
|
#include "include/utils/SkRandom.h"
|
|
|
|
#include "modules/particles/include/SkReflected.h"
|
Experimental Particle System
This adds a new "Particles" slide to viewer, that allows
editing, loading, and saving particle effects. All of the
particle system code is in modules/particles.
There are many rough edges and some not-yet-finished changes
to generalize the model[1]. A rough overview:
- SkReflected.h implements a lightweight reflection system
for classes derived from SkReflected. Adding a new class
involves deriving from SkReflected, adding a macro to the
class declaration, and implementing visitFields(), which
simply calls a virtual on an SkFieldVisitor for each field.
Currently, emitters and affectors use this mechanism.
- SkParticleSerialization.h demonstrates two useful field
visitors - for serializing to and from JSON. The driver
code that uses those is directly in ParticlesSlide.
- SkParticleData.h and SkCurve.h define a variety of helper
types for talking about particles, both for parameterizing
individual values, and communicating about the state of a
particle among the effect, affectors, and emitters.
- SkParticleEffect.h defines the static data definition of
an effect (SkParticleEffectParams), as well as a running
instance of an effect (SkParticleEffect). The effect has
simple update() and draw() methods.
- ParticlesSlide.cpp adds a third field visitor to generate
GUIs for interactively editing the running effect.
---
1: The critical change I'd like to make is to remove all
special case behavior over time and at spawn (setting sprite
frames, size over time, color over time, etc...). Integration
is the only fixed function behavior. Everything else is driven
by two lists of affectors. One is applied at spawn time, using
the effect's lifetime to evaluate curves. This allows spawning
particles with different colors as the effect ages out, for
example. The second list is applied every frame to update
existing particles, and is driven by the particle's lifetime.
This allows particles to change color after being spawned, for
example.
With a small set of affectors using a single expressive curve
primitive (keyframed list of cubic curve segments), we can
have affectors that update color, size, velocity, position,
sprite frame, etc., and implement many complex behaviors.
Bug: skia:
Change-Id: Id9402bef22825d55d021c5a2f9e5e41791aabaf4
Reviewed-on: https://skia-review.googlesource.com/c/181404
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
2019-02-12 18:27:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Various structs used to communicate particle information among emitters, affectors, etc.
|
|
|
|
*/
|
|
|
|
|
2019-03-04 15:55:22 +00:00
|
|
|
enum SkParticleFrame {
|
|
|
|
kWorld_ParticleFrame, // "Up" is { 0, -1 }
|
|
|
|
kLocal_ParticleFrame, // "Up" is particle's heading
|
|
|
|
kVelocity_ParticleFrame, // "Up" is particle's direction of travel
|
|
|
|
};
|
|
|
|
|
|
|
|
static constexpr SkFieldVisitor::EnumStringMapping gParticleFrameMapping[] = {
|
|
|
|
{ kWorld_ParticleFrame, "World" },
|
|
|
|
{ kLocal_ParticleFrame, "Local" },
|
|
|
|
{ kVelocity_ParticleFrame, "Velocity" },
|
|
|
|
};
|
|
|
|
|
Experimental Particle System
This adds a new "Particles" slide to viewer, that allows
editing, loading, and saving particle effects. All of the
particle system code is in modules/particles.
There are many rough edges and some not-yet-finished changes
to generalize the model[1]. A rough overview:
- SkReflected.h implements a lightweight reflection system
for classes derived from SkReflected. Adding a new class
involves deriving from SkReflected, adding a macro to the
class declaration, and implementing visitFields(), which
simply calls a virtual on an SkFieldVisitor for each field.
Currently, emitters and affectors use this mechanism.
- SkParticleSerialization.h demonstrates two useful field
visitors - for serializing to and from JSON. The driver
code that uses those is directly in ParticlesSlide.
- SkParticleData.h and SkCurve.h define a variety of helper
types for talking about particles, both for parameterizing
individual values, and communicating about the state of a
particle among the effect, affectors, and emitters.
- SkParticleEffect.h defines the static data definition of
an effect (SkParticleEffectParams), as well as a running
instance of an effect (SkParticleEffect). The effect has
simple update() and draw() methods.
- ParticlesSlide.cpp adds a third field visitor to generate
GUIs for interactively editing the running effect.
---
1: The critical change I'd like to make is to remove all
special case behavior over time and at spawn (setting sprite
frames, size over time, color over time, etc...). Integration
is the only fixed function behavior. Everything else is driven
by two lists of affectors. One is applied at spawn time, using
the effect's lifetime to evaluate curves. This allows spawning
particles with different colors as the effect ages out, for
example. The second list is applied every frame to update
existing particles, and is driven by the particle's lifetime.
This allows particles to change color after being spawned, for
example.
With a small set of affectors using a single expressive curve
primitive (keyframed list of cubic curve segments), we can
have affectors that update color, size, velocity, position,
sprite frame, etc., and implement many complex behaviors.
Bug: skia:
Change-Id: Id9402bef22825d55d021c5a2f9e5e41791aabaf4
Reviewed-on: https://skia-review.googlesource.com/c/181404
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
2019-02-12 18:27:51 +00:00
|
|
|
struct SkParticlePose {
|
|
|
|
SkPoint fPosition;
|
|
|
|
SkVector fHeading;
|
|
|
|
SkScalar fScale;
|
|
|
|
|
|
|
|
SkRSXform asRSXform(SkPoint ofs) const {
|
|
|
|
const float s = fHeading.fX * fScale;
|
|
|
|
const float c = -fHeading.fY * fScale;
|
|
|
|
return SkRSXform::Make(c, s,
|
|
|
|
fPosition.fX + -c * ofs.fX + s * ofs.fY,
|
|
|
|
fPosition.fY + -s * ofs.fX + -c * ofs.fY);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SkParticleVelocity {
|
|
|
|
SkVector fLinear;
|
|
|
|
SkScalar fAngular;
|
|
|
|
};
|
|
|
|
|
2019-02-20 17:25:20 +00:00
|
|
|
struct SkParticleState {
|
2019-02-20 19:33:49 +00:00
|
|
|
float fAge; // Normalized age [0, 1]
|
|
|
|
float fInvLifetime; // 1 / Lifetime
|
Experimental Particle System
This adds a new "Particles" slide to viewer, that allows
editing, loading, and saving particle effects. All of the
particle system code is in modules/particles.
There are many rough edges and some not-yet-finished changes
to generalize the model[1]. A rough overview:
- SkReflected.h implements a lightweight reflection system
for classes derived from SkReflected. Adding a new class
involves deriving from SkReflected, adding a macro to the
class declaration, and implementing visitFields(), which
simply calls a virtual on an SkFieldVisitor for each field.
Currently, emitters and affectors use this mechanism.
- SkParticleSerialization.h demonstrates two useful field
visitors - for serializing to and from JSON. The driver
code that uses those is directly in ParticlesSlide.
- SkParticleData.h and SkCurve.h define a variety of helper
types for talking about particles, both for parameterizing
individual values, and communicating about the state of a
particle among the effect, affectors, and emitters.
- SkParticleEffect.h defines the static data definition of
an effect (SkParticleEffectParams), as well as a running
instance of an effect (SkParticleEffect). The effect has
simple update() and draw() methods.
- ParticlesSlide.cpp adds a third field visitor to generate
GUIs for interactively editing the running effect.
---
1: The critical change I'd like to make is to remove all
special case behavior over time and at spawn (setting sprite
frames, size over time, color over time, etc...). Integration
is the only fixed function behavior. Everything else is driven
by two lists of affectors. One is applied at spawn time, using
the effect's lifetime to evaluate curves. This allows spawning
particles with different colors as the effect ages out, for
example. The second list is applied every frame to update
existing particles, and is driven by the particle's lifetime.
This allows particles to change color after being spawned, for
example.
With a small set of affectors using a single expressive curve
primitive (keyframed list of cubic curve segments), we can
have affectors that update color, size, velocity, position,
sprite frame, etc., and implement many complex behaviors.
Bug: skia:
Change-Id: Id9402bef22825d55d021c5a2f9e5e41791aabaf4
Reviewed-on: https://skia-review.googlesource.com/c/181404
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
2019-02-12 18:27:51 +00:00
|
|
|
SkParticlePose fPose;
|
|
|
|
SkParticleVelocity fVelocity;
|
2019-02-20 17:25:20 +00:00
|
|
|
SkColor4f fColor;
|
2019-02-20 19:33:49 +00:00
|
|
|
SkScalar fFrame; // Parameter to drawable for animated sprites, etc.
|
2019-02-26 19:58:40 +00:00
|
|
|
SkRandom fRandom;
|
2019-03-04 15:55:22 +00:00
|
|
|
|
|
|
|
SkVector getFrameHeading(SkParticleFrame frame) const {
|
|
|
|
switch (frame) {
|
|
|
|
case kLocal_ParticleFrame:
|
|
|
|
return fPose.fHeading;
|
|
|
|
case kVelocity_ParticleFrame: {
|
|
|
|
SkVector heading = fVelocity.fLinear;
|
|
|
|
if (!heading.normalize()) {
|
|
|
|
heading.set(0, -1);
|
|
|
|
}
|
|
|
|
return heading;
|
|
|
|
}
|
|
|
|
case kWorld_ParticleFrame:
|
|
|
|
default:
|
|
|
|
return SkVector{ 0, -1 };
|
|
|
|
}
|
|
|
|
}
|
Experimental Particle System
This adds a new "Particles" slide to viewer, that allows
editing, loading, and saving particle effects. All of the
particle system code is in modules/particles.
There are many rough edges and some not-yet-finished changes
to generalize the model[1]. A rough overview:
- SkReflected.h implements a lightweight reflection system
for classes derived from SkReflected. Adding a new class
involves deriving from SkReflected, adding a macro to the
class declaration, and implementing visitFields(), which
simply calls a virtual on an SkFieldVisitor for each field.
Currently, emitters and affectors use this mechanism.
- SkParticleSerialization.h demonstrates two useful field
visitors - for serializing to and from JSON. The driver
code that uses those is directly in ParticlesSlide.
- SkParticleData.h and SkCurve.h define a variety of helper
types for talking about particles, both for parameterizing
individual values, and communicating about the state of a
particle among the effect, affectors, and emitters.
- SkParticleEffect.h defines the static data definition of
an effect (SkParticleEffectParams), as well as a running
instance of an effect (SkParticleEffect). The effect has
simple update() and draw() methods.
- ParticlesSlide.cpp adds a third field visitor to generate
GUIs for interactively editing the running effect.
---
1: The critical change I'd like to make is to remove all
special case behavior over time and at spawn (setting sprite
frames, size over time, color over time, etc...). Integration
is the only fixed function behavior. Everything else is driven
by two lists of affectors. One is applied at spawn time, using
the effect's lifetime to evaluate curves. This allows spawning
particles with different colors as the effect ages out, for
example. The second list is applied every frame to update
existing particles, and is driven by the particle's lifetime.
This allows particles to change color after being spawned, for
example.
With a small set of affectors using a single expressive curve
primitive (keyframed list of cubic curve segments), we can
have affectors that update color, size, velocity, position,
sprite frame, etc., and implement many complex behaviors.
Bug: skia:
Change-Id: Id9402bef22825d55d021c5a2f9e5e41791aabaf4
Reviewed-on: https://skia-review.googlesource.com/c/181404
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
2019-02-12 18:27:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SkParticleUpdateParams {
|
|
|
|
float fDeltaTime;
|
2019-03-04 15:55:22 +00:00
|
|
|
float fEffectAge;
|
|
|
|
int fAgeSource;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SkParticleValue selects a specific value to be used when evaluating a curve, position on a path,
|
|
|
|
* or any other affector that needs a scalar float input. An SkParticleValue starts with a source
|
|
|
|
* value taken from the state of the effect or particle. That can be adjusted using a scale and
|
|
|
|
* bias, and then reduced into the desired range (typically [0, 1]) via a chosen tile mode.
|
|
|
|
*/
|
|
|
|
struct SkParticleValue {
|
|
|
|
enum Source {
|
|
|
|
// Either the particle or effect age, depending on spawn or update
|
|
|
|
kAge_Source,
|
|
|
|
|
|
|
|
kRandom_Source,
|
|
|
|
kParticleAge_Source,
|
|
|
|
kEffectAge_Source,
|
|
|
|
kPositionX_Source,
|
|
|
|
kPositionY_Source,
|
|
|
|
kHeadingX_Source,
|
|
|
|
kHeadingY_Source,
|
|
|
|
kScale_Source,
|
|
|
|
kVelocityX_Source,
|
|
|
|
kVelocityY_Source,
|
|
|
|
kRotation_Source,
|
|
|
|
kColorR_Source,
|
|
|
|
kColorG_Source,
|
|
|
|
kColorB_Source,
|
|
|
|
kColorA_Source,
|
|
|
|
kSpriteFrame_Source,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum TileMode {
|
|
|
|
kClamp_TileMode,
|
|
|
|
kRepeat_TileMode,
|
|
|
|
kMirror_TileMode,
|
|
|
|
};
|
|
|
|
|
|
|
|
void visitFields(SkFieldVisitor* v);
|
|
|
|
float eval(const SkParticleUpdateParams& params, SkParticleState& ps) const;
|
|
|
|
|
|
|
|
int fSource = kAge_Source;
|
|
|
|
int fFrame = kWorld_ParticleFrame;
|
|
|
|
int fTileMode = kRepeat_TileMode;
|
|
|
|
|
|
|
|
// We map fLeft -> 0 and fRight -> 1. This is easier to work with and reason about.
|
|
|
|
float fLeft = 0.0f;
|
|
|
|
float fRight = 1.0f;
|
|
|
|
|
|
|
|
// Cached from the above
|
|
|
|
float fScale = 1.0f;
|
|
|
|
float fBias = 0.0f;
|
|
|
|
|
|
|
|
private:
|
|
|
|
float getSourceValue(const SkParticleUpdateParams& params, SkParticleState& ps) const;
|
Experimental Particle System
This adds a new "Particles" slide to viewer, that allows
editing, loading, and saving particle effects. All of the
particle system code is in modules/particles.
There are many rough edges and some not-yet-finished changes
to generalize the model[1]. A rough overview:
- SkReflected.h implements a lightweight reflection system
for classes derived from SkReflected. Adding a new class
involves deriving from SkReflected, adding a macro to the
class declaration, and implementing visitFields(), which
simply calls a virtual on an SkFieldVisitor for each field.
Currently, emitters and affectors use this mechanism.
- SkParticleSerialization.h demonstrates two useful field
visitors - for serializing to and from JSON. The driver
code that uses those is directly in ParticlesSlide.
- SkParticleData.h and SkCurve.h define a variety of helper
types for talking about particles, both for parameterizing
individual values, and communicating about the state of a
particle among the effect, affectors, and emitters.
- SkParticleEffect.h defines the static data definition of
an effect (SkParticleEffectParams), as well as a running
instance of an effect (SkParticleEffect). The effect has
simple update() and draw() methods.
- ParticlesSlide.cpp adds a third field visitor to generate
GUIs for interactively editing the running effect.
---
1: The critical change I'd like to make is to remove all
special case behavior over time and at spawn (setting sprite
frames, size over time, color over time, etc...). Integration
is the only fixed function behavior. Everything else is driven
by two lists of affectors. One is applied at spawn time, using
the effect's lifetime to evaluate curves. This allows spawning
particles with different colors as the effect ages out, for
example. The second list is applied every frame to update
existing particles, and is driven by the particle's lifetime.
This allows particles to change color after being spawned, for
example.
With a small set of affectors using a single expressive curve
primitive (keyframed list of cubic curve segments), we can
have affectors that update color, size, velocity, position,
sprite frame, etc., and implement many complex behaviors.
Bug: skia:
Change-Id: Id9402bef22825d55d021c5a2f9e5e41791aabaf4
Reviewed-on: https://skia-review.googlesource.com/c/181404
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
2019-02-12 18:27:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif // SkParticleData_DEFINED
|