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 <brianosman@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
Brian Osman 2019-02-26 10:02:15 -05:00 committed by Skia Commit-Bot
parent 804f17e35b
commit 0c48681e58
9 changed files with 142 additions and 27 deletions

View File

@ -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<SkParticleAffector> MakeLinearVelocity(const SkCurve& angle,
const SkCurve& strength,
bool force,
bool local);
SkParticleFrame frame);
static sk_sp<SkParticleAffector> MakeAngularVelocity(const SkCurve& strength,
bool force);
// Set the orientation of a particle, relative to the world, local, or velocity frame.
static sk_sp<SkParticleAffector> MakeOrientation(const SkCurve& angle,
SkParticleFrame frame);
static sk_sp<SkParticleAffector> MakePointForce(SkPoint point, SkScalar constant,
SkScalar invSquare);
static sk_sp<SkParticleAffector> MakeOrientAlongVelocity();
static sk_sp<SkParticleAffector> MakeSize(const SkCurve& curve);
static sk_sp<SkParticleAffector> MakeFrame(const SkCurve& curve);

View File

@ -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<SkParticleFrame>(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<SkParticleFrame>(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> SkParticleAffector::MakeLinearVelocity(const SkCurve& angle,
const SkCurve& strength,
bool force,
bool local) {
return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, local));
SkParticleFrame frame) {
return sk_sp<SkParticleAffector>(new SkLinearVelocityAffector(angle, strength, force, frame));
}
sk_sp<SkParticleAffector> SkParticleAffector::MakeAngularVelocity(const SkCurve& strength,
bool force) {
return sk_sp<SkParticleAffector>(new SkAngularVelocityAffector(strength, force));
}
sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkScalar constant,
@ -204,8 +266,9 @@ sk_sp<SkParticleAffector> SkParticleAffector::MakePointForce(SkPoint point, SkSc
return sk_sp<SkParticleAffector>(new SkPointForceAffector(point, constant, invSquare));
}
sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientAlongVelocity() {
return sk_sp<SkParticleAffector>(new SkOrientAlongVelocityAffector());
sk_sp<SkParticleAffector> SkParticleAffector::MakeOrientation(const SkCurve& angle,
SkParticleFrame frame) {
return sk_sp<SkParticleAffector>(new SkOrientationAffector(angle, frame));
}
sk_sp<SkParticleAffector> SkParticleAffector::MakeSize(const SkCurve& curve) {

View File

@ -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": [

View File

@ -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": [

View File

@ -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
}
]
}
}
]
}

View File

@ -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": [

View File

@ -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": [

View File

@ -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": [

View File

@ -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": [