• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "modules/skottie/src/Camera.h"
9 
10 #include "modules/skottie/src/SkottieJson.h"
11 #include "modules/skottie/src/SkottiePriv.h"
12 #include "modules/sksg/include/SkSGTransform.h"
13 
14 namespace skottie {
15 namespace internal {
16 
17 namespace  {
18 
ComputeCameraMatrix(const SkV3 & position,const SkV3 & poi,const SkV3 & rotation,const SkSize & viewport_size,float zoom)19 SkM44 ComputeCameraMatrix(const SkV3& position,
20                           const SkV3& poi,
21                           const SkV3& rotation,
22                           const SkSize& viewport_size,
23                           float zoom) {
24 
25     // Initial camera vector.
26     const auto cam_t = SkM44::Rotate({0, 0, 1}, SkDegreesToRadians(-rotation.z))
27                      * SkM44::Rotate({0, 1, 0}, SkDegreesToRadians( rotation.y))
28                      * SkM44::Rotate({1, 0, 0}, SkDegreesToRadians( rotation.x))
29                      * SkM44::LookAt({ position.x, position.y, -position.z },
30                                      {      poi.x,      poi.y,       poi.z },
31                                      {          0,          1,           0 })
32                      * SkM44::Scale(1, 1, -1);
33 
34     // View parameters:
35     //
36     //   * size     -> composition size (TODO: AE seems to base it on width only?)
37     //   * distance -> "zoom" camera attribute
38     //
39     const auto view_size     = std::max(viewport_size.width(), viewport_size.height()),
40                view_distance = zoom,
41                view_angle    = std::atan(sk_ieee_float_divide(view_size * 0.5f, view_distance));
42 
43     const auto persp_t = SkM44::Scale(view_size * 0.5f, view_size * 0.5f, 1)
44                        * SkM44::Perspective(0, view_distance, 2 * view_angle);
45 
46     return SkM44::Translate(viewport_size.width()  * 0.5f,
47                             viewport_size.height() * 0.5f,
48                             0)
49            * persp_t * cam_t;
50 }
51 
52 } // namespace
53 
CameraAdaper(const skjson::ObjectValue & jlayer,const skjson::ObjectValue & jtransform,const AnimationBuilder & abuilder,const SkSize & viewport_size)54 CameraAdaper::CameraAdaper(const skjson::ObjectValue& jlayer,
55                            const skjson::ObjectValue& jtransform,
56                            const AnimationBuilder& abuilder,
57                            const SkSize& viewport_size)
58     : INHERITED(jtransform, abuilder)
59     , fViewportSize(viewport_size)
60     // The presence of an anchor point property ('a') differentiates
61     // one-node vs. two-node cameras.
62     , fType(jtransform["a"].is<skjson::NullValue>() ? CameraType::kOneNode
63                                                     : CameraType::kTwoNode) {
64     // 'pe' (perspective?) corresponds to AE's "zoom" camera property.
65     this->bind(abuilder, jlayer["pe"], fZoom);
66 }
67 
68 CameraAdaper::~CameraAdaper() = default;
69 
totalMatrix() const70 SkM44 CameraAdaper::totalMatrix() const {
71     // Camera parameters:
72     //
73     //   * location          -> position attribute
74     //   * point of interest -> anchor point attribute (two-node camera only)
75     //   * orientation       -> rotation attribute
76     //
77     const auto position = this->position();
78 
79     return ComputeCameraMatrix(position,
80                                this->poi(position),
81                                this->rotation(),
82                                fViewportSize,
83                                fZoom);
84 }
85 
poi(const SkV3 & pos) const86 SkV3 CameraAdaper::poi(const SkV3& pos) const {
87     // AE supports two camera types:
88     //
89     //   - one-node camera: does not auto-orient, and starts off perpendicular
90     //     to the z = 0 plane, facing "forward" (decreasing z).
91     //
92     //   - two-node camera: has a point of interest (encoded as the anchor point),
93     //     and auto-orients to point in its direction.
94 
95     if (fType == CameraType::kOneNode) {
96         return { pos.x, pos.y, -pos.z - 1};
97     }
98 
99     const auto ap = this->anchor_point();
100 
101     return { ap.x, ap.y, -ap.z };
102 }
103 
DefaultCameraTransform(const SkSize & viewport_size)104 sk_sp<sksg::Transform> CameraAdaper::DefaultCameraTransform(const SkSize& viewport_size) {
105     const auto center = SkVector::Make(viewport_size.width()  * 0.5f,
106                                        viewport_size.height() * 0.5f);
107 
108     static constexpr float kDefaultAEZoom = 879.13f;
109 
110     const SkV3 pos = { center.fX, center.fY, -kDefaultAEZoom },
111                poi = {     pos.x,     pos.y,      -pos.z - 1 },
112                rot = {         0,         0,               0 };
113 
114     return sksg::Matrix<SkM44>::Make(
115                 ComputeCameraMatrix(pos, poi, rot, viewport_size, kDefaultAEZoom));
116 }
117 
attachCamera(const skjson::ObjectValue & jlayer,const skjson::ObjectValue & jtransform,sk_sp<sksg::Transform> parent,const SkSize & viewport_size) const118 sk_sp<sksg::Transform> AnimationBuilder::attachCamera(const skjson::ObjectValue& jlayer,
119                                                       const skjson::ObjectValue& jtransform,
120                                                       sk_sp<sksg::Transform> parent,
121                                                       const SkSize& viewport_size) const {
122     auto adapter = sk_make_sp<CameraAdaper>(jlayer, jtransform, *this, viewport_size);
123 
124     if (adapter->isStatic()) {
125         adapter->seek(0);
126     } else {
127         fCurrentAnimatorScope->push_back(adapter);
128     }
129 
130     return sksg::Transform::MakeConcat(adapter->node(), std::move(parent));
131 }
132 
133 } // namespace internal
134 } // namespace skottie
135