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

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,7 @@
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
public interface IRigObserver
{
public void OnRigUpdated();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 00acdb04eae148a0b993a37cb2b95007
timeCreated: 1708431186

View File

@@ -0,0 +1,7 @@
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
public interface IRigProvider
{
public KRigElement[] GetHierarchy();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8c27f9465994402da2a00b6e82c4a580
timeCreated: 1744271712

View File

@@ -0,0 +1,8 @@
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
public interface IRigUser
{
// Must return a reference to the used Rig Asset.
public KRig GetRigAsset();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 906523edc5b146fb8837b1804a606af5
timeCreated: 1705907873

View File

@@ -0,0 +1,32 @@
using System;
using KINEMATION.KAnimationCore.Runtime.Core;
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
// Represents the space we will modify bone transform in.
public enum ESpaceType
{
BoneSpace,
ParentBoneSpace,
ComponentSpace,
WorldSpace
}
// Whether the operation is additive or absolute.
public enum EModifyMode
{
Add,
Replace,
Ignore
}
// Represents the pose for the specific rig element.
[Serializable]
public struct KPose
{
public KRigElement element;
public KTransform pose;
public ESpaceType space;
public EModifyMode modifyMode;
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 054feb4bdc8a463ea7b6aba306d8cd64
timeCreated: 1704783390

View File

@@ -0,0 +1,138 @@
// Designed by KINEMATION, 2024.
using KINEMATION.KAnimationCore.Runtime.Input;
using System.Collections.Generic;
using KINEMATION.KAnimationCore.Runtime.Attributes;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
public abstract class KRigBase : ScriptableObject, IRigProvider
{
public RuntimeAnimatorController targetAnimator;
public List<KRigElement> rigHierarchy = new List<KRigElement>();
[CustomElementChainDrawer(false, true)]
public List<KRigElementChain> rigElementChains = new List<KRigElementChain>();
public KRigElement[] GetHierarchy()
{
return rigHierarchy.ToArray();
}
}
// Character skeleton asset.
public class KRig : KRigBase
{
public UserInputConfig inputConfig;
public List<string> rigCurves = new List<string>();
public KRigElementChain GetElementChainByName(string chainName)
{
var chain = rigElementChains.Find(item => item.chainName.Equals(chainName));
return chain;
}
public KTransformChain GetPopulatedChain(string chainName, KRigComponent rigComponent)
{
KTransformChain result = new KTransformChain();
var targetChain = GetElementChainByName(chainName);
if (targetChain == null)
{
Debug.LogError($"Rig `{name}`: `{chainName}` chain not found!");
return null;
}
foreach (var element in targetChain.elementChain)
{
result.transformChain.Add(rigComponent.GetRigTransform(element));
}
return result;
}
#if UNITY_EDITOR
public List<int> rigDepths = new List<int>();
private List<Object> _rigObservers = new List<Object>();
private void OnEnable()
{
// Force update rig depths for compatibility reasons.
int count = rigHierarchy.Count;
for (int i = 0; i < count; i++)
{
var element = rigHierarchy[i];
element.depth = rigDepths[i];
rigHierarchy[i] = element;
}
}
public void ImportRig(KRigComponent rigComponent)
{
rigHierarchy.Clear();
rigDepths.Clear();
rigComponent.RefreshHierarchy();
var hierarchy = rigComponent.GetRigTransforms();
var depths = rigComponent.GetHierarchyDepths();
for (int i = 0; i < hierarchy.Length; i++)
{
rigHierarchy.Add(new KRigElement(i, hierarchy[i].transform.name));
rigDepths.Add(depths[i]);
}
NotifyObservers();
EditorUtility.SetDirty(this);
AssetDatabase.SaveAssetIfDirty(this);
}
public KRigElement GetElementByName(string targetName)
{
return rigHierarchy.Find(item => item.name.Equals(targetName));
}
public void RegisterRigObserver(Object newRigObserver)
{
// Only register Rig Observers.
IRigObserver observer = (IRigObserver) newRigObserver;
if (observer == null) return;
if (_rigObservers.Contains(newRigObserver))
{
return;
}
_rigObservers.Add(newRigObserver);
EditorUtility.SetDirty(this);
}
public void UnRegisterObserver(Object rigObserver)
{
_rigObservers.Remove(rigObserver);
EditorUtility.SetDirty(this);
}
public void NotifyObservers()
{
List<Object> validObservers = new List<Object>();
foreach (var observer in _rigObservers)
{
if (observer is IRigObserver obj)
{
obj.OnRigUpdated();
validObservers.Add(observer);
}
}
_rigObservers = validObservers;
}
#endif
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8c9c04639ae548bdb0a8e927492d029d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,176 @@
// Designed by KINEMATION, 2024.
using System.Collections.Generic;
using KINEMATION.KAnimationCore.Runtime.Core;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
public class KRigComponent : MonoBehaviour
{
[SerializeField] private List<Transform> hierarchy = new List<Transform>();
private List<KVirtualElement> _virtualElements;
private Dictionary<string, int> _hierarchyMap;
private List<KTransform> _cachedHierarchyPose;
#if UNITY_EDITOR
[SerializeField] private List<int> hierarchyDepths = new List<int>();
public bool CompareRig(KRig compareTo)
{
if (compareTo == null || hierarchy == null || compareTo.rigHierarchy.Count != hierarchy.Count)
{
return false;
}
int count = hierarchy.Count;
for (int i = 0; i < count; i++)
{
if (!compareTo.rigHierarchy[i].name.Equals(hierarchy[i].name)) return false;
}
return true;
}
public int[] GetHierarchyDepths()
{
return hierarchyDepths.ToArray();
}
public void RefreshHierarchy()
{
hierarchy.Clear();
hierarchyDepths.Clear();
TraverseHierarchyByLayer(transform, 0);
}
public Transform[] GetHierarchy()
{
if (hierarchy == null)
{
return null;
}
return hierarchy.ToArray();
}
public bool Contains(string entry)
{
if (hierarchy == null) return false;
HashSet<string> set = new HashSet<string>();
foreach (var element in hierarchy)
{
set.Add(element.name);
}
return set.Contains(entry);
}
private void TraverseHierarchyByLayer(Transform currentTransform, int depth)
{
hierarchy.Add(currentTransform);
hierarchyDepths.Add(depth);
foreach (Transform child in currentTransform)
{
TraverseHierarchyByLayer(child, depth + 1);
}
}
#endif
public void Initialize()
{
// Register Virtual Elements.
_virtualElements = new List<KVirtualElement>();
KVirtualElement[] virtualElements = GetComponentsInChildren<KVirtualElement>();
foreach (var virtualElement in virtualElements)
{
_virtualElements.Add(virtualElement);
}
// Map the hierarchy indexes to the element names.
_hierarchyMap = new Dictionary<string, int>();
int count = hierarchy.Count;
for (int i = 0; i < count; i++)
{
_hierarchyMap.TryAdd(hierarchy[i].name, i);
}
_cachedHierarchyPose = new List<KTransform>();
}
public void AnimateVirtualElements()
{
foreach (var virtualElement in _virtualElements)
{
virtualElement.Animate();
}
}
public Transform[] GetRigTransforms()
{
return hierarchy.ToArray();
}
public Transform GetRigTransform(KRigElement rigElement)
{
int index = rigElement.index;
// Invalid index, try to use the element name instead.
if (index < 0 || index > hierarchy.Count - 1)
{
index = _hierarchyMap[rigElement.name];
}
// Total failure, return null.
if (index < 0 || index > hierarchy.Count - 1)
{
return null;
}
return hierarchy[index].transform;
}
public Transform GetRigTransform(string elementName)
{
if (_hierarchyMap.TryGetValue(elementName, out var element))
{
return hierarchy[element];
}
return null;
}
public Transform GetRigTransform(int elementIndex)
{
if (elementIndex < 0 || elementIndex > hierarchy.Count - 1)
{
return null;
}
return hierarchy[elementIndex].transform;
}
public void CacheHierarchyPose()
{
_cachedHierarchyPose.Clear();
foreach (var element in hierarchy) _cachedHierarchyPose.Add(new KTransform(element,
false));
}
public void ApplyHierarchyCachedPose()
{
int count = hierarchy.Count;
for (int i = 0; i < count; i++)
{
var cachedPose = _cachedHierarchyPose[i];
hierarchy[i].localPosition = cachedPose.position;
hierarchy[i].localRotation = cachedPose.rotation;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e03e7ed42ce9470c899fc6cc550571e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
// Designed by KINEMATION, 2024.
using System;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
[Serializable]
public struct KRigElement
{
public string name;
[HideInInspector] public int index;
public int depth;
public KRigElement(int index = -1, string name = "None", int depth = -1)
{
this.index = index;
this.name = name;
this.depth = depth;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ba9819a027d34b42a29b91a6cdaa5bbf
timeCreated: 1704271222

View File

@@ -0,0 +1,123 @@
// Designed by KINEMATION, 2024.
using KINEMATION.KAnimationCore.Runtime.Core;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
[Serializable]
public class KRigElementChain
{
public int Count => elementChain.Count;
public string chainName;
[HideInInspector] public List<KRigElement> elementChain = new List<KRigElement>();
public KRigElementChain GetCopy()
{
KRigElementChain copy = new KRigElementChain();
copy.chainName = chainName;
foreach (var element in elementChain) copy.elementChain.Add(element);
return copy;
}
}
// A simplified version of the KRigElementChain, which contains transforms only.
public class KTransformChain
{
public List<Transform> transformChain = new List<Transform>();
public List<KTransform> cachedTransforms = new List<KTransform>();
public ESpaceType spaceType;
public void CacheTransforms(ESpaceType targetSpace, Transform root = null)
{
cachedTransforms.Clear();
spaceType = targetSpace;
foreach (var element in transformChain)
{
KTransform cache = new KTransform();
if (targetSpace == ESpaceType.WorldSpace)
{
cache.position = element.position;
cache.rotation = element.rotation;
}
else if (targetSpace == ESpaceType.ComponentSpace)
{
if (root == null)
{
root = element.root;
}
cache.position = root.InverseTransformPoint(element.position);
cache.rotation = Quaternion.Inverse(root.rotation) * element.rotation;
}
else
{
cache.position = element.localPosition;
cache.rotation = element.localRotation;
}
cachedTransforms.Add(cache);
}
}
public void BlendTransforms(float weight)
{
int count = transformChain.Count;
for (int i = 0; i < count; i++)
{
Transform element = transformChain[i];
KTransform cache = cachedTransforms[i];
KPose pose = new KPose()
{
modifyMode = EModifyMode.Replace,
pose = cache,
space = spaceType
};
KAnimationMath.ModifyTransform(element.root, element, pose, weight);
}
}
public float GetLength(Transform root = null)
{
float chainLength = 0f;
int count = transformChain.Count;
if (count > 0 && root == null) root = transformChain[0];
for (int i = 0; i < count; i++)
{
Transform targetBone = transformChain[i];
if (count == 1)
{
Vector3 targetMS = root.InverseTransformPoint(targetBone.position);
chainLength = targetMS.magnitude;
}
if (i > 0)
{
chainLength += (targetBone.position - transformChain[i - 1].position).magnitude;
}
}
return chainLength;
}
public bool IsValid()
{
if (transformChain == null || cachedTransforms == null) return false;
if (transformChain.Count == 0) return false;
return true;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 33155135ddde45ec8689a8c186f23deb
timeCreated: 1704271199

View File

@@ -0,0 +1,15 @@
using UnityEngine;
namespace KINEMATION.KAnimationCore.Runtime.Rig
{
public class KVirtualElement : MonoBehaviour
{
public Transform targetBone;
public void Animate()
{
transform.position = targetBone.position;
transform.rotation = targetBone.rotation;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9f3351c9a16a41d9b4e52958975b758b
timeCreated: 1707634755