Add Spline

This commit is contained in:
Wojtek Figat
2021-01-25 10:41:53 +01:00
parent 6cbeac6537
commit fe78fa7575
16 changed files with 914 additions and 2 deletions

View File

@@ -7,6 +7,7 @@
#include "Engine/Core/Math/Vector2.h"
#include "Engine/Core/Math/Vector3.h"
#include "Engine/Core/Math/Quaternion.h"
#include "Engine/Core/Math/Transform.h"
namespace AnimationUtils
{
@@ -40,6 +41,12 @@ namespace AnimationUtils
return Quaternion::Identity;
}
template<>
FORCE_INLINE Transform GetZero<Transform>()
{
return Transform::Identity;
}
template<>
FORCE_INLINE Color GetZero<Color>()
{
@@ -66,6 +73,16 @@ namespace AnimationUtils
Quaternion::Slerp(a, b, oneThird, result);
}
template<>
FORCE_INLINE void GetTangent<Transform>(const Transform& a, const Transform& b, float length, Transform& result)
{
const float oneThird = 1.0f / 3.0f;
const float oneThirdLength = length * oneThird;
result.Translation = a.Translation + b.Translation * oneThirdLength;
Quaternion::Slerp(a.Orientation, b.Orientation, oneThird, result.Orientation);
result.Scale = a.Scale + b.Scale * oneThirdLength;
}
template<class T>
FORCE_INLINE static void Interpolate(const T& a, const T& b, float alpha, T& result)
{
@@ -203,4 +220,12 @@ namespace AnimationUtils
Quaternion::Slerp(p12, p23, alpha, p123);
Quaternion::Slerp(p012, p123, alpha, result);
}
template<>
void Bezier<Transform>(const Transform& p0, const Transform& p1, const Transform& p2, const Transform& p3, float alpha, Transform& result)
{
Bezier<Vector3>(p0.Translation, p1.Translation, p2.Translation, p3.Translation, alpha, result.Translation);
Bezier<Quaternion>(p0.Orientation, p1.Orientation, p2.Orientation, p3.Orientation, alpha, result.Orientation);
Bezier<Vector3>(p0.Scale, p1.Scale, p2.Scale, p3.Scale, alpha, result.Scale);
}
}

View File

@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace FlaxEngine
{
@@ -338,6 +339,7 @@ namespace FlaxEngine
/// <summary>
/// A single keyframe that can be injected into linear curve.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Keyframe : IComparable, IComparable<Keyframe>
{
/// <summary>
@@ -586,6 +588,7 @@ namespace FlaxEngine
/// <summary>
/// A single keyframe that can be injected into Bezier curve.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Keyframe : IComparable, IComparable<Keyframe>
{
/// <summary>

View File

@@ -52,6 +52,11 @@ public:
{
result = a;
}
bool operator==(const StepCurveKeyframe& other) const
{
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value);
}
} PACK_END();
/// <summary>
@@ -97,6 +102,11 @@ public:
result.Time = a.Time + (b.Time - a.Time) * alpha;
AnimationUtils::Interpolate(a.Value, b.Value, alpha, result.Value);
}
bool operator==(const LinearCurveKeyframe& other) const
{
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value);
}
} PACK_END();
/// <summary>
@@ -164,6 +174,11 @@ public:
result.TangentIn /= length;
result.TangentOut = result.TangentIn;
}
bool operator==(const HermiteCurveKeyframe& other) const
{
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value) && Math::NearEqual(TangentIn, other.TangentIn) && Math::NearEqual(TangentOut, other.TangentOut);
}
} PACK_END();
/// <summary>
@@ -240,6 +255,11 @@ public:
result.TangentIn = a.TangentOut;
result.TangentOut = b.TangentIn;
}
bool operator==(const BezierCurveKeyframe& other) const
{
return Math::NearEqual(Time, other.Time) && Math::NearEqual(Value, other.Value) && Math::NearEqual(TangentIn, other.TangentIn) && Math::NearEqual(TangentOut, other.TangentOut);
}
} PACK_END();
// @formatter:on
@@ -708,6 +728,30 @@ public:
return false;
}
public:
FORCE_INLINE KeyFrame& operator[](int32 index)
{
return _keyframes[index];
}
FORCE_INLINE const KeyFrame& operator[](int32 index) const
{
return _keyframes[index];
}
bool operator==(const Curve& other) const
{
if (_keyframes.Count() != other._keyframes.Count())
return false;
for (int32 i = 0; i < _keyframes.Count(); i++)
{
if (!(_keyframes[i] == other._keyframes[i]))
return false;
}
return true;
}
};
/// <summary>

View File

