[skottie] Parented camera support
Parent camera layer transforms apply to the camera itself, thus T_camera' = T_camera x Inv(T_parent) To support this composition: - introduce sksg::Transform::MakeInverse() - allow selectable pre/post parent composition in AnimationBuilder::attachMatrix3D() Change-Id: Ie70b36e4e9bb1b32e60893df5695bdc6c0dc0d00 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/210422 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
fd7657cba2
commit
2253c22afb
@ -118,7 +118,8 @@ sk_sp<sksg::Transform> AnimationBuilder::attachMatrix2D(const skjson::ObjectValu
|
||||
sk_sp<sksg::Transform> AnimationBuilder::attachMatrix3D(const skjson::ObjectValue& t,
|
||||
AnimatorScope* ascope,
|
||||
sk_sp<sksg::Transform> parent,
|
||||
sk_sp<TransformAdapter3D> adapter) const {
|
||||
sk_sp<TransformAdapter3D> adapter,
|
||||
bool precompose_parent) const {
|
||||
static const VectorValue g_default_vec_0 = { 0, 0, 0},
|
||||
g_default_vec_100 = {100, 100, 100};
|
||||
|
||||
@ -167,9 +168,13 @@ sk_sp<sksg::Transform> AnimationBuilder::attachMatrix3D(const skjson::ObjectValu
|
||||
|
||||
// TODO: dispatch 3D transform properties
|
||||
|
||||
return (bound)
|
||||
? sksg::Transform::MakeConcat(std::move(parent), adapter->refTransform())
|
||||
: parent;
|
||||
if (!bound) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
return precompose_parent
|
||||
? sksg::Transform::MakeConcat(adapter->refTransform(), std::move(parent))
|
||||
: sksg::Transform::MakeConcat(std::move(parent), adapter->refTransform());
|
||||
}
|
||||
|
||||
sk_sp<sksg::RenderNode> AnimationBuilder::attachOpacity(const skjson::ObjectValue& jtransform,
|
||||
|
@ -119,8 +119,6 @@ SkMatrix44 CameraAdapter::totalMatrix() const {
|
||||
// * point of interest -> anchor point attribute
|
||||
// * orientation -> rotation attribute
|
||||
//
|
||||
// Note: the orientation is specified post position/POI adjustment.
|
||||
//
|
||||
SkPoint3 pos = { this->getPosition().fX,
|
||||
this->getPosition().fY,
|
||||
-this->getPosition().fZ },
|
||||
@ -129,9 +127,11 @@ SkMatrix44 CameraAdapter::totalMatrix() const {
|
||||
-this->getAnchorPoint().fZ },
|
||||
up = { 0, 1, 0 };
|
||||
|
||||
// Initial camera vector.
|
||||
SkMatrix44 cam_t;
|
||||
Sk3LookAt(&cam_t, pos, poi, up);
|
||||
|
||||
// Rotation origin is camera position.
|
||||
{
|
||||
SkMatrix44 rot;
|
||||
rot.setRotateDegreesAbout(1, 0, 0, this->getRotation().fX);
|
||||
@ -142,6 +142,9 @@ SkMatrix44 CameraAdapter::totalMatrix() const {
|
||||
cam_t.postConcat(rot);
|
||||
}
|
||||
|
||||
// Flip world Z, as it is opposite of what Sk3D expects.
|
||||
cam_t.preScale(1, 1, -1);
|
||||
|
||||
// View parameters:
|
||||
//
|
||||
// * size -> composition size (TODO: AE seems to base it on width only?)
|
||||
@ -151,13 +154,13 @@ SkMatrix44 CameraAdapter::totalMatrix() const {
|
||||
view_distance = this->getZoom(),
|
||||
view_angle = std::atan(view_size * 0.5f / view_distance);
|
||||
|
||||
SkMatrix44 view_t;
|
||||
Sk3Perspective(&view_t, 0, view_distance, 2 * view_angle);
|
||||
view_t.postScale(view_size * 0.5f, view_size * 0.5f, 1);
|
||||
SkMatrix44 persp_t;
|
||||
Sk3Perspective(&persp_t, 0, view_distance, 2 * view_angle);
|
||||
persp_t.postScale(view_size * 0.5f, view_size * 0.5f, 1);
|
||||
|
||||
SkMatrix44 t;
|
||||
t.setTranslate(fViewportSize.width() * 0.5f, fViewportSize.height() * 0.5f, 0);
|
||||
t.preConcat(view_t);
|
||||
t.preConcat(persp_t);
|
||||
t.preConcat(cam_t);
|
||||
|
||||
return t;
|
||||
|
@ -474,9 +474,17 @@ private:
|
||||
camera_adapter->setZoom(pe);
|
||||
});
|
||||
|
||||
// parent_transform applies to the camera itself => it pre-composes inverted to the
|
||||
// camera/view/adapter transform.
|
||||
//
|
||||
// T_camera' = T_camera x Inv(parent_transform)
|
||||
//
|
||||
parent_transform = sksg::Transform::MakeInverse(std::move(parent_transform));
|
||||
|
||||
return abuilder->attachMatrix3D(*jtransform, fScope,
|
||||
std::move(parent_transform),
|
||||
std::move(camera_adapter));
|
||||
std::move(camera_adapter),
|
||||
true); // pre-compose parent
|
||||
}
|
||||
|
||||
return (ParseDefault<int>(jlayer["ddd"], 0) == 0)
|
||||
|
@ -79,7 +79,8 @@ public:
|
||||
sk_sp<sksg::Transform>) const;
|
||||
sk_sp<sksg::Transform> attachMatrix3D(const skjson::ObjectValue&, AnimatorScope*,
|
||||
sk_sp<sksg::Transform>,
|
||||
sk_sp<TransformAdapter3D> = nullptr) const;
|
||||
sk_sp<TransformAdapter3D> = nullptr,
|
||||
bool precompose_parent = false) const;
|
||||
sk_sp<sksg::RenderNode> attachOpacity(const skjson::ObjectValue&, AnimatorScope*,
|
||||
sk_sp<sksg::RenderNode>) const;
|
||||
sk_sp<sksg::Path> attachPath(const skjson::Value&, AnimatorScope*) const;
|
||||
|
1
modules/skottie/tests/camera-parent-1.json
Normal file
1
modules/skottie/tests/camera-parent-1.json
Normal file
File diff suppressed because one or more lines are too long
1
modules/skottie/tests/camera-parent-2.json
Normal file
1
modules/skottie/tests/camera-parent-2.json
Normal file
File diff suppressed because one or more lines are too long
1
modules/skottie/tests/camera-parent-3.json
Normal file
1
modules/skottie/tests/camera-parent-3.json
Normal file
File diff suppressed because one or more lines are too long
@ -20,9 +20,12 @@ namespace sksg {
|
||||
*/
|
||||
class Transform : public Node {
|
||||
public:
|
||||
// Compose T = A x B
|
||||
// Compose T' = A x B
|
||||
static sk_sp<Transform> MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b);
|
||||
|
||||
// T' = Inv(T)
|
||||
static sk_sp<Transform> MakeInverse(sk_sp<Transform> t);
|
||||
|
||||
protected:
|
||||
Transform();
|
||||
|
||||
|
@ -46,10 +46,12 @@ protected:
|
||||
bool is44() const override { return std::is_same<T, SkMatrix44>::value; }
|
||||
|
||||
SkMatrix asMatrix() const override {
|
||||
SkASSERT(!this->hasInval());
|
||||
return fComposed;
|
||||
}
|
||||
|
||||
SkMatrix44 asMatrix44() const override {
|
||||
SkASSERT(!this->hasInval());
|
||||
return fComposed;
|
||||
}
|
||||
|
||||
@ -60,6 +62,52 @@ private:
|
||||
using INHERITED = Transform;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class Inverse final : public Transform {
|
||||
public:
|
||||
template <typename = std::enable_if<std::is_same<T, SkMatrix >::value ||
|
||||
std::is_same<T, SkMatrix44>::value >>
|
||||
explicit Inverse(sk_sp<Transform> t)
|
||||
: fT(std::move(t)) {
|
||||
SkASSERT(fT);
|
||||
|
||||
this->observeInval(fT);
|
||||
}
|
||||
|
||||
~Inverse() override {
|
||||
this->unobserveInval(fT);
|
||||
}
|
||||
|
||||
protected:
|
||||
SkRect onRevalidate(InvalidationController* ic, const SkMatrix& ctm) override {
|
||||
fT->revalidate(ic, ctm);
|
||||
|
||||
if (!TransformPriv::As<T>(fT).invert(&fInverted)) {
|
||||
fInverted.reset();
|
||||
}
|
||||
|
||||
return SkRect::MakeEmpty();
|
||||
}
|
||||
|
||||
bool is44() const override { return std::is_same<T, SkMatrix44>::value; }
|
||||
|
||||
SkMatrix asMatrix() const override {
|
||||
SkASSERT(!this->hasInval());
|
||||
return fInverted;
|
||||
}
|
||||
|
||||
SkMatrix44 asMatrix44() const override {
|
||||
SkASSERT(!this->hasInval());
|
||||
return fInverted;
|
||||
}
|
||||
|
||||
private:
|
||||
const sk_sp<Transform> fT;
|
||||
T fInverted;
|
||||
|
||||
using INHERITED = Transform;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Transform nodes don't generate damage on their own, but via ancestor TransformEffects.
|
||||
@ -79,6 +127,16 @@ sk_sp<Transform> Transform::MakeConcat(sk_sp<Transform> a, sk_sp<Transform> b) {
|
||||
: sk_sp<Transform>(new Concat<SkMatrix >(std::move(a), std::move(b)));
|
||||
}
|
||||
|
||||
sk_sp<Transform> Transform::MakeInverse(sk_sp<Transform> t) {
|
||||
if (!t) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return TransformPriv::Is44(t)
|
||||
? sk_sp<Transform>(new Inverse<SkMatrix44>(std::move(t)))
|
||||
: sk_sp<Transform>(new Inverse<SkMatrix >(std::move(t)));
|
||||
}
|
||||
|
||||
TransformEffect::TransformEffect(sk_sp<RenderNode> child, sk_sp<Transform> transform)
|
||||
: INHERITED(std::move(child))
|
||||
, fTransform(std::move(transform)) {
|
||||
|
Loading…
Reference in New Issue
Block a user