You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
- Add support for double precision channels, curves, evaluation, blending, and all other runtime infrastructure. - Note that, as usual for now, double channels load and save float values. - Editor side also gains some new track editors for these new types, with some workarounds to correctly recognize between float and double vectors. - Transform tracks are now operating entirely in doubles. - Float recomposing APIs for keying tracks in the editor are now using doubles, and have been renamed to "value recomposing". #rb max.chen #preflight 6123f6d9e7a3070001ff37ed [CL 17278174 by ludovic chabant in ue5-main branch]
233 lines
7.7 KiB
C++
233 lines
7.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "Systems/MovieSceneQuaternionInterpolationRotationSystem.h"
|
|
#include "Channels/MovieSceneDoubleChannel.h"
|
|
#include "EntitySystem/BuiltInComponentTypes.h"
|
|
#include "EntitySystem/MovieSceneEvalTimeSystem.h"
|
|
#include "EntitySystem/MovieSceneEntitySystemLinker.h"
|
|
#include "EntitySystem/MovieSceneEntitySystemTask.h"
|
|
#include "MovieSceneTracksComponentTypes.h"
|
|
|
|
DECLARE_CYCLE_STAT(TEXT("MovieScene: Quat-interp-rot channel system"), MovieSceneEval_QuatInterpRotChannelSystem, STATGROUP_MovieSceneECS);
|
|
DECLARE_CYCLE_STAT(TEXT("MovieScene: Evaluate quat-interp-rot channels"), MovieSceneEval_EvaluateQuatInterpRotChannelTask, STATGROUP_MovieSceneECS);
|
|
|
|
namespace UE
|
|
{
|
|
namespace MovieScene
|
|
{
|
|
|
|
struct FEvaluateQuaternionInterpolationRotationChannels
|
|
{
|
|
// Find the closest next/previous times to the current time inside a list of keyframe times.
|
|
static void SetFrameRange(const FFrameTime FrameTime, const TArrayView<const FFrameNumber> &Times, TRange<FFrameNumber> &FrameRange)
|
|
{
|
|
int32 Index1, Index2;
|
|
Index2 = 0;
|
|
Index2 = Algo::UpperBound(Times, FrameTime.FrameNumber);
|
|
Index1 = Index2 - 1;
|
|
Index1 = Index1 >= 0 ? Index1 : INDEX_NONE;
|
|
Index2 = Index2 < Times.Num() ? Index2 : INDEX_NONE;
|
|
if (Index1 != INDEX_NONE && Index2 != INDEX_NONE)
|
|
{
|
|
if (Times[Index1] != FrameTime.FrameNumber && Times[Index1] > FrameRange.GetLowerBoundValue())
|
|
{
|
|
FrameRange.SetLowerBoundValue(Times[Index1]);
|
|
}
|
|
if (Times[Index2] != FrameTime.FrameNumber && Times[Index1] < FrameRange.GetUpperBoundValue())
|
|
{
|
|
FrameRange.SetUpperBoundValue(Times[Index2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ForEachAllocation(
|
|
const FEntityAllocation* Allocation,
|
|
TRead<FFrameTime> FrameTimes,
|
|
TMultiReadOptional<FSourceDoubleChannel, FSourceDoubleChannel, FSourceDoubleChannel> RotChannelAccessors,
|
|
double* OutResultXs, double* OutResultYs, double* OutResultZs)
|
|
{
|
|
const FSourceDoubleChannel* RotationXs = RotChannelAccessors.Get<0>();
|
|
const FSourceDoubleChannel* RotationYs = RotChannelAccessors.Get<1>();
|
|
const FSourceDoubleChannel* RotationZs = RotChannelAccessors.Get<2>();
|
|
|
|
check(
|
|
(OutResultXs != nullptr) == (RotationXs != nullptr) &&
|
|
(OutResultYs != nullptr) == (RotationYs != nullptr) &&
|
|
(OutResultZs != nullptr) == (RotationZs != nullptr) );
|
|
|
|
const int32 AllocationSize = Allocation->Num();
|
|
for (int32 Index = 0; Index < AllocationSize; ++Index)
|
|
{
|
|
const FFrameTime FrameTime = FrameTimes[Index];
|
|
|
|
const FSourceDoubleChannel* RotationX = RotationXs ? &RotationXs[Index] : nullptr;
|
|
const FSourceDoubleChannel* RotationY = RotationYs ? &RotationYs[Index] : nullptr;
|
|
const FSourceDoubleChannel* RotationZ = RotationZs ? &RotationZs[Index] : nullptr;
|
|
|
|
// Find the closest keyframes before/after the current time on the 3 rotation channels.
|
|
TRange<FFrameNumber> FrameRange(TNumericLimits<FFrameNumber>::Min(), TNumericLimits<FFrameNumber>::Max());
|
|
if (RotationX)
|
|
{
|
|
SetFrameRange(FrameTime, RotationX->Source->GetTimes(), FrameRange);
|
|
}
|
|
if (RotationY)
|
|
{
|
|
SetFrameRange(FrameTime, RotationY->Source->GetTimes(), FrameRange);
|
|
}
|
|
if (RotationZ)
|
|
{
|
|
SetFrameRange(FrameTime, RotationZ->Source->GetTimes(), FrameRange);
|
|
}
|
|
|
|
const FFrameNumber LowerBound = FrameRange.GetLowerBoundValue();
|
|
const FFrameNumber UpperBound = FrameRange.GetUpperBoundValue();
|
|
if (LowerBound != TNumericLimits<FFrameNumber>::Min() && UpperBound != TNumericLimits<FFrameNumber>::Max())
|
|
{
|
|
double Value;
|
|
FVector FirstRot(0.0f, 0.0f, 0.0f);
|
|
FVector SecondRot(0.0f, 0.0f, 0.0f);
|
|
double U = (FrameTime.AsDecimal() - (double) FrameRange.GetLowerBoundValue().Value) /
|
|
double(FrameRange.GetUpperBoundValue().Value - FrameRange.GetLowerBoundValue().Value);
|
|
U = FMath::Clamp(U, 0.0, 1.0);
|
|
|
|
if (RotationX)
|
|
{
|
|
if (RotationX->Source->Evaluate(LowerBound, Value))
|
|
{
|
|
FirstRot[0] = Value;
|
|
}
|
|
if (RotationX->Source->Evaluate(UpperBound, Value))
|
|
{
|
|
SecondRot[0] = Value;
|
|
}
|
|
}
|
|
if (RotationY)
|
|
{
|
|
if (RotationY->Source->Evaluate(LowerBound, Value))
|
|
{
|
|
FirstRot[1] = Value;
|
|
}
|
|
if (RotationY->Source->Evaluate(UpperBound, Value))
|
|
{
|
|
SecondRot[1] = Value;
|
|
}
|
|
}
|
|
if (RotationZ)
|
|
{
|
|
if (RotationZ->Source->Evaluate(LowerBound, Value))
|
|
{
|
|
FirstRot[2] = Value;
|
|
}
|
|
if (RotationZ->Source->Evaluate(UpperBound, Value))
|
|
{
|
|
SecondRot[2] = Value;
|
|
}
|
|
}
|
|
|
|
const FQuat Key1Quat = FQuat::MakeFromEuler(FirstRot);
|
|
const FQuat Key2Quat = FQuat::MakeFromEuler(SecondRot);
|
|
|
|
const FQuat SlerpQuat = FQuat::Slerp(Key1Quat, Key2Quat, U);
|
|
FVector Euler = FRotator(SlerpQuat).Euler();
|
|
if (RotationX)
|
|
{
|
|
OutResultXs[Index] = Euler[0];
|
|
}
|
|
if (RotationY)
|
|
{
|
|
OutResultYs[Index] = Euler[1];
|
|
}
|
|
if (RotationZ)
|
|
{
|
|
OutResultZs[Index] = Euler[2];
|
|
}
|
|
}
|
|
else // no range found: default to regular, but still do RotToQuat
|
|
{
|
|
double Value;
|
|
FVector CurrentRot(0.0f, 0.0f, 0.0f);
|
|
if (RotationX && RotationX->Source->Evaluate(FrameTime, Value))
|
|
{
|
|
CurrentRot[0] = Value;
|
|
}
|
|
if (RotationY && RotationY->Source->Evaluate(FrameTime, Value))
|
|
{
|
|
CurrentRot[1] = Value;
|
|
}
|
|
if (RotationZ && RotationZ->Source->Evaluate(FrameTime, Value))
|
|
{
|
|
CurrentRot[2] = Value;
|
|
}
|
|
FQuat Quat = FQuat::MakeFromEuler(CurrentRot);
|
|
FVector Euler = FRotator(Quat).Euler();
|
|
if (RotationX)
|
|
{
|
|
OutResultXs[Index] = Euler[0];
|
|
}
|
|
if (RotationY)
|
|
{
|
|
OutResultYs[Index] = Euler[1];
|
|
}
|
|
if (RotationZ)
|
|
{
|
|
OutResultZs[Index] = Euler[2];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
} // namespace MovieScene
|
|
} // namespace UE
|
|
|
|
UMovieSceneQuaternionInterpolationRotationSystem::UMovieSceneQuaternionInterpolationRotationSystem(const FObjectInitializer& ObjInit)
|
|
: Super(ObjInit)
|
|
{
|
|
using namespace UE::MovieScene;
|
|
|
|
if (HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
DefineImplicitPrerequisite(UMovieSceneEvalTimeSystem::StaticClass(), GetClass());
|
|
|
|
FBuiltInComponentTypes* BuiltInComponents = FBuiltInComponentTypes::Get();
|
|
DefineComponentProducer(GetClass(), BuiltInComponents->DoubleResult[3]);
|
|
DefineComponentProducer(GetClass(), BuiltInComponents->DoubleResult[4]);
|
|
DefineComponentProducer(GetClass(), BuiltInComponents->DoubleResult[5]);
|
|
}
|
|
}
|
|
|
|
bool UMovieSceneQuaternionInterpolationRotationSystem::IsRelevantImpl(UMovieSceneEntitySystemLinker* InLinker) const
|
|
{
|
|
using namespace UE::MovieScene;
|
|
|
|
FMovieSceneTracksComponentTypes* TrackComponents = FMovieSceneTracksComponentTypes::Get();
|
|
|
|
return InLinker->EntityManager.ContainsAnyComponent({
|
|
TrackComponents->QuaternionRotationChannel[0],
|
|
TrackComponents->QuaternionRotationChannel[1],
|
|
TrackComponents->QuaternionRotationChannel[2]
|
|
});
|
|
}
|
|
|
|
void UMovieSceneQuaternionInterpolationRotationSystem::OnRun(FSystemTaskPrerequisites& InPrerequisites, FSystemSubsequentTasks& Subsequents)
|
|
{
|
|
using namespace UE::MovieScene;
|
|
|
|
SCOPE_CYCLE_COUNTER(MovieSceneEval_QuatInterpRotChannelSystem);
|
|
|
|
FBuiltInComponentTypes* BuiltInComponents = FBuiltInComponentTypes::Get();
|
|
FMovieSceneTracksComponentTypes* TrackComponents = FMovieSceneTracksComponentTypes::Get();
|
|
|
|
FEntityTaskBuilder()
|
|
.Read(BuiltInComponents->EvalTime)
|
|
.ReadOneOrMoreOf(
|
|
TrackComponents->QuaternionRotationChannel[0],
|
|
TrackComponents->QuaternionRotationChannel[1],
|
|
TrackComponents->QuaternionRotationChannel[2])
|
|
.WriteOptional(BuiltInComponents->DoubleResult[3])
|
|
.WriteOptional(BuiltInComponents->DoubleResult[4])
|
|
.WriteOptional(BuiltInComponents->DoubleResult[5])
|
|
.SetStat(GET_STATID(MovieSceneEval_EvaluateQuatInterpRotChannelTask))
|
|
.Dispatch_PerAllocation<FEvaluateQuaternionInterpolationRotationChannels>(&Linker->EntityManager, InPrerequisites, &Subsequents);
|
|
}
|