| Flutter Impeller |

skin.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/scene/skin.h"
6
7 #include <cmath>
8 #include <memory>
9 #include <optional>
10 #include <vector>
11
12 #include "flutter/fml/logging.h"
13 #include "impeller/core/allocator.h"
14 #include "impeller/scene/importer/conversions.h"
15
16 namespace impeller {
17 namespace scene {
18
19 std::unique_ptr<Skin> Skin::MakeFromFlatbuffer(
20 const fb::Skin& skin,
21 const std::vector<std::shared_ptr<Node>>& scene_nodes) {
22 if (!skin.joints() || !skin.inverse_bind_matrices() ||
23 skin.joints()->size() != skin.inverse_bind_matrices()->size()) {
24 VALIDATION_LOG << "Skin data is missing joints or bind matrices.";
25 return nullptr;
26 }
27
28 Skin result;
29
30 result.joints_.reserve(skin.joints()->size());
31 for (auto joint : *skin.joints()) {
32 if (joint < 0 || static_cast<size_t>(joint) > scene_nodes.size()) {
33 VALIDATION_LOG << "Skin joint index out of range.";
34 result.joints_.push_back(nullptr);
35 continue;
36 }
37 if (scene_nodes[joint]) {
38 scene_nodes[joint]->SetIsJoint(true);
39 }
40 result.joints_.push_back(scene_nodes[joint]);
41 }
42
43 result.inverse_bind_matrices_.reserve(skin.inverse_bind_matrices()->size());
44 for (size_t matrix_i = 0; matrix_i < skin.inverse_bind_matrices()->size();
45 matrix_i++) {
46 const auto* ip_matrix = skin.inverse_bind_matrices()->Get(matrix_i);
47 Matrix matrix = ip_matrix ? importer::ToMatrix(*ip_matrix) : Matrix();
48
49 result.inverse_bind_matrices_.push_back(matrix);
50 // Overwrite the joint transforms with the inverse bind pose.
51 result.joints_[matrix_i]->SetGlobalTransform(matrix.Invert());
52 }
53
54 return std::make_unique<Skin>(std::move(result));
55 }
56
57 Skin::Skin() = default;
58
59 Skin::~Skin() = default;
60
61 Skin::Skin(Skin&&) = default;
62
63 Skin& Skin::operator=(Skin&&) = default;
64
65 std::shared_ptr<Texture> Skin::GetJointsTexture(Allocator& allocator) {
66 // Each joint has a matrix. 1 matrix = 16 floats. 1 pixel = 4 floats.
67 // Therefore, each joint needs 4 pixels.
68 auto required_pixels = joints_.size() * 4;
69 auto dimension_size = std::max(
70 2u,
71 Allocation::NextPowerOfTwoSize(std::ceil(std::sqrt(required_pixels))));
72
73 impeller::TextureDescriptor texture_descriptor;
74 texture_descriptor.storage_mode = impeller::StorageMode::kHostVisible;
75 texture_descriptor.format = PixelFormat::kR32G32B32A32Float;
76 texture_descriptor.size = {dimension_size, dimension_size};
77 texture_descriptor.mip_count = 1u;
78
79 auto result = allocator.CreateTexture(texture_descriptor);
80 result->SetLabel("Joints Texture");
81 if (!result) {
82 FML_LOG(ERROR) << "Could not create joint texture.";
83 return nullptr;
84 }
85
86 std::vector<Matrix> joints;
87 joints.resize(result->GetSize().Area() / 4, Matrix());
88 FML_DCHECK(joints.size() >= joints_.size());
89 for (size_t joint_i = 0; joint_i < joints_.size(); joint_i++) {
90 const Node* joint = joints_[joint_i].get();
91 if (!joint) {
92 // When a joint is missing, just let it remain as an identity matrix.
93 continue;
94 }
95
96 // Compute a model space matrix for the joint by walking up the bones to the
97 // skeleton root.
98 while (joint && joint->IsJoint()) {
99 joints[joint_i] = joint->GetLocalTransform() * joints[joint_i];
100 joint = joint->GetParent();
101 }
102
103 // Get the joint transform relative to the default pose of the bone by
104 // incorporating the joint's inverse bind matrix. The inverse bind matrix
105 // transforms from model space to the default pose space of the joint. The
106 // result is a model space matrix that only captures the difference between
107 // the joint's default pose and the joint's current pose in the scene. This
108 // is necessary because the skinned model's vertex positions (which _define_
109 // the default pose) are all in model space.
110 joints[joint_i] = joints[joint_i] * inverse_bind_matrices_[joint_i];
111 }
112
113 if (!result->SetContents(reinterpret_cast<uint8_t*>(joints.data()),
114 joints.size() * sizeof(Matrix))) {
115 FML_LOG(ERROR) << "Could not set contents of joint texture.";
116 return nullptr;
117 }
118
119 return result;
120 }
121
122 } // namespace scene
123 } // namespace impeller
impeller::scene::Node::GetLocalTransform
Matrix GetLocalTransform() const
Definition: node.cc:292
impeller::scene::Node::GetParent
Node * GetParent() const
Definition: node.cc:250
impeller::Allocation::NextPowerOfTwoSize
static uint32_t NextPowerOfTwoSize(uint32_t x)
Definition: allocation.cc:41
impeller::TextureDescriptor::format
PixelFormat format
Definition: texture_descriptor.h:40
impeller::TextureDescriptor::mip_count
size_t mip_count
Definition: texture_descriptor.h:42
impeller::scene::Skin::MakeFromFlatbuffer
static std::unique_ptr< Skin > MakeFromFlatbuffer(const fb::Skin &skin, const std::vector< std::shared_ptr< Node >> &scene_nodes)
Definition: skin.cc:19
impeller::scene::Skin::~Skin
~Skin()
impeller::StorageMode::kHostVisible
@ kHostVisible
impeller::Allocator::CreateTexture
std::shared_ptr< Texture > CreateTexture(const TextureDescriptor &desc)
Definition: allocator.cc:49
conversions.h
impeller::Allocator
An object that allocates device memory.
Definition: allocator.h:22
impeller::scene::Skin
Definition: skin.h:21
impeller::PixelFormat::kR32G32B32A32Float
@ kR32G32B32A32Float
impeller::Matrix::Invert
Matrix Invert() const
Definition: matrix.cc:97
impeller::TextureDescriptor::size
ISize size
Definition: texture_descriptor.h:41
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:67
allocator.h
impeller::scene::Skin::operator=
Skin & operator=(Skin &&)
impeller::scene::Node::IsJoint
bool IsJoint() const
Definition: node.cc:351
impeller::scene::Node
Definition: node.h:30
impeller::scene::Skin::GetJointsTexture
std::shared_ptr< Texture > GetJointsTexture(Allocator &allocator)
Definition: skin.cc:65
impeller::TextureDescriptor::storage_mode
StorageMode storage_mode
Definition: texture_descriptor.h:38
impeller::TextureDescriptor
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...
Definition: texture_descriptor.h:37
impeller
Definition: aiks_context.cc:10
skin.h
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::scene::importer::ToMatrix
Matrix ToMatrix(const std::vector< double > &m)
Definition: conversions.cc:15