Skip to content

Commit

Permalink
[Impeller Scene] Change how property resolution works to fix Animatio…
Browse files Browse the repository at this point in the history
…n 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
  • Loading branch information
bdero authored Jan 12, 2023
1 parent 24eb954 commit 2b024cb
Show file tree
Hide file tree
Showing 22 changed files with 416 additions and 93 deletions.
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,7 @@ ORIGIN: ../../../flutter/impeller/scene/animation/animation_clip.cc + ../../../f
ORIGIN: ../../../flutter/impeller/scene/animation/animation_clip.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/animation/animation_player.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/animation/animation_player.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/animation/animation_transforms.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/animation/property_resolver.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/animation/property_resolver.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/scene/camera.cc + ../../../flutter/LICENSE
Expand Down Expand Up @@ -4121,6 +4122,7 @@ FILE: ../../../flutter/impeller/scene/animation/animation_clip.cc
FILE: ../../../flutter/impeller/scene/animation/animation_clip.h
FILE: ../../../flutter/impeller/scene/animation/animation_player.cc
FILE: ../../../flutter/impeller/scene/animation/animation_player.h
FILE: ../../../flutter/impeller/scene/animation/animation_transforms.h
FILE: ../../../flutter/impeller/scene/animation/property_resolver.cc
FILE: ../../../flutter/impeller/scene/animation/property_resolver.h
FILE: ../../../flutter/impeller/scene/camera.cc
Expand Down
2 changes: 2 additions & 0 deletions impeller/geometry/quaternion.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ struct Quaternion {
return {x * m, y * m, z * m, w * m};
}

Quaternion Invert() const { return {-x, -y, -z, w}; }

Quaternion Slerp(const Quaternion& to, double time) const;