@@ -0,0 +1,171 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#pragma once
#include "Curve.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Serialization/Serialization.h"
// @formatter:off
namespace Serialization
{
// StepCurveKeyframe
template<class T>
inline bool ShouldSerialize(const StepCurveKeyframe<T>& v, const void* otherObj)
{
if (!otherObj)
return true;
const auto other = (const StepCurveKeyframe<T>*)otherObj;
return !(v == *other);
}
template<class T>
inline void Serialize(ISerializable::SerializeStream& stream, const StepCurveKeyframe<T>& v, const void* otherObj)
{
stream.StartObject();
stream.JKEY("Time");
Serialize(stream, v.Time, nullptr);
stream.JKEY("Value");
Serialize(stream, v.Value, nullptr);
stream.EndObject();
}
template<class T>
inline void Deserialize(ISerializable::DeserializeStream& stream, StepCurveKeyframe<T>& v, ISerializeModifier* modifier)
{
DESERIALIZE_MEMBER(Time, v.Time);
DESERIALIZE_MEMBER(Value, v.Value);
}
// LinearCurveKeyframe
template<class T>
inline bool ShouldSerialize(const LinearCurveKeyframe<T>& v, const void* otherObj)
{
if (!otherObj)
return true;
const auto other = (const LinearCurveKeyframe<T>*)otherObj;
return !(v == *other);
}
template<class T>
inline void Serialize(ISerializable::SerializeStream& stream, const LinearCurveKeyframe<T>& v, const void* otherObj)
{
stream.StartObject();
stream.JKEY("Time");
Serialize(stream, v.Time, nullptr);
stream.JKEY("Value");
Serialize(stream, v.Value, nullptr);
stream.EndObject();
}
template<class T>
inline void Deserialize(ISerializable::DeserializeStream& stream, LinearCurveKeyframe<T>& v, ISerializeModifier* modifier)
{
DESERIALIZE_MEMBER(Time, v.Time);
DESERIALIZE_MEMBER(Value, v.Value);
}
// HermiteCurveKeyframe
template<class T>
inline bool ShouldSerialize(const HermiteCurveKeyframe<T>& v, const void* otherObj)
{
if (!otherObj)
return true;
const auto other = (const HermiteCurveKeyframe<T>*)otherObj;
return !(v == *other);
}
template<class T>
inline void Serialize(ISerializable::SerializeStream& stream, const HermiteCurveKeyframe<T>& v, const void* otherObj)
{
stream.StartObject();
stream.JKEY("Time");
Serialize(stream, v.Time, nullptr);
stream.JKEY("Value");
Serialize(stream, v.Value, nullptr);
stream.JKEY("TangentIn");
Serialize(stream, v.TangentIn, nullptr);
stream.JKEY("TangentOut");
Serialize(stream, v.TangentOut, nullptr);
stream.EndObject();
}
template<class T>
inline void Deserialize(ISerializable::DeserializeStream& stream, HermiteCurveKeyframe<T>& v, ISerializeModifier* modifier)
{
DESERIALIZE_MEMBER(Time, v.Time);
DESERIALIZE_MEMBER(Value, v.Value);
DESERIALIZE_MEMBER(TangentIn, v.TangentIn);
DESERIALIZE_MEMBER(TangentOut, v.TangentOut);
}
// BezierCurveKeyframe
template<class T>
inline bool ShouldSerialize(const BezierCurveKeyframe<T>& v, const void* otherObj)
{
if (!otherObj)
return true;
const auto other = (const BezierCurveKeyframe<T>*)otherObj;
return !(v == *other);
}
template<class T>
inline void Serialize(ISerializable::SerializeStream& stream, const BezierCurveKeyframe<T>& v, const void* otherObj)
{
stream.StartObject();
stream.JKEY("Time");
Serialize(stream, v.Time, nullptr);
stream.JKEY("Value");
Serialize(stream, v.Value, nullptr);
stream.JKEY("TangentIn");
Serialize(stream, v.TangentIn, nullptr);
stream.JKEY("TangentOut");
Serialize(stream, v.TangentOut, nullptr);
stream.EndObject();
}
template<class T>
inline void Deserialize(ISerializable::DeserializeStream& stream, BezierCurveKeyframe<T>& v, ISerializeModifier* modifier)
{
DESERIALIZE_MEMBER(Time, v.Time);
DESERIALIZE_MEMBER(Value, v.Value);
DESERIALIZE_MEMBER(TangentIn, v.TangentIn);
DESERIALIZE_MEMBER(TangentOut, v.TangentOut);
}
// Curve
template<class T, typename KeyFrame>
inline bool ShouldSerialize(const Curve<T, KeyFrame>& v, const void* otherObj)
{
if (!otherObj)
return true;
const auto other = (const Curve<T, KeyFrame>*)otherObj;
return !(v == *other);
}
template<class T, typename KeyFrame>
inline void Serialize(ISerializable::SerializeStream& stream, const Curve<T, KeyFrame>& v, const void* otherObj)
{
stream.StartObject();
stream.JKEY("Keyframes");
stream.StartArray();
for (auto& k : v.GetKeyframes())
Serialize(stream, k, nullptr);
stream.EndArray();
stream.EndObject();
}
template<class T, typename KeyFrame>
inline void Deserialize(ISerializable::DeserializeStream& stream, Curve<T, KeyFrame>& v, ISerializeModifier* modifier)
{
if (!stream.IsObject())
return;
const auto mKeyframes = SERIALIZE_FIND_MEMBER(stream, "Keyframes");
if (mKeyframes != stream.MemberEnd())
{
const auto& keyframesArray = mKeyframes->value.GetArray();
auto& keyframes = v.GetKeyframes();
keyframes.Resize(keyframesArray.Size());
for (rapidjson::SizeType i = 0; i < keyframesArray.Size(); i++)
Deserialize(keyframesArray[i], keyframes[i], modifier);
}
}
}
// @formatter:on