From 0c48681e58d65258e4b7c2c747cad1ee4b1d2fd5 Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Tue, 26 Feb 2019 10:02:15 -0500 Subject: [PATCH] Few more particle features and some generalization work Add particle "frame" enum, to allow effects relative to local, world, or velocity. Remove the "orient along velocity" and replace with a much more general orientation affector (angle curve + frame). Add an angular velocity affector to mirror the behavior of the linear velocity affector. Bug: skia: Change-Id: Ibbaaeb352c9547d00d81c7916d00148dd65ed2b9 Reviewed-on: https://skia-review.googlesource.com/c/195361 Reviewed-by: Brian Osman Commit-Queue: Brian Osman --- .../particles/include/SkParticleAffector.h | 18 +++- modules/particles/src/SkParticleAffector.cpp | 99 +++++++++++++++---- resources/particles/default.json | 4 +- resources/particles/explosion.json | 2 + resources/particles/penguin_cannon.json | 28 +++++- resources/particles/snowfall.json | 4 +- resources/particles/spiral.json | 4 + resources/particles/swirl.json | 8 +- resources/particles/warp.json | 2 + 9 files changed, 142 insertions(+), 27 deletions(-) diff --git a/modules/particles/include/SkParticleAffector.h b/modules/particles/include/SkParticleAffector.h index 5d08a09254..0efc54b7e3 100644 --- a/modules/particles/include/SkParticleAffector.h +++ b/modules/particles/include/SkParticleAffector.h @@ -17,6 +17,12 @@ struct SkCurve; struct SkParticleState; struct SkParticleUpdateParams; +enum SkParticleFrame { + kWorld_ParticleFrame, // "Up" is { 0, -1 } + kLocal_ParticleFrame, // "Up" is particle's heading + kVelocity_ParticleFrame, // "Up" is particle's direction of travel +}; + class SkParticleAffector : public SkReflected { public: REFLECTED_ABSTRACT(SkParticleAffector, SkReflected) @@ -26,13 +32,21 @@ public: static void RegisterAffectorTypes(); + // Affectors that can set the linear or angular velocity. Both have a 'force' option to apply + // the resulting value as a force, rather than directly setting the velocity. static sk_sp MakeLinearVelocity(const SkCurve& angle, const SkCurve& strength, bool force, - bool local); + SkParticleFrame frame); + static sk_sp MakeAngularVelocity(const SkCurve& strength, + bool force); + + // Set the orientation of a particle, relative to the world, local, or velocity frame. + static sk_sp MakeOrientation(const SkCurve& angle, + SkParticleFrame frame); + static sk_sp MakePointForce(SkPoint point, SkScalar constant, SkScalar invSquare); - static sk_sp MakeOrientAlongVelocity(); static sk_sp MakeSize(const SkCurve& curve); static sk_sp MakeFrame(const SkCurve& curve); diff --git a/modules/particles/src/SkParticleAffector.cpp b/modules/particles/src/SkParticleAffector.cpp index de1a66c2d8..8ff80a0806 100644 --- a/modules/particles/src/SkParticleAffector.cpp +++ b/modules/particles/src/SkParticleAffector.cpp @@ -21,16 +21,33 @@ void SkParticleAffector::visitFields(SkFieldVisitor* v) { v->visit("Enabled", fEnabled); } +static inline SkVector get_heading(const SkParticleState& ps, SkParticleFrame frame) { + switch (frame) { + case kLocal_ParticleFrame: + return ps.fPose.fHeading; + case kVelocity_ParticleFrame: { + SkVector heading = ps.fVelocity.fLinear; + if (!heading.normalize()) { + heading.set(0, -1); + } + return heading; + } + case kWorld_ParticleFrame: + default: + return SkVector{ 0, -1 }; + } +} + class SkLinearVelocityAffector : public SkParticleAffector { public: SkLinearVelocityAffector(const SkCurve& angle = 0.0f, const SkCurve& strength = 0.0f, bool force = true, - bool local = false) + SkParticleFrame frame = kWorld_ParticleFrame) : fAngle(angle) , fStrength(strength) , fForce(force) - , fLocal(local) {} + , fFrame(frame) {} REFLECTED(SkLinearVelocityAffector, SkParticleAffector) @@ -38,7 +55,7 @@ public: for (int i = 0; i < count; ++i) { float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom); SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local); - SkVector heading = fLocal ? ps[i].fPose.fHeading : SkVector{ 0, -1 }; + SkVector heading = get_heading(ps[i], static_cast(fFrame)); SkScalar c = heading.fX * c_local - heading.fY * s_local; SkScalar s = heading.fX * s_local + heading.fY * c_local; float strength = fStrength.eval(ps[i].fAge, ps[i].fStableRandom); @@ -54,7 +71,7 @@ public: void visitFields(SkFieldVisitor* v) override { SkParticleAffector::visitFields(v); v->visit("Force", fForce); - v->visit("Local", fLocal); + v->visit("Frame", fFrame); v->visit("Angle", fAngle); v->visit("Strength", fStrength); } @@ -63,7 +80,37 @@ private: SkCurve fAngle; SkCurve fStrength; bool fForce; - bool fLocal; + int fFrame; +}; + +class SkAngularVelocityAffector : public SkParticleAffector { +public: + SkAngularVelocityAffector(const SkCurve& strength = 0.0f, bool force = true) + : fStrength(strength) + , fForce(force) {} + + REFLECTED(SkAngularVelocityAffector, SkParticleAffector) + + void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override { + for (int i = 0; i < count; ++i) { + float strength = fStrength.eval(ps[i].fAge, ps[i].fStableRandom); + if (fForce) { + ps[i].fVelocity.fAngular += strength * params.fDeltaTime; + } else { + ps[i].fVelocity.fAngular = strength; + } + } + } + + void visitFields(SkFieldVisitor* v) override { + SkParticleAffector::visitFields(v); + v->visit("Force", fForce); + v->visit("Strength", fStrength); + } + +private: + SkCurve fStrength; + bool fForce; }; class SkPointForceAffector : public SkParticleAffector { @@ -97,25 +144,34 @@ private: SkScalar fInvSquare; }; -class SkOrientAlongVelocityAffector : public SkParticleAffector { +class SkOrientationAffector : public SkParticleAffector { public: - SkOrientAlongVelocityAffector() {} + SkOrientationAffector(const SkCurve& angle = 0.0f, + SkParticleFrame frame = kLocal_ParticleFrame) + : fAngle(angle) + , fFrame(frame) {} - REFLECTED(SkOrientAlongVelocityAffector, SkParticleAffector) + REFLECTED(SkOrientationAffector, SkParticleAffector) void onApply(SkParticleUpdateParams& params, SkParticleState ps[], int count) override { for (int i = 0; i < count; ++i) { - SkVector heading = ps[i].fVelocity.fLinear; - if (!heading.normalize()) { - heading.set(0, -1); - } - ps[i].fPose.fHeading = heading; + float angle = fAngle.eval(ps[i].fAge, ps[i].fStableRandom); + SkScalar c_local, s_local = SkScalarSinCos(SkDegreesToRadians(angle), &c_local); + SkVector heading = get_heading(ps[i], static_cast(fFrame)); + ps[i].fPose.fHeading.set(heading.fX * c_local - heading.fY * s_local, + heading.fX * s_local + heading.fY * c_local); } } void visitFields(SkFieldVisitor *v) override { SkParticleAffector::visitFields(v); + v->visit("Frame", fFrame); + v->visit("Angle", fAngle); } + +private: + SkCurve fAngle; + int fFrame; }; class SkSizeAffector : public SkParticleAffector { @@ -185,8 +241,9 @@ private: void SkParticleAffector::RegisterAffectorTypes() { REGISTER_REFLECTED(SkParticleAffector); REGISTER_REFLECTED(SkLinearVelocityAffector); + REGISTER_REFLECTED(SkAngularVelocityAffector); REGISTER_REFLECTED(SkPointForceAffector); - REGISTER_REFLECTED(SkOrientAlongVelocityAffector); + REGISTER_REFLECTED(SkOrientationAffector); REGISTER_REFLECTED(SkSizeAffector); REGISTER_REFLECTED(SkFrameAffector); REGISTER_REFLECTED(SkColorAffector); @@ -195,8 +252,13 @@ void SkParticleAffector::RegisterAffectorTypes() { sk_sp SkParticleAffector::MakeLinearVelocity(const SkCurve& angle, const SkCurve& strength, bool force, - bool local) { - return sk_sp(new SkLinearVelocityAffector(angle, strength, force, local)); + SkParticleFrame frame) { + return sk_sp(new SkLinearVelocityAffector(angle, strength, force, frame)); +} + +sk_sp SkParticleAffector::MakeAngularVelocity(const SkCurve& strength, + bool force) { + return sk_sp(new SkAngularVelocityAffector(strength, force)); } sk_sp SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant, @@ -204,8 +266,9 @@ sk_sp SkParticleAffector::MakePointForce(SkPoint point, SkSc return sk_sp(new SkPointForceAffector(point, constant, invSquare)); } -sk_sp SkParticleAffector::MakeOrientAlongVelocity() { - return sk_sp(new SkOrientAlongVelocityAffector()); +sk_sp SkParticleAffector::MakeOrientation(const SkCurve& angle, + SkParticleFrame frame) { + return sk_sp(new SkOrientationAffector(angle, frame)); } sk_sp SkParticleAffector::MakeSize(const SkCurve& curve) { diff --git a/resources/particles/default.json b/resources/particles/default.json index 6443c92a06..a943a52ff4 100644 --- a/resources/particles/default.json +++ b/resources/particles/default.json @@ -32,8 +32,9 @@ "Spawn": [ { "Type": "SkLinearVelocityAffector", + "Enabled": true, "Force": false, - "Local": false, + "Frame": 0, "Angle": { "XValues": [], "Segments": [ @@ -75,6 +76,7 @@ "Update": [ { "Type": "SkColorAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [ diff --git a/resources/particles/explosion.json b/resources/particles/explosion.json index 51d49efc4d..970a0d68b5 100644 --- a/resources/particles/explosion.json +++ b/resources/particles/explosion.json @@ -35,12 +35,14 @@ "Update": [ { "Type": "SkPointForceAffector", + "Enabled": true, "Point": { "x": 200, "y": 200 }, "Constant": 0, "InvSquare": -50 }, { "Type": "SkFrameAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [ diff --git a/resources/particles/penguin_cannon.json b/resources/particles/penguin_cannon.json index 3bccb05163..f75a743792 100644 --- a/resources/particles/penguin_cannon.json +++ b/resources/particles/penguin_cannon.json @@ -34,8 +34,9 @@ "Spawn": [ { "Type": "SkLinearVelocityAffector", + "Enabled": true, "Force": false, - "Local": false, + "Frame": 0, "Angle": { "XValues": [], "Segments": [ @@ -77,8 +78,9 @@ "Update": [ { "Type": "SkLinearVelocityAffector", + "Enabled": true, "Force": true, - "Local": false, + "Frame": 0, "Angle": { "XValues": [], "Segments": [ @@ -117,7 +119,27 @@ } }, { - "Type": "SkOrientAlongVelocityAffector" + "Type": "SkOrientationAffector", + "Enabled": true, + "Frame": 2, + "Angle": { + "XValues": [], + "Segments": [ + { + "Constant": true, + "Ranged": false, + "Bidirectional": false, + "A0": 0, + "B0": 0, + "C0": 0, + "D0": 0, + "A1": 0, + "B1": 0, + "C1": 0, + "D1": 0 + } + ] + } } ] } \ No newline at end of file diff --git a/resources/particles/snowfall.json b/resources/particles/snowfall.json index 1734a9a6b9..14821e03b5 100644 --- a/resources/particles/snowfall.json +++ b/resources/particles/snowfall.json @@ -32,8 +32,9 @@ "Spawn": [ { "Type": "SkLinearVelocityAffector", + "Enabled": true, "Force": false, - "Local": false, + "Frame": 0, "Angle": { "XValues": [], "Segments": [ @@ -75,6 +76,7 @@ "Update": [ { "Type": "SkSizeAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [ diff --git a/resources/particles/spiral.json b/resources/particles/spiral.json index c55113a7ed..b0b5363d02 100644 --- a/resources/particles/spiral.json +++ b/resources/particles/spiral.json @@ -32,7 +32,9 @@ "Spawn": [ { "Type": "SkLinearVelocityAffector", + "Enabled": true, "Force": false, + "Frame": 0, "Angle": { "XValues": [], "Segments": [ @@ -74,6 +76,7 @@ "Update": [ { "Type": "SkSizeAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [ @@ -95,6 +98,7 @@ }, { "Type": "SkColorAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [ diff --git a/resources/particles/swirl.json b/resources/particles/swirl.json index 23c325c567..4c30b3b69b 100644 --- a/resources/particles/swirl.json +++ b/resources/particles/swirl.json @@ -32,8 +32,9 @@ "Spawn": [ { "Type": "SkLinearVelocityAffector", + "Enabled": true, "Force": false, - "Local": false, + "Frame": 0, "Angle": { "XValues": [], "Segments": [ @@ -75,8 +76,9 @@ "Update": [ { "Type": "SkLinearVelocityAffector", + "Enabled": true, "Force": true, - "Local": false, + "Frame": 0, "Angle": { "XValues": [], "Segments": [ @@ -116,6 +118,7 @@ }, { "Type": "SkSizeAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [ @@ -137,6 +140,7 @@ }, { "Type": "SkColorAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [ diff --git a/resources/particles/warp.json b/resources/particles/warp.json index e788a068cd..b96074ef31 100644 --- a/resources/particles/warp.json +++ b/resources/particles/warp.json @@ -33,12 +33,14 @@ "Update": [ { "Type": "SkPointForceAffector", + "Enabled": true, "Point": { "x": 375, "y": 273 }, "Constant": -10, "InvSquare": 0 }, { "Type": "SkSizeAffector", + "Enabled": true, "Curve": { "XValues": [], "Segments": [