Quaternion operator*(const Quaternion& o) const {
Expand Down
1 change: 1 addition & 0 deletions impeller/scene/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ impeller_component("scene") {
"animation/animation_clip.h",
"animation/animation_player.cc",
"animation/animation_player.h",
"animation/animation_transforms.h",
"animation/property_resolver.cc",
"animation/property_resolver.h",
"camera.cc",
Expand Down
13 changes: 10 additions & 3 deletions impeller/scene/animation/animation_clip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Scalar AnimationClip::GetWeight() const {
}

void AnimationClip::SetWeight(Scalar weight) {
weight_ = weight;
weight_ = std::max(0.0f, weight);
}

SecondsF AnimationClip::GetPlaybackTime() const {
Expand Down Expand Up @@ -110,9 +110,16 @@ void AnimationClip::Advance(SecondsF delta_time) {
}
}

void AnimationClip::ApplyToBindings() const {
void AnimationClip::ApplyToBindings(
std::unordered_map<Node*, AnimationTransforms>& transform_decomps,
Scalar weight_multiplier) const {
for (auto& binding : bindings_) {
binding.channel.resolver->Apply(*binding.node, playback_time_, weight_);
auto transforms = transform_decomps.find(binding.node);
if (transforms == transform_decomps.end()) {
continue;
}
binding.channel.resolver->Apply(transforms->second, playback_time_,
weight_ * weight_multiplier);
}
}

Expand Down
5 changes: 4 additions & 1 deletion impeller/scene/animation/animation_clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "flutter/fml/macros.h"
#include "impeller/scene/animation/animation.h"
#include "impeller/scene/animation/animation_transforms.h"

namespace impeller {
namespace scene {
Expand Down Expand Up @@ -60,7 +61,9 @@ class AnimationClip final {
void Advance(SecondsF delta_time);

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

private:
void BindToTarget(Node* node);
Expand Down
57 changes: 42 additions & 15 deletions impeller/scene/animation/animation_player.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "impeller/scene/animation/animation_player.h"

#include <memory>
#include <unordered_map>

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

AnimationClip& AnimationPlayer::AddAnimation(
std::shared_ptr<Animation> animation,
AnimationClip* AnimationPlayer::AddAnimation(
const std::shared_ptr<Animation>& animation,
Node* bind_target) {
AnimationClip clip(std::move(animation), bind_target);
if (!animation) {
VALIDATION_LOG << "Cannot add null animation.";
return nullptr;
}

AnimationClip clip(animation, bind_target);

// Record all of the unique default transforms that this AnimationClip
// will mutate.
for (const auto& binding : clip.bindings_) {
default_target_transforms_.insert(
{binding.node, binding.node->GetLocalTransform()});
auto decomp = binding.node->GetLocalTransform().Decompose();
if (!decomp.has_value()) {
continue;
}
target_transforms_.insert(
{binding.node, AnimationTransforms{.bind_pose = decomp.value()}});
}

clips_.push_back(std::move(clip));
return clips_.back();
auto result = clips_.insert({animation->GetName(), std::move(clip)});
return &result.first->second;
}

AnimationClip* AnimationPlayer::GetClip(const std::string& name) const {
auto result = clips_.find(name);
if (result == clips_.end()) {
return nullptr;
}
return const_cast<AnimationClip*>(&result->second);
}

void AnimationPlayer::Update() {
Expand All @@ -43,18 +61,27 @@ void AnimationPlayer::Update() {
auto delta_time = new_time - previous_time_.value();
previous_time_ = new_time;

Reset();
// Reset the animated pose state.
for (auto& [node, transforms] : target_transforms_) {
transforms.animated_pose = transforms.bind_pose;
}

// Compute a weight multiplier for normalizing the animation.
Scalar total_weight = 0;
for (auto& [_, clip] : clips_) {
total_weight += clip.GetWeight();
}
Scalar weight_multiplier = total_weight > 1 ? 1 / total_weight : 1;

// Update and apply all clips.
for (auto& clip : clips_) {
// Update and apply all clips to the animation pose state.
for (auto& [_, clip] : clips_) {
clip.Advance(delta_time);
clip.ApplyToBindings();
clip.ApplyToBindings(target_transforms_, weight_multiplier);
}
}

void AnimationPlayer::Reset() {
for (auto& [node, transform] : default_target_transforms_) {
node->SetLocalTransform(Matrix());
// Apply the animated pose to the bound joints.
for (auto& [node, transforms] : target_transforms_) {
node->SetLocalTransform(Matrix(transforms.animated_pose));
}
}

Expand Down
14 changes: 7 additions & 7 deletions impeller/scene/animation/animation_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@

#pragma once

#include <map>
#include <memory>
#include <optional>
#include <unordered_map>
#include <vector>

#include "flutter/fml/hash_combine.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/time/time_delta.h"
#include "impeller/base/timing.h"
#include "impeller/geometry/matrix.h"
#include "impeller/geometry/matrix_decomposition.h"
#include "impeller/scene/animation/animation_clip.h"

namespace impeller {
Expand All @@ -29,19 +30,18 @@ class AnimationPlayer final {
AnimationPlayer(AnimationPlayer&&);
AnimationPlayer& operator=(AnimationPlayer&&);

AnimationClip& AddAnimation(std::shared_ptr<Animation> animation,
AnimationClip* AddAnimation(const std::shared_ptr<Animation>& animation,
Node* bind_target);

AnimationClip* GetClip(const std::string& name) const;

/// @brief Advanced all clips and updates animated properties in the scene.
void Update();

/// @brief Reset all bound animation target transforms.
void Reset();

private:
std::unordered_map<Node*, Matrix> default_target_transforms_;
std::unordered_map<Node*, AnimationTransforms> target_transforms_;

std::vector<AnimationClip> clips_;
std::map<std::string, AnimationClip> clips_;

std::optional<TimePoint> previous_time_;

Expand Down
18 changes: 18 additions & 0 deletions impeller/scene/animation/animation_transforms.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#pragma once

#include "impeller/geometry/matrix_decomposition.h"

namespace impeller {
namespace scene {

struct AnimationTransforms {
MatrixDecomposition bind_pose;
MatrixDecomposition animated_pose;
};

} // namespace scene
} // namespace impeller
25 changes: 16 additions & 9 deletions impeller/scene/animation/property_resolver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <iterator>
#include <memory>

#include "impeller/geometry/matrix_decomposition.h"
#include "impeller/geometry/point.h"
#include "impeller/scene/node.h"

Expand Down Expand Up @@ -78,7 +79,7 @@ TranslationTimelineResolver::TranslationTimelineResolver() = default;

TranslationTimelineResolver::~TranslationTimelineResolver() = default;

void TranslationTimelineResolver::Apply(Node& target,
void TranslationTimelineResolver::Apply(AnimationTransforms& target,
SecondsF time,
Scalar weight) {
if (values_.empty()) {
Expand All @@ -89,15 +90,16 @@ void TranslationTimelineResolver::Apply(Node& target,
if (key.lerp < 1) {
value = values_[key.index - 1].Lerp(value, key.lerp);
}
target.SetLocalTransform(target.GetLocalTransform() *
Matrix::MakeTranslation(value * weight));

target.animated_pose.translation +=
(value - target.bind_pose.translation) * weight;
}

RotationTimelineResolver::RotationTimelineResolver() = default;

RotationTimelineResolver::~RotationTimelineResolver() = default;

void RotationTimelineResolver::Apply(Node& target,
void RotationTimelineResolver::Apply(AnimationTransforms& target,
SecondsF time,
Scalar weight) {
if (values_.empty()) {
Expand All @@ -108,15 +110,19 @@ void RotationTimelineResolver::Apply(Node& target,
if (key.lerp < 1) {
value = values_[key.index - 1].Slerp(value, key.lerp);
}
target.SetLocalTransform(target.GetLocalTransform() *
Matrix::MakeRotation(value * weight));

target.animated_pose.rotation =
target.animated_pose.rotation *
Quaternion().Slerp(target.bind_pose.rotation.Invert() * value, weight);
}

ScaleTimelineResolver::ScaleTimelineResolver() = default;

ScaleTimelineResolver::~ScaleTimelineResolver() = default;

void ScaleTimelineResolver::Apply(Node& target, SecondsF time, Scalar weight) {
void ScaleTimelineResolver::Apply(AnimationTransforms& target,
SecondsF time,
Scalar weight) {
if (values_.empty()) {
return;
}
Expand All @@ -125,8 +131,9 @@ void ScaleTimelineResolver::Apply(Node& target, SecondsF time, Scalar weight) {
if (key.lerp < 1) {
value = values_[key.index - 1].Lerp(value, key.lerp);
}
target.SetLocalTransform(target.GetLocalTransform() *
Matrix::MakeScale(value * weight));

target.animated_pose.scale *=
Vector3(1, 1, 1).Lerp(value / target.bind_pose.scale, weight);
}

} // namespace scene
Expand Down
18 changes: 14 additions & 4 deletions impeller/scene/animation/property_resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
#include "flutter/fml/hash_combine.h"
#include "flutter/fml/macros.h"
#include "impeller/base/timing.h"
#include "impeller/geometry/matrix_decomposition.h"
#include "impeller/geometry/quaternion.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/vector.h"
#include "impeller/scene/animation/animation_transforms.h"

namespace impeller {
namespace scene {
Expand Down Expand Up @@ -46,7 +48,9 @@ class PropertyResolver {
/// many different PropertyResolvers prior to rendering. For example,
/// an AnimationPlayer may blend multiple Animations together by
/// applying several AnimationClips.
virtual void Apply(Node& target, SecondsF time, Scalar weight) = 0;
virtual void Apply(AnimationTransforms& target,
SecondsF time,
Scalar weight) = 0;
};

class TimelineResolver : public PropertyResolver {
Expand Down Expand Up @@ -74,7 +78,9 @@ class TranslationTimelineResolver final : public TimelineResolver {
~TranslationTimelineResolver();

// |Resolver|
void Apply(Node& target, SecondsF time, Scalar weight) override;
void Apply(AnimationTransforms& target,
SecondsF time,
Scalar weight) override;

private:
TranslationTimelineResolver();
Expand All @@ -91,7 +97,9 @@ class RotationTimelineResolver final : public TimelineResolver {
~RotationTimelineResolver();

// |Resolver|
void Apply(Node& target, SecondsF time, Scalar weight) override;
void Apply(AnimationTransforms& target,
SecondsF time,
Scalar weight) override;

private:
RotationTimelineResolver();
Expand All @@ -108,7 +116,9 @@ class ScaleTimelineResolver final : public TimelineResolver {
~ScaleTimelineResolver();

// |Resolver|
void Apply(Node& target, SecondsF time, Scalar weight) override;
void Apply(AnimationTransforms& target,
SecondsF time,
Scalar weight) override;

private:
ScaleTimelineResolver();
Expand Down
2 changes: 1 addition & 1 deletion impeller/scene/geometry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ std::shared_ptr<Geometry> Geometry::MakeFromFlatbuffer(
}

DeviceBufferDescriptor buffer_desc;
buffer_desc.size = vertices_bytes * indices_bytes;
buffer_desc.size = vertices_bytes + indices_bytes;
buffer_desc.storage_mode = StorageMode::kHostVisible;

auto buffer = allocator.CreateBuffer(buffer_desc);
Expand Down
2 changes: 0 additions & 2 deletions impeller/scene/material.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,11 @@ std::unique_ptr<UnlitMaterial> UnlitMaterial::MakeFromFlatbuffer(

if (material.base_color_factor()) {
result->SetColor(importer::ToColor(*material.base_color_factor()));
result->SetVertexColorWeight(0);
}

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

return result;
Expand Down
Loading

0 comments on commit 2b024cb

Please sign in to comment.