plumb experimental SkSL layer effect in native Skottie player
Long term plan is to expose a plugin (standalone or with bodymovin) that allows motion artists to write sksl into a composition. This is the first step where we test how we'd read in the json data under the hood. Change-Id: I300d3af5d01e12f5b495970f89fd12b5f464a9a1 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/464368 Commit-Queue: Jorge Betancourt <jmbetancourt@google.com> Reviewed-by: Florin Malita <fmalita@google.com>
This commit is contained in:
parent
83e99569bd
commit
172c7998e1
@ -64,6 +64,7 @@ skia_skottie_sources = [
|
||||
"$_src/effects/RadialWipeEffect.cpp",
|
||||
"$_src/effects/ShadowStyles.cpp",
|
||||
"$_src/effects/ShiftChannelsEffect.cpp",
|
||||
"$_src/effects/SkSLEffect.cpp",
|
||||
"$_src/effects/SphereEffect.cpp",
|
||||
"$_src/effects/ThresholdEffect.cpp",
|
||||
"$_src/effects/TintEffect.cpp",
|
||||
|
@ -56,7 +56,8 @@ EffectBuilder::EffectBuilderT EffectBuilder::findBuilder(const skjson::ObjectVal
|
||||
{ "ADBE Tritone" , &EffectBuilder::attachTritoneEffect },
|
||||
{ "ADBE Venetian Blinds" , &EffectBuilder::attachVenetianBlindsEffect },
|
||||
{ "CC Sphere" , &EffectBuilder::attachSphereEffect },
|
||||
{ "CC Toner" , &EffectBuilder::attachCCTonerEffect },
|
||||
{ "CC Toner" , &EffectBuilder::attachCCTonerEffect },
|
||||
{ "SkSL Shader" , &EffectBuilder::attachSkSLEffect },
|
||||
};
|
||||
|
||||
const skjson::StringValue* mn = jeffect["mn"];
|
||||
|
@ -79,6 +79,8 @@ private:
|
||||
sk_sp<sksg::RenderNode>) const;
|
||||
sk_sp<sksg::RenderNode> attachShiftChannelsEffect (const skjson::ArrayValue&,
|
||||
sk_sp<sksg::RenderNode>) const;
|
||||
sk_sp<sksg::RenderNode> attachSkSLEffect (const skjson::ArrayValue&,
|
||||
sk_sp<sksg::RenderNode>) const;
|
||||
sk_sp<sksg::RenderNode> attachSphereEffect (const skjson::ArrayValue&,
|
||||
sk_sp<sksg::RenderNode>) const;
|
||||
sk_sp<sksg::RenderNode> attachThresholdEffect (const skjson::ArrayValue&,
|
||||
|
144
modules/skottie/src/effects/SkSLEffect.cpp
Normal file
144
modules/skottie/src/effects/SkSLEffect.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2021 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "modules/skottie/src/effects/Effects.h"
|
||||
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
#include "modules/skottie/src/Adapter.h"
|
||||
#include "modules/skottie/src/SkottieJson.h"
|
||||
#include "modules/skottie/src/SkottieValue.h"
|
||||
#include "modules/sksg/include/SkSGColorFilter.h"
|
||||
|
||||
namespace skottie::internal {
|
||||
|
||||
#ifdef SK_ENABLE_SKSL
|
||||
|
||||
namespace {
|
||||
class SkSLShaderNode final : public sksg::CustomRenderNode {
|
||||
public:
|
||||
explicit SkSLShaderNode(sk_sp<RenderNode> child) : INHERITED({std::move(child)}) {}
|
||||
|
||||
SG_ATTRIBUTE(Shader, sk_sp<SkShader>, fEffectShader)
|
||||
private:
|
||||
SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
|
||||
const auto& child = this->children()[0];
|
||||
return child->revalidate(nullptr, SkMatrix::I());
|
||||
}
|
||||
|
||||
void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
|
||||
const auto& bounds = this->bounds();
|
||||
const auto local_ctx = ScopedRenderContext(canvas, ctx)
|
||||
.setIsolation(bounds, canvas->getTotalMatrix(), true);
|
||||
|
||||
canvas->saveLayer(&bounds, nullptr);
|
||||
this->children()[0]->render(canvas, local_ctx);
|
||||
|
||||
SkPaint effect_paint;
|
||||
effect_paint.setShader(fEffectShader);
|
||||
effect_paint.setBlendMode(SkBlendMode::kSrcIn);
|
||||
|
||||
canvas->drawPaint(effect_paint);
|
||||
}
|
||||
|
||||
const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
|
||||
|
||||
sk_sp<SkShader> fEffectShader;
|
||||
|
||||
using INHERITED = sksg::CustomRenderNode;
|
||||
};
|
||||
|
||||
class SkSLEffectAdapter final : public DiscardableAdapterBase<SkSLEffectAdapter,
|
||||
SkSLShaderNode> {
|
||||
public:
|
||||
SkSLEffectAdapter(const skjson::ArrayValue& jprops,
|
||||
const AnimationBuilder& abuilder,
|
||||
sk_sp<SkSLShaderNode> node)
|
||||
: INHERITED(std::move(node))
|
||||
{
|
||||
enum : size_t {
|
||||
kSkSL_index = 0,
|
||||
kFirstUniform_index = 1,
|
||||
};
|
||||
if (jprops.size() < 1) {
|
||||
return;
|
||||
}
|
||||
const skjson::ObjectValue* jSkSL = jprops[kSkSL_index];
|
||||
if (!jSkSL) {
|
||||
return;
|
||||
}
|
||||
const skjson::StringValue* jShader = (*jSkSL)["sh"];
|
||||
if (!jShader) {
|
||||
return;
|
||||
}
|
||||
SkString shader = SkString(jShader->begin(), jShader->size());
|
||||
auto result = SkRuntimeEffect::MakeForShader(shader, {});
|
||||
if (!result.effect) {
|
||||
abuilder.log(Logger::Level::kError, nullptr, "Failed to parse SkSL shader: %s",
|
||||
result.errorText.c_str());
|
||||
return;
|
||||
}
|
||||
fEffect = std::move(result.effect);
|
||||
|
||||
// construct dynamic uniform list from jprops, skip SkSL property
|
||||
for (size_t i = kFirstUniform_index; i < jprops.size(); i++) {
|
||||
const skjson::ObjectValue* jprop = jprops[i];
|
||||
if (!jprop) { continue; }
|
||||
const skjson::StringValue* uniformName = (*jprop)["nm"];
|
||||
if (!uniformName) { continue; }
|
||||
auto uniformTuple = std::make_tuple(SkString(uniformName->begin(),
|
||||
uniformName->size()),
|
||||
std::make_unique<VectorValue>());
|
||||
fUniforms.push_back(std::move(uniformTuple));
|
||||
this->bind(abuilder, (*jprop)["v"], std::get<1>(fUniforms.back()).get());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void onSync() override {
|
||||
this->node()->setShader(buildEffectShader());
|
||||
}
|
||||
|
||||
sk_sp<SkShader> buildEffectShader() const {
|
||||
if (!fEffect) {
|
||||
return nullptr;
|
||||
}
|
||||
// TODO: consider dumping builder and work with lower level API
|
||||
SkRuntimeShaderBuilder builder = SkRuntimeShaderBuilder(fEffect);
|
||||
for (const auto& uniform : fUniforms) {
|
||||
const auto& name = std::get<0>(uniform);
|
||||
const auto& data = std::get<1>(uniform);
|
||||
auto metadata = fEffect->findUniform(name.c_str());
|
||||
// TODO: build SkData from SkRuntimeEffect::Uniform data
|
||||
switch (metadata->type) {
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat:
|
||||
builder.uniform(name.c_str()) = data->at(0); break;
|
||||
default:
|
||||
printf("!!! %s\n", "uniform data type not supported");
|
||||
}
|
||||
}
|
||||
return builder.makeShader(&SkMatrix::I(), false);
|
||||
}
|
||||
sk_sp<SkRuntimeEffect> fEffect;
|
||||
std::vector<std::tuple<SkString, std::unique_ptr<VectorValue>>> fUniforms;
|
||||
using INHERITED = DiscardableAdapterBase<SkSLEffectAdapter, SkSLShaderNode>;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // SK_ENABLE_SKSL
|
||||
|
||||
sk_sp<sksg::RenderNode> EffectBuilder::attachSkSLEffect(const skjson::ArrayValue& jprops,
|
||||
sk_sp<sksg::RenderNode> layer) const {
|
||||
#ifdef SK_ENABLE_SKSL
|
||||
auto shaderNode = sk_make_sp<SkSLShaderNode>(std::move(layer));
|
||||
return fBuilder->attachDiscardableAdapter<SkSLEffectAdapter>(jprops, *fBuilder, shaderNode);
|
||||
#else
|
||||
return layer;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace skottie::internal
|
1
resources/skottie/skottie-sksl-effect.json
Normal file
1
resources/skottie/skottie-sksl-effect.json
Normal file
@ -0,0 +1 @@
|
||||
{"assets":[],"ddd":0,"fr":60,"h":500,"ip":0,"layers":[{"ao":0,"bm":0,"ddd":0,"ef":[{"ef":[{"ix":1,"mn":"SkSL Shader-0001","nm":"SKSL","sh":"uniform float u_time; float f(vec3 p) {p.z -= u_time * 10.;float a = p.z * .1;p.xy *= mat2(cos(a), sin(a), -sin(a), cos(a));return .1 - length(cos(p.xy) + sin(p.yz));}half4 main(vec2 fragcoord) {vec3 d = .5 - fragcoord.xy1 / 500;vec3 p=vec3(0);for (int i = 0; i < 32; i++) p += f(p) * d;return ((sin(p) + vec3(2, 5, 9)) / length(p)).xyz1;}","ty":0},{"ix":1,"mn":"SkSL Shader-0002","nm":"u_time","ty":0,"v":{"a":1,"ix":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"s":[0],"t":0},{"s":[3.922],"t":299}]}}],"en":1,"ix":1,"mn":"SkSL Shader","nm":"sksl","np":3,"ty":5}],"ind":1,"ip":0,"ks":{"a":{"a":0,"ix":1,"k":[200,200,0],"l":2},"o":{"a":0,"ix":11,"k":100},"p":{"a":0,"ix":2,"k":[250,250,0],"l":2},"r":{"a":0,"ix":10,"k":0},"s":{"a":0,"ix":6,"k":[100,100,100],"l":2}},"nm":"Lime Green Solid 1","op":300,"sc":"#83e325","sh":400,"sr":1,"st":0,"sw":400,"ty":1}],"markers":[],"nm":"sksl","op":300,"v":"5.7.14","w":500}
|
Loading…
Reference in New Issue
Block a user