导入角色动画,和增加角色控制

This commit is contained in:
2025-12-11 19:30:20 +08:00
parent a60a92e7ba
commit 7775fa30bb
1452 changed files with 592217 additions and 42573 deletions

View File

@@ -0,0 +1,438 @@
// Designed by KINEMATION, 2023
using KINEMATION.KAnimationCore.Runtime.Rig;
using UnityEngine;
using UnityEngine.Animations;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
public class KAnimationMath
{
public static Quaternion RotateInSpace(Quaternion space, Quaternion target, Quaternion rotation, float alpha)
{
return Quaternion.Slerp(target, space * rotation * (Quaternion.Inverse(space) * target), alpha);
}
public static Quaternion RotateInSpace(KTransform space, KTransform target, Quaternion offset, float alpha)
{
return RotateInSpace(space.rotation, target.rotation, offset, alpha);
}
public static void RotateInSpace(Transform space, Transform target, Quaternion offset, float alpha)
{
target.rotation = RotateInSpace(space.rotation, target.rotation, offset, alpha);
}
public static Vector3 MoveInSpace(KTransform space, KTransform target, Vector3 offset, float alpha)
{
return target.position + (space.TransformPoint(offset, false) - space.position) * alpha;
}
public static void MoveInSpace(Transform space, Transform target, Vector3 offset, float alpha)
{
target.position += (space.TransformPoint(offset) - space.position) * alpha;
}
public static Vector3 MoveInSpace(Transform space, Vector3 target, Vector3 offset, float alpha)
{
return target + (space.TransformPoint(offset) - space.position) * alpha;
}
public static KTransform GetTransform(AnimationStream stream, TransformStreamHandle handle,
bool isWorld = true)
{
if (!stream.isValid || !handle.IsValid(stream))
{
return KTransform.Identity;
}
KTransform output = new KTransform()
{
position = isWorld ? handle.GetPosition(stream) : handle.GetLocalPosition(stream),
rotation = isWorld ? handle.GetRotation(stream) : handle.GetLocalRotation(stream),
};
return output;
}
public static KTransform GetTransform(AnimationStream stream, TransformSceneHandle handle,
bool isWorld = true)
{
KTransform output = new KTransform()
{
position = isWorld ? handle.GetPosition(stream) : handle.GetLocalPosition(stream),
rotation = isWorld ? handle.GetRotation(stream) : handle.GetLocalRotation(stream),
};
return output;
}
public static void MoveInSpace(AnimationStream stream, TransformSceneHandle space,
TransformStreamHandle target, Vector3 offset, float weight)
{
KTransform spaceT = GetTransform(stream, space);
KTransform targetT = GetTransform(stream, target);
var result = MoveInSpace(spaceT, targetT, offset, weight);
target.SetPosition(stream, result);
}
public static void MoveInSpace(AnimationStream stream, TransformStreamHandle space,
TransformStreamHandle target, Vector3 offset, float weight)
{
KTransform spaceT = GetTransform(stream, space);
KTransform targetT = GetTransform(stream, target);
var result = MoveInSpace(spaceT, targetT, offset, weight);
target.SetPosition(stream, result);
}
public static void RotateInSpace(AnimationStream stream, TransformStreamHandle space,
TransformStreamHandle target, Quaternion offset, float weight)
{
KTransform spaceT = GetTransform(stream, space);
KTransform targetT = GetTransform(stream, target);
var result = RotateInSpace(spaceT, targetT, offset, weight);
target.SetRotation(stream, result);
}
public static void RotateInSpace(AnimationStream stream, TransformSceneHandle space,
TransformStreamHandle target, Quaternion offset, float weight)
{
KTransform spaceT = GetTransform(stream, space);
KTransform targetT = GetTransform(stream, target);
var result = RotateInSpace(spaceT, targetT, offset, weight);
target.SetRotation(stream, result);
}
public static void ModifyPosition(AnimationStream stream, TransformSceneHandle root, TransformStreamHandle bone,
Vector3 position, ESpaceType space, EModifyMode mode, float weight)
{
if (mode == EModifyMode.Ignore) return;
KTransform rootTransform = GetTransform(stream, root);
if (mode == EModifyMode.Add)
{
if (space == ESpaceType.BoneSpace)
{
MoveInSpace(stream, bone, bone, position, weight);
return;
}
if (space == ESpaceType.ParentBoneSpace)
{
var local = GetTransform(stream, bone, false);
bone.SetLocalPosition(stream, Vector3.Lerp(local.position,
local.position + position, weight));
return;
}
if (space == ESpaceType.ComponentSpace)
{
MoveInSpace(stream, root, bone, position, weight);
return;
}
KTransform world = GetTransform(stream, bone);
bone.SetPosition(stream,
Vector3.Lerp(world.position, world.position + position, weight));
return;
}
if (space is ESpaceType.BoneSpace or ESpaceType.ParentBoneSpace)
{
bone.SetLocalPosition(stream,
Vector3.Lerp(bone.GetLocalPosition(stream), position, weight));
return;
}
if (space == ESpaceType.ComponentSpace)
{
position = rootTransform.TransformPoint(position, false);
bone.SetPosition(stream, Vector3.Lerp(bone.GetPosition(stream), position, weight));
return;
}
bone.SetPosition(stream, Vector3.Lerp(bone.GetPosition(stream), position, weight));
}
public static void ModifyRotation(AnimationStream stream, TransformSceneHandle root, TransformStreamHandle bone,
Quaternion rotation, ESpaceType space, EModifyMode mode, float weight)
{
if (mode == EModifyMode.Ignore) return;
KTransform rootTransform = GetTransform(stream, root);
if (mode == EModifyMode.Add)
{
if (space == ESpaceType.BoneSpace)
{
RotateInSpace(stream, bone, bone, rotation, weight);
return;
}
if (space == ESpaceType.ParentBoneSpace)
{
var local = GetTransform(stream, bone, false);
bone.SetLocalRotation(stream, Quaternion.Slerp(local.rotation,
local.rotation * rotation, weight));
return;
}
if (space == ESpaceType.ComponentSpace)
{
RotateInSpace(stream, root, bone, rotation, weight);
return;
}
KTransform world = GetTransform(stream, bone);
bone.SetRotation(stream,
Quaternion.Slerp(world.rotation, world.rotation * rotation, weight));
return;
}
if (space is ESpaceType.BoneSpace or ESpaceType.ParentBoneSpace)
{
bone.SetLocalRotation(stream,
Quaternion.Slerp(bone.GetLocalRotation(stream), rotation, weight));
return;
}
if (space == ESpaceType.ComponentSpace)
{
rotation = rootTransform.rotation * rotation;
bone.SetRotation(stream, Quaternion.Slerp(bone.GetRotation(stream), rotation, weight));
return;
}
bone.SetRotation(stream, Quaternion.Slerp(bone.GetRotation(stream), rotation,
weight));
}
public static void ModifyTransform(AnimationStream stream, TransformSceneHandle root,
TransformStreamHandle target, KPose pose, float weight)
{
KTransform rootTransform = GetTransform(stream, root);
if (pose.modifyMode == EModifyMode.Add)
{
if (pose.space == ESpaceType.BoneSpace)
{
MoveInSpace(stream, target, target, pose.pose.position, weight);
RotateInSpace(stream, target, target, pose.pose.rotation, weight);
return;
}
if (pose.space == ESpaceType.ParentBoneSpace)
{
var local = GetTransform(stream, target, false);
target.SetLocalPosition(stream, Vector3.Lerp(local.position,
local.position + pose.pose.position, weight));
target.SetLocalRotation(stream, Quaternion.Slerp(local.rotation,
local.rotation * pose.pose.rotation, weight));
return;
}
if (pose.space == ESpaceType.ComponentSpace)
{
MoveInSpace(stream, root, target, pose.pose.position, weight);
RotateInSpace(stream, root, target, pose.pose.rotation, weight);
return;
}
KTransform world = GetTransform(stream, target);
target.SetPosition(stream,
Vector3.Lerp(world.position, world.position + pose.pose.position, weight));
target.SetRotation(stream,
Quaternion.Slerp(world.rotation, world.rotation * pose.pose.rotation, weight));
return;
}
if (pose.space is ESpaceType.BoneSpace or ESpaceType.ParentBoneSpace)
{
target.SetLocalPosition(stream,
Vector3.Lerp(target.GetLocalPosition(stream), pose.pose.position, weight));
target.SetLocalRotation(stream,
Quaternion.Slerp(target.GetLocalRotation(stream), pose.pose.rotation, weight));
return;
}
if (pose.space == ESpaceType.ComponentSpace)
{
var worldTransform = rootTransform.GetWorldTransform(pose.pose, false);
worldTransform = KTransform.Lerp(GetTransform(stream, target), worldTransform, weight);
target.SetPosition(stream, worldTransform.position);
target.SetRotation(stream, worldTransform.rotation);
return;
}
target.SetPosition(stream,
Vector3.Lerp(target.GetPosition(stream), pose.pose.position, weight));
target.SetRotation(stream, Quaternion.Slerp(target.GetRotation(stream), pose.pose.rotation,
weight));
}
public static void ModifyTransform(AnimationStream stream, TransformStreamHandle root,
TransformStreamHandle target, KPose pose, float weight)
{
KTransform rootTransform = GetTransform(stream, root);
if (pose.modifyMode == EModifyMode.Add)
{
if (pose.space == ESpaceType.BoneSpace)
{
MoveInSpace(stream, target, target, pose.pose.position, weight);
RotateInSpace(stream, target, target, pose.pose.rotation, weight);
return;
}
if (pose.space == ESpaceType.ParentBoneSpace)
{
var local = GetTransform(stream, target, false);
target.SetLocalPosition(stream, Vector3.Lerp(local.position,
local.position + pose.pose.position, weight));
target.SetLocalRotation(stream, Quaternion.Slerp(local.rotation,
local.rotation * pose.pose.rotation, weight));
return;
}
if (pose.space == ESpaceType.ComponentSpace)
{
MoveInSpace(stream, root, target, pose.pose.position, weight);
RotateInSpace(stream, root, target, pose.pose.rotation, weight);
return;
}
KTransform world = GetTransform(stream, target);
target.SetPosition(stream,
Vector3.Lerp(world.position, world.position + pose.pose.position, weight));
target.SetRotation(stream,
Quaternion.Slerp(world.rotation, world.rotation * pose.pose.rotation, weight));
return;
}
if (pose.space is ESpaceType.BoneSpace or ESpaceType.ParentBoneSpace)
{
target.SetLocalPosition(stream,
Vector3.Lerp(target.GetLocalPosition(stream), pose.pose.position, weight));
target.SetLocalRotation(stream,
Quaternion.Slerp(target.GetLocalRotation(stream), pose.pose.rotation, weight));
return;
}
if (pose.space == ESpaceType.ComponentSpace)
{
var worldTransform = rootTransform.GetWorldTransform(pose.pose, false);
target.SetPosition(stream, worldTransform.position);
target.SetRotation(stream, worldTransform.rotation);
return;
}
target.SetPosition(stream,
Vector3.Lerp(target.GetPosition(stream), pose.pose.position, weight));
target.SetRotation(stream, Quaternion.Slerp(target.GetRotation(stream), pose.pose.rotation,
weight));
}
// Copies a bone pose in world space.
public static void CopyBone(AnimationStream stream, TransformStreamHandle from, TransformStreamHandle to,
float weight = 1f)
{
to.SetPosition(stream, Vector3.Lerp(to.GetPosition(stream), from.GetPosition(stream), weight));
to.SetRotation(stream, Quaternion.Slerp(to.GetRotation(stream), from.GetRotation(stream), weight));
}
// Copies a bone pose in world space.
public static void CopyBone(AnimationStream stream, TransformSceneHandle from, TransformStreamHandle to,
float weight = 1f)
{
to.SetPosition(stream, Vector3.Lerp(to.GetPosition(stream), from.GetPosition(stream), weight));
to.SetRotation(stream, Quaternion.Slerp(to.GetRotation(stream), from.GetRotation(stream), weight));
}
public static bool IsWeightFull(float weight)
{
return Mathf.Approximately(weight, 1f);
}
public static bool IsWeightRelevant(float weight)
{
return !Mathf.Approximately(weight, 0f);
}
public static void ModifyTransform(Transform component, Transform target, in KPose pose, float alpha = 1f)
{
if (pose.modifyMode == EModifyMode.Add)
{
AddTransform(component, target, in pose, alpha);
return;
}
ReplaceTransform(component, target, in pose, alpha);
}
private static void AddTransform(Transform component, Transform target, in KPose pose, float alpha = 1f)
{
if (pose.space == ESpaceType.BoneSpace)
{
MoveInSpace(target, target, pose.pose.position, alpha);
RotateInSpace(target, target, pose.pose.rotation, alpha);
return;
}
if (pose.space == ESpaceType.ParentBoneSpace)
{
Transform parent = target.parent;
MoveInSpace(parent, target, pose.pose.position, alpha);
RotateInSpace(parent, target, pose.pose.rotation, alpha);
return;
}
if (pose.space == ESpaceType.ComponentSpace)
{
MoveInSpace(component, target, pose.pose.position, alpha);
RotateInSpace(component, target, pose.pose.rotation, alpha);
return;
}
Vector3 position = target.position;
Quaternion rotation = target.rotation;
target.position = Vector3.Lerp(position, position + pose.pose.position, alpha);
target.rotation = Quaternion.Slerp(rotation, rotation * pose.pose.rotation, alpha);
}
private static void ReplaceTransform(Transform component, Transform target, in KPose pose, float alpha = 1f)
{
if (pose.space == ESpaceType.BoneSpace || pose.space == ESpaceType.ParentBoneSpace)
{
target.localPosition = Vector3.Lerp(target.localPosition, pose.pose.position, alpha);
target.localRotation = Quaternion.Slerp(target.localRotation, pose.pose.rotation, alpha);
return;
}
if (pose.space == ESpaceType.ComponentSpace)
{
target.position = Vector3.Lerp(target.position, component.TransformPoint(pose.pose.position), alpha);
target.rotation = Quaternion.Slerp(target.rotation, component.rotation * pose.pose.rotation, alpha);
return;
}
target.position = Vector3.Lerp(target.position, pose.pose.position, alpha);
target.rotation = Quaternion.Slerp(target.rotation, pose.pose.rotation, alpha);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4980d4c84030441c922128e9a378b5fb
timeCreated: 1698338913

View File

@@ -0,0 +1,71 @@
// Designed by KINEMATION, 2024.
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
public struct ChainIKData
{
public Vector3[] positions;
public float[] lengths;
public Vector3 target;
public float tolerance;
public float maxReach;
public int maxIterations;
}
public class KChainIK
{
public static bool SolveFABRIK(ref ChainIKData ikData)
{
// If the target is unreachable
var rootToTargetDir = ikData.target - ikData.positions[0];
if (rootToTargetDir.sqrMagnitude > KMath.Square(ikData.maxReach))
{
// Line up chain towards target
var dir = rootToTargetDir.normalized;
for (int i = 1; i < ikData.positions.Length; ++i)
{
ikData.positions[i] = ikData.positions[i - 1] + dir * ikData.lengths[i - 1];
}
return true;
}
int tipIndex = ikData.positions.Length - 1;
float sqrTolerance = KMath.Square(ikData.tolerance);
if (KMath.SqrDistance(ikData.positions[tipIndex], ikData.target) > sqrTolerance)
{
var rootPos = ikData.positions[0];
int iteration = 0;
do
{
// Forward reaching phase
// Set tip to target and propagate displacement to rest of chain
ikData.positions[tipIndex] = ikData.target;
for (int i = tipIndex - 1; i > -1; --i)
{
ikData.positions[i] = ikData.positions[i + 1] +
((ikData.positions[i] - ikData.positions[i + 1]).normalized *
ikData.lengths[i]);
}
// Backward reaching phase
// Set root back at it's original position and propagate displacement to rest of chain
ikData.positions[0] = rootPos;
for (int i = 1; i < ikData.positions.Length; ++i)
ikData.positions[i] = ikData.positions[i - 1] +
((ikData.positions[i] - ikData.positions[i - 1]).normalized * ikData.lengths[i - 1]);
} while ((KMath.SqrDistance(ikData.positions[tipIndex], ikData.target) > sqrTolerance) &&
(++iteration < ikData.maxIterations));
return true;
}
return false;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1308cae72dcf420ab9a43892668bf485
timeCreated: 1716450134

View File

@@ -0,0 +1,154 @@
// Designed by KINEMATION, 2024.
using System;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
[Serializable]
public struct VectorCurve
{
public AnimationCurve x;
public AnimationCurve y;
public AnimationCurve z;
public static VectorCurve Linear(float timeStart, float timeEnd, float valueStart, float valueEnd)
{
VectorCurve result = new VectorCurve()
{
x = AnimationCurve.Linear(timeStart, timeEnd, valueStart, valueEnd),
y = AnimationCurve.Linear(timeStart, timeEnd, valueStart, valueEnd),
z = AnimationCurve.Linear(timeStart, timeEnd, valueStart, valueEnd)
};
return result;
}
public static VectorCurve Constant(float timeStart, float timeEnd, float value)
{
VectorCurve result = new VectorCurve()
{
x = AnimationCurve.Constant(timeStart, timeEnd, value),
y = AnimationCurve.Constant(timeStart, timeEnd, value),
z = AnimationCurve.Constant(timeStart, timeEnd, value)
};
return result;
}
public float GetCurveLength()
{
float maxTime = -1f;
float curveTime = KCurves.GetCurveLength(x);
maxTime = curveTime > maxTime ? curveTime : maxTime;
curveTime = KCurves.GetCurveLength(y);
maxTime = curveTime > maxTime ? curveTime : maxTime;
curveTime = KCurves.GetCurveLength(z);
maxTime = curveTime > maxTime ? curveTime : maxTime;
return maxTime;
}
public Vector3 GetValue(float time)
{
return new Vector3(x.Evaluate(time), y.Evaluate(time), z.Evaluate(time));
}
public Vector3 GetLastValue()
{
float length = GetCurveLength();
return GetValue(length);
}
public bool IsValid()
{
return x != null && y != null && z != null;
}
public VectorCurve(Keyframe[] keyFrame)
{
x = new AnimationCurve(keyFrame);
y = new AnimationCurve(keyFrame);
z = new AnimationCurve(keyFrame);
}
}
[Serializable]
public enum EEaseFunc
{
Linear,
Sine,
Cubic,
Custom
}
[Serializable]
public struct EaseMode
{
public EEaseFunc easeFunc;
public AnimationCurve curve;
public EaseMode(EEaseFunc func)
{
easeFunc = func;
curve = AnimationCurve.Linear(0f, 0f, 1f, 0f);
}
}
public class KCurves
{
public static float GetCurveLength(AnimationCurve curve)
{
float length = 0f;
if (curve != null)
{
length = curve[curve.length - 1].time;
}
return length;
}
public static float EaseSine(float a, float b, float alpha)
{
return Mathf.Lerp(a, b, -(Mathf.Cos(Mathf.PI * alpha) - 1) / 2);
}
public static float EaseCubic(float a, float b, float alpha)
{
alpha = alpha < 0.5 ? 4 * alpha * alpha * alpha : 1 - Mathf.Pow(-2 * alpha + 2, 3) / 2;
return Mathf.Lerp(a, b, alpha);
}
public static float EaseCurve(float a, float b, float alpha, AnimationCurve curve)
{
alpha = curve?.Evaluate(alpha) ?? alpha;
return Mathf.Lerp(a, b, alpha);
}
public static float Ease(float a, float b, float alpha, EaseMode ease)
{
alpha = Mathf.Clamp01(alpha);
if (ease.easeFunc == EEaseFunc.Sine)
{
return EaseSine(a, b, alpha);
}
if (ease.easeFunc == EEaseFunc.Cubic)
{
return EaseCubic(a, b, alpha);
}
if (ease.easeFunc == EEaseFunc.Custom)
{
return EaseCurve(a, b, alpha, ease.curve);
}
return Mathf.Lerp(a, b, alpha);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4594292dc1514661a692348534d3285c
timeCreated: 1698343937

View File

@@ -0,0 +1,104 @@
// Designed by KINEMATION, 2024.
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
public class KMath
{
public const float FloatMin = 1e-10f;
public const float SqrEpsilon = 1e-8f;
public static float Square(float value)
{
return value * value;
}
public static float SqrDistance(Vector3 a, Vector3 b)
{
return (b - a).sqrMagnitude;
}
public static float NormalizeEulerAngle(float angle)
{
while (angle < -180f) angle += 360f;
while (angle >= 180f) angle -= 360f;
return angle;
}
public static float TriangleAngle(float aLen, float aLen1, float aLen2)
{
float c = Mathf.Clamp((aLen1 * aLen1 + aLen2 * aLen2 - aLen * aLen) / (aLen1 * aLen2) / 2.0f, -1.0f, 1.0f);
return Mathf.Acos(c);
}
public static Quaternion FromToRotation(Vector3 from, Vector3 to)
{
float theta = Vector3.Dot(from.normalized, to.normalized);
if (theta >= 1f) return Quaternion.identity;
if (theta <= -1f)
{
Vector3 axis = Vector3.Cross(from, Vector3.right);
if (axis.sqrMagnitude == 0f) axis = Vector3.Cross(from, Vector3.up);
return Quaternion.AngleAxis(180f, axis);
}
return Quaternion.AngleAxis(Mathf.Acos(theta) * Mathf.Rad2Deg, Vector3.Cross(from, to).normalized);
}
public static Quaternion NormalizeSafe(Quaternion q)
{
float dot = Quaternion.Dot(q, q);
if (dot > FloatMin)
{
float rsqrt = 1.0f / Mathf.Sqrt(dot);
return new Quaternion(q.x * rsqrt, q.y * rsqrt, q.z * rsqrt, q.w * rsqrt);
}
return Quaternion.identity;
}
public static float InvLerp(float value, float a, float b)
{
float alpha = 0f;
if (!Mathf.Approximately(a, b))
{
alpha = (value - a) / (b - a);
}
return Mathf.Clamp01(alpha);
}
public static float ExpDecayAlpha(float speed, float deltaTime)
{
return 1 - Mathf.Exp(-speed * deltaTime);
}
public static float FloatInterp(float a, float b, float speed, float deltaTime)
{
return speed > 0f ? Mathf.Lerp(a, b, ExpDecayAlpha(speed, deltaTime)) : b;
}
public static Quaternion SmoothSlerp(Quaternion a, Quaternion b, float speed, float deltaTime)
{
return speed > 0f ? Quaternion.Slerp(a, b, ExpDecayAlpha(speed, deltaTime)) : b;
}
public static Vector2 ComputeLookAtInput(Transform root, Transform from, Transform to)
{
Vector2 result = Vector2.zero;
Quaternion rot = Quaternion.LookRotation(to.position - from.position);
rot = Quaternion.Inverse(root.rotation) * rot;
Vector3 euler = rot.eulerAngles;
result.x = NormalizeEulerAngle(euler.x);
result.y = NormalizeEulerAngle(euler.y);
return result;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bd8cdd8e10864049b6b1119a7c3cc296
timeCreated: 1704002312

View File

@@ -0,0 +1,87 @@
// Designed by KINEMATION, 2023
using System;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
public struct FloatSpringState
{
public float velocity;
public float error;
public void Reset()
{
error = velocity = 0f;
}
}
public struct VectorSpringState
{
public FloatSpringState x;
public FloatSpringState y;
public FloatSpringState z;
public void Reset()
{
x.Reset();
y.Reset();
z.Reset();
}
}
[Serializable]
public struct VectorSpring
{
public Vector3 damping;
public Vector3 stiffness;
public Vector3 speed;
public Vector3 scale;
public static VectorSpring identity = new VectorSpring()
{
damping = Vector3.zero,
stiffness = Vector3.zero,
speed = Vector3.zero,
scale = Vector3.zero
};
}
public class KSpringMath
{
public static float FloatSpringInterp(float current, float target, float speed, float criticalDamping,
float stiffness, float scale, ref FloatSpringState state, float deltaTime)
{
float interpSpeed = Mathf.Min(deltaTime * speed, 1f);
if (!Mathf.Approximately(interpSpeed, 0f))
{
float damping = 2 * Mathf.Sqrt(stiffness) * criticalDamping;
float error = target * scale - current;
float errorDeriv = error - state.error;
state.velocity += error * stiffness * interpSpeed + errorDeriv * damping;
state.error = error;
float value = current + state.velocity * interpSpeed;
return value;
}
return current;
}
public static Vector3 VectorSpringInterp(Vector3 current, in Vector3 target, in VectorSpring spring,
ref VectorSpringState state, float deltaTime)
{
current.x = FloatSpringInterp(current.x, target.x, spring.speed.x,
spring.damping.x, spring.stiffness.x, spring.scale.x, ref state.x, deltaTime);
current.y = FloatSpringInterp(current.y, target.y, spring.speed.y,
spring.damping.y, spring.stiffness.y, spring.scale.y, ref state.y, deltaTime);
current.z = FloatSpringInterp(current.z, target.z, spring.speed.z,
spring.damping.z, spring.stiffness.z, spring.scale.z, ref state.z, deltaTime);
return current;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b715a4ee42b646169c5ce859e6d34964
timeCreated: 1698339846

View File

@@ -0,0 +1,153 @@
// Designed by KINEMATION, 2024
using System;
using UnityEngine;
using Quaternion = UnityEngine.Quaternion;
using Vector3 = UnityEngine.Vector3;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
// Struct alternative for Transform.
[Serializable]
public struct KTransform
{
public static KTransform Identity = new(Vector3.zero, Quaternion.identity, Vector3.one);
public Vector3 position;
public Quaternion rotation;
public Vector3 scale;
public KTransform(Vector3 newPos, Quaternion newRot, Vector3 newScale)
{
position = newPos;
rotation = newRot;
scale = newScale;
}
public KTransform(Vector3 newPos, Quaternion newRot)
{
position = newPos;
rotation = newRot;
scale = Vector3.one;
}
public KTransform(Transform t, bool worldSpace = true)
{
if (worldSpace)
{
position = t.position;
rotation = t.rotation;
}
else
{
position = t.localPosition;
rotation = t.localRotation;
}
scale = t.localScale;
}
// Linearly interpolates translation and scale. Spherically interpolates rotation.
public static KTransform Lerp(KTransform a, KTransform b, float alpha)
{
Vector3 outPos = Vector3.Lerp(a.position, b.position, alpha);
Quaternion outRot = Quaternion.Slerp(a.rotation, b.rotation, alpha);
Vector3 outScale = Vector3.Lerp(a.scale, a.scale, alpha);
return new KTransform(outPos, outRot, outScale);
}
public static KTransform EaseLerp(KTransform a, KTransform b, float alpha, EaseMode easeMode)
{
return Lerp(a, b, KCurves.Ease(0f, 1f, alpha, easeMode));
}
// Frame-rate independent interpolation.
public static KTransform ExpDecay(KTransform a, KTransform b, float speed, float deltaTime)
{
return Lerp(a, b, KMath.ExpDecayAlpha(speed, deltaTime));
}
public bool Equals(KTransform other, bool useScale)
{
bool result = position.Equals(other.position) && rotation.Equals(other.rotation);
if (useScale)
{
result = result && scale.Equals(other.scale);
}
return result;
}
// Returns a point relative to this transform.
public Vector3 InverseTransformPoint(Vector3 worldPosition, bool useScale)
{
Vector3 result = Quaternion.Inverse(rotation) * (worldPosition - position);
if (useScale)
{
result = Vector3.Scale(scale, result);
}
return result;
}
// Returns a vector relative to this transform.
public Vector3 InverseTransformVector(Vector3 worldDirection, bool useScale)
{
Vector3 result = Quaternion.Inverse(rotation) * worldDirection;
if (useScale)
{
result = Vector3.Scale(scale, result);
}
return result;
}
// Converts a local position from this transform to world.
public Vector3 TransformPoint(Vector3 localPosition, bool useScale)
{
if (useScale)
{
localPosition = Vector3.Scale(scale, localPosition);
}
return position + rotation * localPosition;
}
// Converts a local vector from this transform to world.
public Vector3 TransformVector(Vector3 localDirection, bool useScale)
{
if (useScale)
{
localDirection = Vector3.Scale(scale, localDirection);
}
return rotation * localDirection;
}
// Returns a transform relative to this transform.
public KTransform GetRelativeTransform(KTransform worldTransform, bool useScale)
{
return new KTransform()
{
position = InverseTransformPoint(worldTransform.position, useScale),
rotation = Quaternion.Inverse(rotation) * worldTransform.rotation,
scale = Vector3.Scale(scale, worldTransform.scale)
};
}
// Converts a local transform to world.
public KTransform GetWorldTransform(KTransform localTransform, bool useScale)
{
return new KTransform()
{
position = TransformPoint(localTransform.position, useScale),
rotation = rotation * localTransform.rotation,
scale = Vector3.Scale(scale, localTransform.scale)
};
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d8ef53e57347421a8fcc4468bd018afd
timeCreated: 1698341198

View File

@@ -0,0 +1,121 @@
// Designed by KINEMATION, 2023
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
public struct KTwoBoneIkData
{
public KTransform root;
public KTransform mid;
public KTransform tip;
public KTransform target;
public KTransform hint;
public float posWeight;
public float rotWeight;
public float hintWeight;
public bool hasValidHint;
}
public class KTwoBoneIK
{
public static void Solve(ref KTwoBoneIkData ikData)
{
Vector3 aPosition = ikData.root.position;
Vector3 bPosition = ikData.mid.position;
Vector3 cPosition = ikData.tip.position;
Vector3 tPosition = Vector3.Lerp(cPosition, ikData.target.position, ikData.posWeight);
Quaternion tRotation = Quaternion.Slerp(ikData.tip.rotation, ikData.target.rotation, ikData.rotWeight);
bool hasHint = ikData.hasValidHint && ikData.hintWeight > 0f;
Vector3 ab = bPosition - aPosition;
Vector3 bc = cPosition - bPosition;
Vector3 ac = cPosition - aPosition;
Vector3 at = tPosition - aPosition;
float abLen = ab.magnitude;
float bcLen = bc.magnitude;
float acLen = ac.magnitude;
float atLen = at.magnitude;
float oldAbcAngle = KMath.TriangleAngle(acLen, abLen, bcLen);
float newAbcAngle = KMath.TriangleAngle(atLen, abLen, bcLen);
// Bend normal strategy is to take whatever has been provided in the animation
// stream to minimize configuration changes, however if this is collinear
// try computing a bend normal given the desired target position.
// If this also fails, try resolving axis using hint if provided.
Vector3 axis = Vector3.Cross(ab, bc);
if (axis.sqrMagnitude < KMath.SqrEpsilon)
{
axis = hasHint ? Vector3.Cross(ikData.hint.position - aPosition, bc) : Vector3.zero;
if (axis.sqrMagnitude < KMath.SqrEpsilon)
axis = Vector3.Cross(at, bc);
if (axis.sqrMagnitude < KMath.SqrEpsilon)
axis = Vector3.up;
}
axis = Vector3.Normalize(axis);
float a = 0.5f * (oldAbcAngle - newAbcAngle);
float sin = Mathf.Sin(a);
float cos = Mathf.Cos(a);
Quaternion deltaR = new Quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos);
KTransform localTip = ikData.mid.GetRelativeTransform(ikData.tip, false);
ikData.mid.rotation = deltaR * ikData.mid.rotation;
// Update child transform.
ikData.tip = ikData.mid.GetWorldTransform(localTip, false);
cPosition = ikData.tip.position;
ac = cPosition - aPosition;
KTransform localMid = ikData.root.GetRelativeTransform(ikData.mid, false);
localTip = ikData.mid.GetRelativeTransform(ikData.tip, false);
ikData.root.rotation = KMath.FromToRotation(ac, at) * ikData.root.rotation;
// Update child transforms.
ikData.mid = ikData.root.GetWorldTransform(localMid, false);
ikData.tip = ikData.mid.GetWorldTransform(localTip, false);
if (hasHint)
{
float acSqrMag = ac.sqrMagnitude;
if (acSqrMag > 0f)
{
bPosition = ikData.mid.position;
cPosition = ikData.tip.position;
ab = bPosition - aPosition;
ac = cPosition - aPosition;
Vector3 acNorm = ac / Mathf.Sqrt(acSqrMag);
Vector3 ah = ikData.hint.position - aPosition;
Vector3 abProj = ab - acNorm * Vector3.Dot(ab, acNorm);
Vector3 ahProj = ah - acNorm * Vector3.Dot(ah, acNorm);
float maxReach = abLen + bcLen;
if (abProj.sqrMagnitude > (maxReach * maxReach * 0.001f) && ahProj.sqrMagnitude > 0f)
{
Quaternion hintR = KMath.FromToRotation(abProj, ahProj);
hintR.x *= ikData.hintWeight;
hintR.y *= ikData.hintWeight;
hintR.z *= ikData.hintWeight;
hintR = KMath.NormalizeSafe(hintR);
ikData.root.rotation = hintR * ikData.root.rotation;
ikData.mid = ikData.root.GetWorldTransform(localMid, false);
ikData.tip = ikData.mid.GetWorldTransform(localTip, false);
}
}
}
ikData.tip.rotation = tRotation;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8d99a3775c3e469dbe146569b35cd7a6
timeCreated: 1698338938

View File

@@ -0,0 +1,53 @@
// Designed by KINEMATION, 2024.
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Core
{
public class SetFloat : StateMachineBehaviour
{
[SerializeField] private string paramName;
[SerializeField] private float paramTargetValue;
[SerializeField] private EaseMode easeMode = new EaseMode(EEaseFunc.Linear);
private int _paramId;
private float _paramStartValue;
private bool _isInitialized;
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
if (!_isInitialized)
{
_paramId = Animator.StringToHash(paramName);
_isInitialized = true;
}
_paramStartValue = animator.GetFloat(_paramId);
}
public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
int nextHash = animator.GetNextAnimatorStateInfo(layerIndex).fullPathHash;
if (nextHash != stateInfo.fullPathHash && nextHash != 0)
{
return;
}
float alpha = 0f;
if (animator.IsInTransition(layerIndex))
{
alpha = animator.GetAnimatorTransitionInfo(layerIndex).normalizedTime;
}
else
{
alpha = 1f;
}
animator.SetFloat(_paramId, KCurves.Ease(_paramStartValue, paramTargetValue, alpha, easeMode));
}
public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d4437088df934c1a9375bf492c23d011
timeCreated: 1709881756