Files
UnrealEngine/Engine/Source/Runtime/MovieSceneTracks/Public/Systems/WeightAndEasingEvaluatorSystem.h
2025-05-18 13:04:45 +08:00

193 lines
6.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "Containers/Array.h"
#include "Containers/ContainerAllocationPolicies.h"
#include "Containers/Map.h"
#include "Containers/Set.h"
#include "Containers/SortedMap.h"
#include "Containers/SparseArray.h"
#include "EntitySystem/BuiltInComponentTypes.h"
#include "EntitySystem/EntityAllocationIterator.h"
#include "EntitySystem/MovieSceneEntityIDs.h"
#include "EntitySystem/MovieSceneEntityInstantiatorSystem.h"
#include "EntitySystem/MovieSceneEntitySystem.h"
#include "EntitySystem/MovieSceneSequenceInstanceHandle.h"
#include "HAL/Platform.h"
#include "UObject/ObjectMacros.h"
#include "UObject/UObjectGlobals.h"
#include "WeightAndEasingEvaluatorSystem.generated.h"
class UMovieSceneEntitySystemLinker;
class UMovieSceneEvalTimeSystem;
class UWeightAndEasingEvaluatorSystem;
class UObject;
struct FMovieSceneSubSequenceData;
// Bezier blending gives a true linear interpolation between biases, but
// disabled by default because it misbehaves if you feed it different parameters for 't' to each term
#ifndef UE_ENABLE_MOVIESCENE_BEZIER_BLENDING
#define UE_ENABLE_MOVIESCENE_BEZIER_BLENDING 0
#endif
namespace UE::MovieScene
{
struct FEasingMutationBase;
struct FAddEasingChannelToProviderMutation;
struct FAddEasingChannelToConsumerMutation;
enum class EHierarchicalBlendMode : uint8
{
// Blend hierarchical weights by multiplying children with all parent weights (default)
AccumulateParentToChild,
// Combine weights from child -> parent using an increasingly small factor based on previously accumulated weights
// For example:
// values = ( (a,t1), (b, t2), (c, t3), (d, t4))
// float final_weight = 1;
// float t = 1;
// for (i : size(values))
// float this = values[i].value*t*values[i].weight
// t = max(t - this, 0)
// final_weight *= this
ChildFirstBlendTarget,
#if UE_ENABLE_MOVIESCENE_BEZIER_BLENDING
// Combine weights from child -> parent using a bezier interpolation series
BezierSeries,
#endif
};
/** Computation data used for accumulating hierarchical weights for sub sequences */
struct FHierarchicalEasingChannelData
{
/** The final result of this easing channel, accumulated with all parents */
double FinalResult = 1.0;
/** Initial easing result from manual and easing weights, not accumulated with all parents */
double UnaccumulatedResult = 1.0;
/** Our parent's computation data within PreAllocatedComputationData (in order to support one -> many multiplications). */
uint16 ParentChannel = uint16(-1);
/** An optional result channel to feed our result to (in order to support many -> one multiplications) */
uint16 ResultChannel = uint16(-1);
/** This channel's HBias */
int16 HBias = 0;
#if UE_ENABLE_MOVIESCENE_BEZIER_BLENDING
// Bezier blending coefficients of the form a(1-t)^b + t^c
float CoeffA = 1.f;
float ExpB = 1.f;
float ExpC = 1.f;
#endif
EHierarchicalBlendMode BlendMode = EHierarchicalBlendMode::AccumulateParentToChild;
};
struct FHierarchicalEasingChannelBuffer
{
bool IsEmpty() const;
void Reset();
void ResetBlendTargets();
uint16 AddBaseChannel(const FHierarchicalEasingChannelData& InChannelData);
uint16 AddBlendTargetChannel(const FHierarchicalEasingChannelData& InChannelData);
TArray<FHierarchicalEasingChannelData> Channels;
int32 BlendTargetStartIndex = INDEX_NONE;
};
} // namespace UE::MovieScene
/**
* System that creates hierarchical easing channels for any newly introduced HierarchicalEasingProvider components
*/
UCLASS(MinimalAPI)
class UMovieSceneHierarchicalEasingInstantiatorSystem : public UMovieSceneEntityInstantiatorSystem
{
public:
struct FHierarchicalInstanceData
{
int32 HierarchicalDepth = -1;
uint16 StrongRefCount = 0;
uint16 WeakRefCount = 0;
};
GENERATED_BODY()
MOVIESCENETRACKS_API UMovieSceneHierarchicalEasingInstantiatorSystem(const FObjectInitializer& ObjInit);
MOVIESCENETRACKS_API void FinalizeBlendTargets();
private:
MOVIESCENETRACKS_API virtual bool IsRelevantImpl(UMovieSceneEntitySystemLinker* InLinker) const;
MOVIESCENETRACKS_API virtual void OnLink() override;
MOVIESCENETRACKS_API virtual void OnUnlink() override;
MOVIESCENETRACKS_API virtual void OnRun(FSystemTaskPrerequisites& InPrerequisites, FSystemSubsequentTasks& Subsequents) override;
private:
/** Map between a sub-sequence handle and the easing channel affecting it */
TSparseArray<uint16> CachedInstanceIDToChannel;
/** Cached output channels for a specific pair (source, target) of hierarchical blends */
TMap<TTuple<int16, UE::MovieScene::FHierarchicalBlendTarget>, uint16> CachedHierarchicalBlendTargetChannels;
UPROPERTY()
TObjectPtr<UWeightAndEasingEvaluatorSystem> EvaluatorSystem;
/** True of this system just updated all its channels */
bool bChannelsHaveBeenInvalidated;
};
/**
* System that finalizes creation of easing channels by allocating new channels for hierarchical blend targets if necessary
* This is required in order to solve the problem that the hierarchical instantiator needs to run before the property instantiator,
* but we can't allocate channels for blend targets until _after_ the property instantiator (which sets up the relevant BlendTarget components)
*
*/
UCLASS()
class UE_DEPRECATED(5.5, "This system is no longer functional") UMovieSceneHierarchicalEasingFinalizationSystem : public UMovieSceneEntityInstantiatorSystem
{
public:
GENERATED_BODY()
UMovieSceneHierarchicalEasingFinalizationSystem(const FObjectInitializer& ObjInit);
};
/**
* System that combines manual weights and easings and propagates them to entities with matching EasingChannelID components
*/
UCLASS(MinimalAPI)
class UWeightAndEasingEvaluatorSystem : public UMovieSceneEntitySystem
{
public:
GENERATED_BODY()
MOVIESCENETRACKS_API UWeightAndEasingEvaluatorSystem(const FObjectInitializer& ObjInit);
/**
* Called from the instantiator system once channel IDs have been calculated
*/
MOVIESCENETRACKS_API UE::MovieScene::FHierarchicalEasingChannelBuffer& GetComputationBuffer();
private:
MOVIESCENETRACKS_API virtual void OnSchedulePersistentTasks(UE::MovieScene::IEntitySystemScheduler* TaskScheduler) override;
MOVIESCENETRACKS_API virtual void OnRun(FSystemTaskPrerequisites& InPrerequisites, FSystemSubsequentTasks& Subsequents) override;
MOVIESCENETRACKS_API virtual bool IsRelevantImpl(UMovieSceneEntitySystemLinker* InLinker) const override;
MOVIESCENETRACKS_API virtual void OnLink() override final;
MOVIESCENETRACKS_API virtual void OnUnlink() override final;
private:
/** Unstable array of preallocated storage for computing easing results sorted by hierarchical depth. */
UE::MovieScene::FHierarchicalEasingChannelBuffer PreAllocatedComputationData;
};