导入角色动画,和增加角色控制
This commit is contained in:
438
Assets/KINEMATION/KAnimationCore/Runtime/Core/KAnimationMath.cs
Normal file
438
Assets/KINEMATION/KAnimationCore/Runtime/Core/KAnimationMath.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4980d4c84030441c922128e9a378b5fb
|
||||
timeCreated: 1698338913
|
||||
71
Assets/KINEMATION/KAnimationCore/Runtime/Core/KChainIK.cs
Normal file
71
Assets/KINEMATION/KAnimationCore/Runtime/Core/KChainIK.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1308cae72dcf420ab9a43892668bf485
|
||||
timeCreated: 1716450134
|
||||
154
Assets/KINEMATION/KAnimationCore/Runtime/Core/KCurves.cs
Normal file
154
Assets/KINEMATION/KAnimationCore/Runtime/Core/KCurves.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4594292dc1514661a692348534d3285c
|
||||
timeCreated: 1698343937
|
||||
104
Assets/KINEMATION/KAnimationCore/Runtime/Core/KMath.cs
Normal file
104
Assets/KINEMATION/KAnimationCore/Runtime/Core/KMath.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd8cdd8e10864049b6b1119a7c3cc296
|
||||
timeCreated: 1704002312
|
||||
87
Assets/KINEMATION/KAnimationCore/Runtime/Core/KSpringMath.cs
Normal file
87
Assets/KINEMATION/KAnimationCore/Runtime/Core/KSpringMath.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b715a4ee42b646169c5ce859e6d34964
|
||||
timeCreated: 1698339846
|
||||
153
Assets/KINEMATION/KAnimationCore/Runtime/Core/KTransform.cs
Normal file
153
Assets/KINEMATION/KAnimationCore/Runtime/Core/KTransform.cs
Normal 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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8ef53e57347421a8fcc4468bd018afd
|
||||
timeCreated: 1698341198
|
||||
121
Assets/KINEMATION/KAnimationCore/Runtime/Core/KTwoBoneIK.cs
Normal file
121
Assets/KINEMATION/KAnimationCore/Runtime/Core/KTwoBoneIK.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d99a3775c3e469dbe146569b35cd7a6
|
||||
timeCreated: 1698338938
|
||||
53
Assets/KINEMATION/KAnimationCore/Runtime/Core/SetFloat.cs
Normal file
53
Assets/KINEMATION/KAnimationCore/Runtime/Core/SetFloat.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4437088df934c1a9375bf492c23d011
|
||||
timeCreated: 1709881756
|
||||
Reference in New Issue
Block a user