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 <vector>
10 
11 #include "flutter/fml/logging.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;
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:282
impeller::scene::Node::GetParent
Node * GetParent() const
Definition: node.cc:240
allocation.h
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:73
allocator.h
impeller::scene::Skin::operator=
Skin & operator=(Skin &&)
impeller::scene::Node::IsJoint
bool IsJoint() const
Definition: node.cc:341
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_blur_unittests.cc:20
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