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 14namespace skottie { 15namespace internal { 16 17namespace { 18 19SkM44 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 54CameraAdaper::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 68CameraAdaper::~CameraAdaper() = default; 69 70SkM44 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 86SkV3 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 104sk_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 118sk_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