/src/skia/modules/skottie/src/Camera.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
19 | | SkM44 ComputeCameraMatrix(const SkV3& position, |
20 | | const SkV3& poi, |
21 | | const SkV3& rotation, |
22 | | const SkSize& viewport_size, |
23 | 2.85k | float zoom) { |
24 | | |
25 | | // Initial camera vector. |
26 | 2.85k | const auto cam_t = SkM44::Rotate({0, 0, 1}, SkDegreesToRadians(-rotation.z)) |
27 | 2.85k | * SkM44::Rotate({0, 1, 0}, SkDegreesToRadians( rotation.y)) |
28 | 2.85k | * SkM44::Rotate({1, 0, 0}, SkDegreesToRadians( rotation.x)) |
29 | 2.85k | * SkM44::LookAt({ position.x, position.y, -position.z }, |
30 | 2.85k | { poi.x, poi.y, poi.z }, |
31 | 2.85k | { 0, 1, 0 }) |
32 | 2.85k | * 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 | 2.85k | const auto view_size = std::max(viewport_size.width(), viewport_size.height()), |
40 | 2.85k | view_distance = zoom, |
41 | 2.85k | view_angle = std::atan(sk_ieee_float_divide(view_size * 0.5f, view_distance)); |
42 | | |
43 | 2.85k | const auto persp_t = SkM44::Scale(view_size * 0.5f, view_size * 0.5f, 1) |
44 | 2.85k | * SkM44::Perspective(0, view_distance, 2 * view_angle); |
45 | | |
46 | 2.85k | return SkM44::Translate(viewport_size.width() * 0.5f, |
47 | 2.85k | viewport_size.height() * 0.5f, |
48 | 2.85k | 0) |
49 | 2.85k | * persp_t * cam_t; |
50 | 2.85k | } |
51 | | |
52 | | } // namespace |
53 | | |
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 | 1.62k | : CameraType::kTwoNode) { |
64 | | // 'pe' (perspective?) corresponds to AE's "zoom" camera property. |
65 | 1.62k | this->bind(abuilder, jlayer["pe"], fZoom); |
66 | 1.62k | } |
67 | | |
68 | 1.62k | CameraAdaper::~CameraAdaper() = default; |
69 | | |
70 | 1.62k | 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 | 1.62k | const auto position = this->position(); |
78 | | |
79 | 1.62k | return ComputeCameraMatrix(position, |
80 | 1.62k | this->poi(position), |
81 | 1.62k | this->rotation(), |
82 | 1.62k | fViewportSize, |
83 | 1.62k | fZoom); |
84 | 1.62k | } |
85 | | |
86 | 1.62k | 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 | 1.62k | if (fType == CameraType::kOneNode) { |
96 | 1.16k | return { pos.x, pos.y, -pos.z - 1}; |
97 | 1.16k | } |
98 | | |
99 | 459 | const auto ap = this->anchor_point(); |
100 | | |
101 | 459 | return { ap.x, ap.y, -ap.z }; |
102 | 459 | } |
103 | | |
104 | 1.23k | sk_sp<sksg::Transform> CameraAdaper::DefaultCameraTransform(const SkSize& viewport_size) { |
105 | 1.23k | const auto center = SkVector::Make(viewport_size.width() * 0.5f, |
106 | 1.23k | viewport_size.height() * 0.5f); |
107 | | |
108 | 1.23k | static constexpr float kDefaultAEZoom = 879.13f; |
109 | | |
110 | 1.23k | const SkV3 pos = { center.fX, center.fY, -kDefaultAEZoom }, |
111 | 1.23k | poi = { pos.x, pos.y, -pos.z - 1 }, |
112 | 1.23k | rot = { 0, 0, 0 }; |
113 | | |
114 | 1.23k | return sksg::Matrix<SkM44>::Make( |
115 | 1.23k | ComputeCameraMatrix(pos, poi, rot, viewport_size, kDefaultAEZoom)); |
116 | 1.23k | } |
117 | | |
118 | | sk_sp<sksg::Transform> AnimationBuilder::attachCamera(const skjson::ObjectValue& jlayer, |
119 | | const skjson::ObjectValue& jtransform, |
120 | | sk_sp<sksg::Transform> parent, |
121 | 1.62k | const SkSize& viewport_size) const { |
122 | 1.62k | auto adapter = sk_make_sp<CameraAdaper>(jlayer, jtransform, *this, viewport_size); |
123 | | |
124 | 1.62k | if (adapter->isStatic()) { |
125 | 1.62k | adapter->seek(0); |
126 | 0 | } else { |
127 | 0 | fCurrentAnimatorScope->push_back(adapter); |
128 | 0 | } |
129 | | |
130 | 1.62k | return sksg::Transform::MakeConcat(adapter->node(), std::move(parent)); |
131 | 1.62k | } |
132 | | |
133 | | } // namespace internal |
134 | | } // namespace skottie |