[skottie] Fractal Noise: cycle evolution support
AE allows for optional cycling of evolution, after a certain number of revolutions. To support: - split off the base/offset component into a separate uniform (currently front-loaded into evolution) - introduce an additional "cycle" (period) uniform to mod() the noise plane calculations Change-Id: Ib412027114c467934c549cc1438a7d4560aa14bc Reviewed-on: https://skia-review.googlesource.com/c/skia/+/460116 Reviewed-by: Jorge Betancourt <jmbetancourt@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: Florin Malita <fmalita@google.com>
This commit is contained in:
parent
9f43ceefa3
commit
b6a3aa7eb5
@ -57,7 +57,9 @@ static constexpr char gNoiseEffectSkSL[] =
|
||||
|
||||
"uniform half u_octaves," // number of octaves (can be fractional)
|
||||
"u_persistence," // relative octave weight
|
||||
"u_evolution;" // evolution/seed
|
||||
"u_evo," // evolution
|
||||
"u_evo_offset," // evolution offset (based on rnd seed)
|
||||
"u_evo_cycle;" // evolution period
|
||||
|
||||
// Hash based on hash13 (https://www.shadertoy.com/view/4djSRW).
|
||||
"half hash(half3 v) {"
|
||||
@ -72,10 +74,12 @@ static constexpr char gNoiseEffectSkSL[] =
|
||||
"half sample_noise(vec2 xy) {"
|
||||
"xy = floor(xy);"
|
||||
|
||||
"half e_ = floor(u_evolution),"
|
||||
"t = u_evolution - e_,"
|
||||
"n0 = hash(half3(xy, e_ + 0)),"
|
||||
"n1 = hash(half3(xy, e_ + 1));"
|
||||
"half e_ = floor(u_evo),"
|
||||
"t = u_evo - e_,"
|
||||
"np0 = mod(e_ + 0, u_evo_cycle) + u_evo_offset,"
|
||||
"np1 = mod(e_ + 1, u_evo_cycle) + u_evo_offset,"
|
||||
"n0 = hash(half3(xy, np0)),"
|
||||
"n1 = hash(half3(xy, np1));"
|
||||
|
||||
// Note: Ideally we would use 4 samples (-1, 0, 1, 2) and cubic interpolation for
|
||||
// better results -- but that's significantly more expensive than lerp.
|
||||
@ -235,14 +239,16 @@ class FractalNoiseNode final : public sksg::CustomRenderNode {
|
||||
public:
|
||||
explicit FractalNoiseNode(sk_sp<RenderNode> child) : INHERITED({std::move(child)}) {}
|
||||
|
||||
SG_ATTRIBUTE(Matrix , SkMatrix , fMatrix )
|
||||
SG_ATTRIBUTE(SubMatrix , SkMatrix , fSubMatrix )
|
||||
SG_ATTRIBUTE(Matrix , SkMatrix , fMatrix )
|
||||
SG_ATTRIBUTE(SubMatrix , SkMatrix , fSubMatrix )
|
||||
|
||||
SG_ATTRIBUTE(NoiseFilter , NoiseFilter , fFilter )
|
||||
SG_ATTRIBUTE(NoiseFractal, NoiseFractal, fFractal )
|
||||
SG_ATTRIBUTE(Octaves , float , fOctaves )
|
||||
SG_ATTRIBUTE(Persistence , float , fPersistence)
|
||||
SG_ATTRIBUTE(Evolution , float , fEvolution )
|
||||
SG_ATTRIBUTE(NoiseFilter , NoiseFilter , fFilter )
|
||||
SG_ATTRIBUTE(NoiseFractal , NoiseFractal, fFractal )
|
||||
SG_ATTRIBUTE(Octaves , float , fOctaves )
|
||||
SG_ATTRIBUTE(Persistence , float , fPersistence )
|
||||
SG_ATTRIBUTE(Evolution , float , fEvolution )
|
||||
SG_ATTRIBUTE(EvolutionOffset, float , fEvolutionOffset)
|
||||
SG_ATTRIBUTE(EvolutionCycle , float , fEvolutionCycle )
|
||||
|
||||
private:
|
||||
template <NoiseFilter FI, NoiseFractal FR>
|
||||
@ -285,10 +291,12 @@ private:
|
||||
sk_sp<SkShader> buildEffectShader() const {
|
||||
SkRuntimeShaderBuilder builder(this->getEffect());
|
||||
|
||||
builder.uniform("u_octaves") = fOctaves;
|
||||
builder.uniform("u_octaves" ) = fOctaves;
|
||||
builder.uniform("u_persistence") = fPersistence;
|
||||
builder.uniform("u_evolution") = fEvolution;
|
||||
builder.uniform("u_submatrix") = std::array<float,9>{
|
||||
builder.uniform("u_evo" ) = fEvolution;
|
||||
builder.uniform("u_evo_offset" ) = fEvolutionOffset;
|
||||
builder.uniform("u_evo_cycle" ) = fEvolutionCycle;
|
||||
builder.uniform("u_submatrix" ) = std::array<float,9>{
|
||||
fSubMatrix.rc(0,0), fSubMatrix.rc(1,0), fSubMatrix.rc(2,0),
|
||||
fSubMatrix.rc(0,1), fSubMatrix.rc(1,1), fSubMatrix.rc(2,1),
|
||||
fSubMatrix.rc(0,2), fSubMatrix.rc(1,2), fSubMatrix.rc(2,2),
|
||||
@ -327,11 +335,13 @@ private:
|
||||
|
||||
SkMatrix fMatrix,
|
||||
fSubMatrix;
|
||||
NoiseFilter fFilter = NoiseFilter::kNearest;
|
||||
NoiseFractal fFractal = NoiseFractal::kBasic;
|
||||
float fOctaves = 1,
|
||||
fPersistence = 1,
|
||||
fEvolution = 0;
|
||||
NoiseFilter fFilter = NoiseFilter::kNearest;
|
||||
NoiseFractal fFractal = NoiseFractal::kBasic;
|
||||
float fOctaves = 1,
|
||||
fPersistence = 1,
|
||||
fEvolution = 0,
|
||||
fEvolutionOffset = 0,
|
||||
fEvolutionCycle = SK_ScalarMax;
|
||||
|
||||
using INHERITED = sksg::CustomRenderNode;
|
||||
};
|
||||
@ -370,8 +380,8 @@ public:
|
||||
// 22 -- sub settings end-group
|
||||
.bind(23, fEvolution )
|
||||
// 24 -- evolution options begin-group
|
||||
// 25 -- cycle evolution
|
||||
// 26 -- cycle revolution
|
||||
.bind(25, fCycleEvolution )
|
||||
.bind(26, fCycleRevolutions)
|
||||
.bind(27, fRandomSeed )
|
||||
// 28 -- evolution options end-group
|
||||
.bind(29, fOpacity );
|
||||
@ -379,14 +389,33 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
float evolution() const {
|
||||
std::tuple<float, float, float> evolution() const {
|
||||
// Constant chosen to visually match AE's evolution rate.
|
||||
const auto evo = SkDegreesToRadians(fEvolution) * 0.25f;
|
||||
static constexpr auto kEvolutionScale = 0.25f;
|
||||
|
||||
// The random seed determines an arbitrary start plane.
|
||||
const auto base = SkRandom(static_cast<uint32_t>(fRandomSeed)).nextRangeU(0, 100);
|
||||
// Evolution inputs:
|
||||
//
|
||||
// * evolution - main evolution control (degrees)
|
||||
// * cycle evolution - flag controlling whether evolution cycles
|
||||
// * cycle revolutions - number of revolutions after which evolution cycles (period)
|
||||
// * random seed - determines an arbitrary starting plane (evolution offset)
|
||||
//
|
||||
// The shader uses evolution floor/ceil to select two noise planes, and the fractional part
|
||||
// to interpolate between the two -> in order to wrap around smoothly, the cycle/period
|
||||
// must be integral.
|
||||
const float
|
||||
evo_rad = SkDegreesToRadians(fEvolution),
|
||||
rev_rad = std::max(fCycleRevolutions, 1.0f)*SK_FloatPI*2,
|
||||
cycle = fCycleEvolution
|
||||
? SkScalarRoundToScalar(rev_rad*kEvolutionScale)
|
||||
: SK_ScalarMax,
|
||||
// Adjust scale when cycling to ensure an integral period (post scaling).
|
||||
scale = fCycleEvolution
|
||||
? cycle/rev_rad
|
||||
: kEvolutionScale,
|
||||
offset = SkRandom(static_cast<uint32_t>(fRandomSeed)).nextRangeU(0, 100);
|
||||
|
||||
return evo + base;
|
||||
return std::make_tuple(evo_rad*scale, offset, cycle);
|
||||
}
|
||||
|
||||
SkMatrix shaderMatrix() const {
|
||||
@ -433,9 +462,13 @@ private:
|
||||
void onSync() override {
|
||||
const auto& n = this->node();
|
||||
|
||||
const auto [evo, evo_offset, evo_cycle] = this->evolution();
|
||||
|
||||
n->setOctaves(SkTPin(fComplexity, 1.0f, 20.0f));
|
||||
n->setPersistence(SkTPin(fSubInfluence * 0.01f, 0.0f, 100.0f));
|
||||
n->setEvolution(this->evolution());
|
||||
n->setEvolution(evo);
|
||||
n->setEvolutionOffset(evo_offset);
|
||||
n->setEvolutionCycle(evo_cycle);
|
||||
n->setNoiseFilter(this->noiseFilter());
|
||||
n->setNoiseFractal(this->noiseFractal());
|
||||
n->setMatrix(this->shaderMatrix());
|
||||
@ -460,6 +493,8 @@ private:
|
||||
fSubRotation = 0,
|
||||
|
||||
fEvolution = 0,
|
||||
fCycleEvolution = 0,
|
||||
fCycleRevolutions = 0,
|
||||
fRandomSeed = 0,
|
||||
|
||||
fOpacity = 100, // TODO
|
||||
|
1
resources/skottie/skottie-fractalnoise-cycle.json
Normal file
1
resources/skottie/skottie-fractalnoise-cycle.json
Normal file
@ -0,0 +1 @@
|
||||
{"v":"5.7.14","fr":60,"ip":0,"op":300,"w":500,"h":500,"nm":"fractal-cycle","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":1,"nm":"Black Solid 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[250,250,0],"ix":2,"l":2},"a":{"a":0,"k":[250,250,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ef":[{"ty":5,"nm":"Fractal Noise","np":33,"mn":"ADBE Fractal Noise","ix":1,"en":1,"ef":[{"ty":7,"nm":"Fractal Type","mn":"ADBE Fractal Noise-0001","ix":1,"v":{"a":0,"k":5,"ix":1}},{"ty":7,"nm":"Noise Type","mn":"ADBE Fractal Noise-0002","ix":2,"v":{"a":0,"k":3,"ix":2}},{"ty":7,"nm":"Invert","mn":"ADBE Fractal Noise-0003","ix":3,"v":{"a":0,"k":0,"ix":3}},{"ty":0,"nm":"Contrast","mn":"ADBE Fractal Noise-0004","ix":4,"v":{"a":0,"k":100,"ix":4}},{"ty":0,"nm":"Brightness","mn":"ADBE Fractal Noise-0005","ix":5,"v":{"a":0,"k":0,"ix":5}},{"ty":7,"nm":"Overflow","mn":"ADBE Fractal Noise-0006","ix":6,"v":{"a":0,"k":4,"ix":6}},{"ty":6,"nm":"Transform","mn":"ADBE Fractal Noise-0007","ix":7,"v":0},{"ty":0,"nm":"Rotation","mn":"ADBE Fractal Noise-0008","ix":8,"v":{"a":0,"k":0,"ix":8}},{"ty":7,"nm":"Uniform Scaling","mn":"ADBE Fractal Noise-0009","ix":9,"v":{"a":0,"k":1,"ix":9}},{"ty":0,"nm":"Scale","mn":"ADBE Fractal Noise-0010","ix":10,"v":{"a":0,"k":100,"ix":10}},{"ty":0,"nm":"Scale Width","mn":"ADBE Fractal Noise-0011","ix":11,"v":{"a":0,"k":100,"ix":11}},{"ty":0,"nm":"Scale Height","mn":"ADBE Fractal Noise-0012","ix":12,"v":{"a":0,"k":100,"ix":12}},{"ty":3,"nm":"Offset Turbulence","mn":"ADBE Fractal Noise-0013","ix":13,"v":{"a":0,"k":[250,250],"ix":13}},{"ty":7,"nm":"Perspective Offset","mn":"ADBE Fractal Noise-0031","ix":14,"v":{"a":0,"k":0,"ix":14}},{"ty":6,"nm":"","mn":"ADBE Fractal Noise-0014","ix":15,"v":0},{"ty":0,"nm":"Complexity","mn":"ADBE Fractal Noise-0015","ix":16,"v":{"a":0,"k":1,"ix":16}},{"ty":6,"nm":"Sub Settings","mn":"ADBE Fractal Noise-0016","ix":17,"v":0},{"ty":0,"nm":"Sub Influence (%)","mn":"ADBE Fractal Noise-0017","ix":18,"v":{"a":0,"k":70,"ix":18}},{"ty":0,"nm":"Sub Scaling","mn":"ADBE Fractal Noise-0018","ix":19,"v":{"a":0,"k":56,"ix":19}},{"ty":0,"nm":"Sub Rotation","mn":"ADBE Fractal Noise-0019","ix":20,"v":{"a":0,"k":0,"ix":20}},{"ty":3,"nm":"Sub Offset","mn":"ADBE Fractal Noise-0020","ix":21,"v":{"a":0,"k":[0,0],"ix":21}},{"ty":7,"nm":"Center Subscale","mn":"ADBE Fractal Noise-0021","ix":22,"v":{"a":0,"k":0,"ix":22}},{"ty":6,"nm":"","mn":"ADBE Fractal Noise-0022","ix":23,"v":0},{"ty":0,"nm":"Evolution","mn":"ADBE Fractal Noise-0023","ix":24,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-720]},{"t":299,"s":[720]}],"ix":24}},{"ty":6,"nm":"Evolution Options","mn":"ADBE Fractal Noise-0024","ix":25,"v":0},{"ty":7,"nm":"Cycle Evolution","mn":"ADBE Fractal Noise-0025","ix":26,"v":{"a":0,"k":1,"ix":26}},{"ty":0,"nm":"Cycle (in Revolutions)","mn":"ADBE Fractal Noise-0026","ix":27,"v":{"a":0,"k":2,"ix":27}},{"ty":0,"nm":"Random Seed","mn":"ADBE Fractal Noise-0027","ix":28,"v":{"a":0,"k":350,"ix":28}},{"ty":6,"nm":"Random Seed","mn":"ADBE Fractal Noise-0028","ix":29,"v":0},{"ty":0,"nm":"Opacity","mn":"ADBE Fractal Noise-0029","ix":30,"v":{"a":0,"k":100,"ix":30}},{"ty":7,"nm":"Blending Mode","mn":"ADBE Fractal Noise-0030","ix":31,"v":{"a":0,"k":2,"ix":31}}]}],"sw":500,"sh":500,"sc":"#000000","ip":0,"op":300,"st":0,"bm":0}],"markers":[]}
|
Loading…
Reference in New Issue
Block a user