Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 2b024cb

Browse files
authored
[Impeller Scene] Change how property resolution works to fix Animation blending; add mutation log to nodes; enable backface culling; add vertex color contribution back to meshes (#38766)
* [Impeller Scene] Add mutation log to nodes * Apply the bind pose matrix when the skin is initialized * Refactor property resolver to modify decomposed properties * Make the property resolvers additive again to support complex blending * Normalize clip weights * Fix UI-side animation bugs and add looping config * Backface culling * Make dart analyzer happy * Incorporate vertex colors for imported meshes again * Address comments
1 parent 24eb954 commit 2b024cb

22 files changed

+416
-93
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,7 @@ ORIGIN: ../../../flutter/impeller/scene/animation/animation_clip.cc + ../../../f
16411641
ORIGIN: ../../../flutter/impeller/scene/animation/animation_clip.h + ../../../flutter/LICENSE
16421642
ORIGIN: ../../../flutter/impeller/scene/animation/animation_player.cc + ../../../flutter/LICENSE
16431643
ORIGIN: ../../../flutter/impeller/scene/animation/animation_player.h + ../../../flutter/LICENSE
1644+
ORIGIN: ../../../flutter/impeller/scene/animation/animation_transforms.h + ../../../flutter/LICENSE
16441645
ORIGIN: ../../../flutter/impeller/scene/animation/property_resolver.cc + ../../../flutter/LICENSE
16451646
ORIGIN: ../../../flutter/impeller/scene/animation/property_resolver.h + ../../../flutter/LICENSE
16461647
ORIGIN: ../../../flutter/impeller/scene/camera.cc + ../../../flutter/LICENSE
@@ -4121,6 +4122,7 @@ FILE: ../../../flutter/impeller/scene/animation/animation_clip.cc
41214122
FILE: ../../../flutter/impeller/scene/animation/animation_clip.h
41224123
FILE: ../../../flutter/impeller/scene/animation/animation_player.cc
41234124
FILE: ../../../flutter/impeller/scene/animation/animation_player.h
4125+
FILE: ../../../flutter/impeller/scene/animation/animation_transforms.h
41244126
FILE: ../../../flutter/impeller/scene/animation/property_resolver.cc
41254127
FILE: ../../../flutter/impeller/scene/animation/property_resolver.h
41264128
FILE: ../../../flutter/impeller/scene/camera.cc

impeller/geometry/quaternion.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ struct Quaternion {
4545
return {x * m, y * m, z * m, w * m};
4646
}
4747

48+
Quaternion Invert() const { return {-x, -y, -z, w}; }
49+
4850
Quaternion Slerp(const Quaternion& to, double time) const;
4951

5052
Quaternion operator*(const Quaternion& o) const {

impeller/scene/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ impeller_component("scene") {
1212
"animation/animation_clip.h",
1313
"animation/animation_player.cc",
1414
"animation/animation_player.h",
15+
"animation/animation_transforms.h",
1516
"animation/property_resolver.cc",
1617
"animation/property_resolver.h",
1718
"camera.cc",

impeller/scene/animation/animation_clip.cc

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Scalar AnimationClip::GetWeight() const {
6767
}
6868

6969
void AnimationClip::SetWeight(Scalar weight) {
70-
weight_ = weight;
70+
weight_ = std::max(0.0f, weight);
7171
}
7272

7373
SecondsF AnimationClip::GetPlaybackTime() const {
@@ -110,9 +110,16 @@ void AnimationClip::Advance(SecondsF delta_time) {
110110
}
111111
}
112112

113-
void AnimationClip::ApplyToBindings() const {
113+
void AnimationClip::ApplyToBindings(
114+
std::unordered_map<Node*, AnimationTransforms>& transform_decomps,
115+
Scalar weight_multiplier) const {
114116
for (auto& binding : bindings_) {
115-
binding.channel.resolver->Apply(*binding.node, playback_time_, weight_);
117+
auto transforms = transform_decomps.find(binding.node);
118+
if (transforms == transform_decomps.end()) {
119+
continue;
120+
}
121+
binding.channel.resolver->Apply(transforms->second, playback_time_,
122+
weight_ * weight_multiplier);
116123
}
117124
}
118125

impeller/scene/animation/animation_clip.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "flutter/fml/macros.h"
1111
#include "impeller/scene/animation/animation.h"
12+
#include "impeller/scene/animation/animation_transforms.h"
1213

1314
namespace impeller {
1415
namespace scene {
@@ -60,7 +61,9 @@ class AnimationClip final {
6061
void Advance(SecondsF delta_time);
6162

6263
/// @brief Applies the animation to all binded properties in the scene.
63-
void ApplyToBindings() const;
64+
void ApplyToBindings(
65+
std::unordered_map<Node*, AnimationTransforms>& transform_decomps,
66+
Scalar weight_multiplier) const;
6467

6568
private:
6669
void BindToTarget(Node* node);

impeller/scene/animation/animation_player.cc

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "impeller/scene/animation/animation_player.h"
66

77
#include <memory>
8+
#include <unordered_map>
89

910
#include "flutter/fml/time/time_point.h"
1011
#include "impeller/base/timing.h"
@@ -19,20 +20,37 @@ AnimationPlayer::~AnimationPlayer() = default;
1920
AnimationPlayer::AnimationPlayer(AnimationPlayer&&) = default;
2021
AnimationPlayer& AnimationPlayer::operator=(AnimationPlayer&&) = default;
2122

22-
AnimationClip& AnimationPlayer::AddAnimation(
23-
std::shared_ptr<Animation> animation,
23+
AnimationClip* AnimationPlayer::AddAnimation(
24+
const std::shared_ptr<Animation>& animation,
2425
Node* bind_target) {
25-
AnimationClip clip(std::move(animation), bind_target);
26+
if (!animation) {
27+
VALIDATION_LOG << "Cannot add null animation.";
28+
return nullptr;
29+
}
30+
31+
AnimationClip clip(animation, bind_target);
2632

2733
// Record all of the unique default transforms that this AnimationClip
2834
// will mutate.
2935
for (const auto& binding : clip.bindings_) {
30-
default_target_transforms_.insert(
31-
{binding.node, binding.node->GetLocalTransform()});
36+
auto decomp = binding.node->GetLocalTransform().Decompose();
37+
if (!decomp.has_value()) {
38+
continue;
39+
}
40+
target_transforms_.insert(
41+
{binding.node, AnimationTransforms{.bind_pose = decomp.value()}});
3242
}
3343

34-
clips_.push_back(std::move(clip));
35-
return clips_.back();
44+
auto result = clips_.insert({animation->GetName(), std::move(clip)});
45+
return &result.first->second;
46+
}
47+
48+
AnimationClip* AnimationPlayer::GetClip(const std::string& name) const {
49+
auto result = clips_.find(name);
50+
if (result == clips_.end()) {
51+
return nullptr;
52+
}
53+
return const_cast<AnimationClip*>(&result->second);
3654
}
3755

3856
void AnimationPlayer::Update() {
@@ -43,18 +61,27 @@ void AnimationPlayer::Update() {
4361
auto delta_time = new_time - previous_time_.value();
4462
previous_time_ = new_time;
4563

46-
Reset();
64+
// Reset the animated pose state.
65+
for (auto& [node, transforms] : target_transforms_) {
66+
transforms.animated_pose = transforms.bind_pose;
67+
}
68+
69+
// Compute a weight multiplier for normalizing the animation.
70+
Scalar total_weight = 0;
71+
for (auto& [_, clip] : clips_) {
72+
total_weight += clip.GetWeight();
73+
}
74+
Scalar weight_multiplier = total_weight > 1 ? 1 / total_weight : 1;
4775

48-
// Update and apply all clips.
49-
for (auto& clip : clips_) {
76+
// Update and apply all clips to the animation pose state.
77+
for (auto& [_, clip] : clips_) {
5078
clip.Advance(delta_time);
51-
clip.ApplyToBindings();
79+
clip.ApplyToBindings(target_transforms_, weight_multiplier);
5280
}
53-
}
5481

55-
void AnimationPlayer::Reset() {
56-
for (auto& [node, transform] : default_target_transforms_) {
57-
node->SetLocalTransform(Matrix());
82+
// Apply the animated pose to the bound joints.
83+
for (auto& [node, transforms] : target_transforms_) {
84+
node->SetLocalTransform(Matrix(transforms.animated_pose));
5885
}
5986
}
6087

impeller/scene/animation/animation_player.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@
44

55
#pragma once
66

7+
#include <map>
78
#include <memory>
89
#include <optional>
9-
#include <unordered_map>
1010
#include <vector>
1111

1212
#include "flutter/fml/hash_combine.h"
1313
#include "flutter/fml/macros.h"
1414
#include "flutter/fml/time/time_delta.h"
1515
#include "impeller/base/timing.h"
1616
#include "impeller/geometry/matrix.h"
17+
#include "impeller/geometry/matrix_decomposition.h"
1718
#include "impeller/scene/animation/animation_clip.h"
1819

1920
namespace impeller {
@@ -29,19 +30,18 @@ class AnimationPlayer final {
2930
AnimationPlayer(AnimationPlayer&&);
3031
AnimationPlayer& operator=(AnimationPlayer&&);
3132

32-
AnimationClip& AddAnimation(std::shared_ptr<Animation> animation,
33+
AnimationClip* AddAnimation(const std::shared_ptr<Animation>& animation,
3334
Node* bind_target);
3435

36+
AnimationClip* GetClip(const std::string& name) const;
37+
3538
/// @brief Advanced all clips and updates animated properties in the scene.
3639
void Update();
3740

38-
/// @brief Reset all bound animation target transforms.
39-
void Reset();
40-
4141
private:
42-
std::unordered_map<Node*, Matrix> default_target_transforms_;
42+
std::unordered_map<Node*, AnimationTransforms> target_transforms_;
4343

44-
std::vector<AnimationClip> clips_;
44+
std::map<std::string, AnimationClip> clips_;
4545

4646
std::optional<TimePoint> previous_time_;
4747

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
#pragma once
6+
7+
#include "impeller/geometry/matrix_decomposition.h"
8+
9+
namespace impeller {
10+
namespace scene {
11+
12+
struct AnimationTransforms {
13+
MatrixDecomposition bind_pose;
14+
MatrixDecomposition animated_pose;
15+
};
16+
17+
} // namespace scene
18+
} // namespace impeller

impeller/scene/animation/property_resolver.cc

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <iterator>
99
#include <memory>
1010

11+
#include "impeller/geometry/matrix_decomposition.h"
1112
#include "impeller/geometry/point.h"
1213
#include "impeller/scene/node.h"
1314

@@ -78,7 +79,7 @@ TranslationTimelineResolver::TranslationTimelineResolver() = default;
7879

7980
TranslationTimelineResolver::~TranslationTimelineResolver() = default;
8081

81-
void TranslationTimelineResolver::Apply(Node& target,
82+
void TranslationTimelineResolver::Apply(AnimationTransforms& target,
8283
SecondsF time,
8384
Scalar weight) {
8485
if (values_.empty()) {
@@ -89,15 +90,16 @@ void TranslationTimelineResolver::Apply(Node& target,
8990
if (key.lerp < 1) {
9091
value = values_[key.index - 1].Lerp(value, key.lerp);
9192
}
92-
target.SetLocalTransform(target.GetLocalTransform() *
93-
Matrix::MakeTranslation(value * weight));
93+
94+
target.animated_pose.translation +=
95+
(value - target.bind_pose.translation) * weight;
9496
}
9597

9698
RotationTimelineResolver::RotationTimelineResolver() = default;
9799

98100
RotationTimelineResolver::~RotationTimelineResolver() = default;
99101

100-
void RotationTimelineResolver::Apply(Node& target,
102+
void RotationTimelineResolver::Apply(AnimationTransforms& target,
101103
SecondsF time,
102104
Scalar weight) {
103105
if (values_.empty()) {
@@ -108,15 +110,19 @@ void RotationTimelineResolver::Apply(Node& target,
108110
if (key.lerp < 1) {
109111
value = values_[key.index - 1].Slerp(value, key.lerp);
110112
}
111-
target.SetLocalTransform(target.GetLocalTransform() *
112-
Matrix::MakeRotation(value * weight));
113+
114+
target.animated_pose.rotation =
115+
target.animated_pose.rotation *
116+
Quaternion().Slerp(target.bind_pose.rotation.Invert() * value, weight);
113117
}
114118

115119
ScaleTimelineResolver::ScaleTimelineResolver() = default;
116120

117121
ScaleTimelineResolver::~ScaleTimelineResolver() = default;
118122

119-
void ScaleTimelineResolver::Apply(Node& target, SecondsF time, Scalar weight) {
123+
void ScaleTimelineResolver::Apply(AnimationTransforms& target,
124+
SecondsF time,
125+
Scalar weight) {
120126
if (values_.empty()) {
121127
return;
122128
}
@@ -125,8 +131,9 @@ void ScaleTimelineResolver::Apply(Node& target, SecondsF time, Scalar weight) {
125131
if (key.lerp < 1) {
126132
value = values_[key.index - 1].Lerp(value, key.lerp);
127133
}
128-
target.SetLocalTransform(target.GetLocalTransform() *
129-
Matrix::MakeScale(value * weight));
134+
135+
target.animated_pose.scale *=
136+
Vector3(1, 1, 1).Lerp(value / target.bind_pose.scale, weight);
130137
}
131138

132139
} // namespace scene

impeller/scene/animation/property_resolver.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
#include "flutter/fml/hash_combine.h"
1212
#include "flutter/fml/macros.h"
1313
#include "impeller/base/timing.h"
14+
#include "impeller/geometry/matrix_decomposition.h"
1415
#include "impeller/geometry/quaternion.h"
1516
#include "impeller/geometry/scalar.h"
1617
#include "impeller/geometry/vector.h"
18+
#include "impeller/scene/animation/animation_transforms.h"
1719

1820
namespace impeller {
1921
namespace scene {
@@ -46,7 +48,9 @@ class PropertyResolver {
4648
/// many different PropertyResolvers prior to rendering. For example,
4749
/// an AnimationPlayer may blend multiple Animations together by
4850
/// applying several AnimationClips.
49-
virtual void Apply(Node& target, SecondsF time, Scalar weight) = 0;
51+
virtual void Apply(AnimationTransforms& target,
52+
SecondsF time,
53+
Scalar weight) = 0;
5054
};
5155

5256
class TimelineResolver : public PropertyResolver {
@@ -74,7 +78,9 @@ class TranslationTimelineResolver final : public TimelineResolver {
7478
~TranslationTimelineResolver();
7579

7680
// |Resolver|
77-
void Apply(Node& target, SecondsF time, Scalar weight) override;
81+
void Apply(AnimationTransforms& target,
82+
SecondsF time,
83+
Scalar weight) override;
7884

7985
private:
8086
TranslationTimelineResolver();
@@ -91,7 +97,9 @@ class RotationTimelineResolver final : public TimelineResolver {
9197
~RotationTimelineResolver();
9298

9399
// |Resolver|
94-
void Apply(Node& target, SecondsF time, Scalar weight) override;
100+
void Apply(AnimationTransforms& target,
101+
SecondsF time,
102+
Scalar weight) override;
95103

96104
private:
97105
RotationTimelineResolver();
@@ -108,7 +116,9 @@ class ScaleTimelineResolver final : public TimelineResolver {
108116
~ScaleTimelineResolver();
109117

110118
// |Resolver|
111-
void Apply(Node& target, SecondsF time, Scalar weight) override;
119+
void Apply(AnimationTransforms& target,
120+
SecondsF time,
121+
Scalar weight) override;
112122

113123
private:
114124
ScaleTimelineResolver();

impeller/scene/geometry.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ std::shared_ptr<Geometry> Geometry::MakeFromFlatbuffer(
9595
}
9696

9797
DeviceBufferDescriptor buffer_desc;
98-
buffer_desc.size = vertices_bytes * indices_bytes;
98+
buffer_desc.size = vertices_bytes + indices_bytes;
9999
buffer_desc.storage_mode = StorageMode::kHostVisible;
100100

101101
auto buffer = allocator.CreateBuffer(buffer_desc);

impeller/scene/material.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,11 @@ std::unique_ptr<UnlitMaterial> UnlitMaterial::MakeFromFlatbuffer(
8181

8282
if (material.base_color_factor()) {
8383
result->SetColor(importer::ToColor(*material.base_color_factor()));
84-
result->SetVertexColorWeight(0);
8584
}
8685

8786
if (material.base_color_texture() >= 0 &&
8887
material.base_color_texture() < static_cast<int32_t>(textures.size())) {
8988
result->SetColorTexture(textures[material.base_color_texture()]);
90-
result->SetVertexColorWeight(0);
9189
}
9290

9391
return result;

0 commit comments

Comments
 (0)