From 38391181af60df8532075f38bbc0ccddf9bd2280 Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Fri, 10 Apr 2026 17:43:44 +0200 Subject: [PATCH] Animation scaling step 1 --- .../Editor/Scripts/AnimationEditor.cs | 117 +++++ .../Editor/Scripts/AnimationEditor.cs.meta | 11 + .../Editor/Scripts/Creature_Editor.cs | 2 +- .../Editor/Scripts/Insect/InsectRig_Editor.cs | 15 +- .../Editor/Scripts/Insect/Insect_Editor.cs | 108 +++- CreatureControl/Editor/Scripts/Leg_Editor.cs | 9 +- .../Editor/Scripts/TargetLeg_Editor.cs | 44 ++ .../Editor/Scripts/TargetLeg_Editor.cs.meta | 11 + CreatureControl/Runtime/Scripts/Creature.cs | 3 +- .../Runtime/Scripts/Insect/Insect.cs | 9 +- .../Runtime/Scripts/Insect/InsectRig.cs | 44 +- CreatureControl/Runtime/Scripts/Leg.cs | 46 +- CreatureControl/Runtime/Scripts/LegTarget.cs | 2 +- CreatureControl/Runtime/Scripts/TargetLeg.cs | 108 ++-- CreatureControl/Runtime/Scripts/TargetRig.cs | 7 +- Documentation/Animations.md | 36 +- Documentation/{Ant2.md => Ant.md} | 0 Documentation/{Ant2.md.meta => Ant.md.meta} | 0 Documentation/Models.md | 12 +- Editor/Scripts/Ant_Editor.cs | 2 +- Runtime/Resources/InsectTargetRig.prefab | 70 ++- Runtime/Scripts/Ant.cs | 5 +- Runtime/Scripts/AntsNest.cs | 2 +- Runtime/Scripts/Food.cs | 2 +- Runtime/Scripts/Mouth.cs | 2 +- Runtime/Scripts/Odorant.cs | 2 +- Runtime/Scripts/Pheromone.cs | 2 +- Samples/Animation/AntWalkForward 1.anim | 473 ++++++++++++++++++ Samples/Animation/AntWalkForward 1.anim.meta | 8 + 29 files changed, 1009 insertions(+), 143 deletions(-) create mode 100644 CreatureControl/Editor/Scripts/AnimationEditor.cs create mode 100644 CreatureControl/Editor/Scripts/AnimationEditor.cs.meta create mode 100644 CreatureControl/Editor/Scripts/TargetLeg_Editor.cs create mode 100644 CreatureControl/Editor/Scripts/TargetLeg_Editor.cs.meta rename Documentation/{Ant2.md => Ant.md} (100%) rename Documentation/{Ant2.md.meta => Ant.md.meta} (100%) create mode 100644 Samples/Animation/AntWalkForward 1.anim create mode 100644 Samples/Animation/AntWalkForward 1.anim.meta diff --git a/CreatureControl/Editor/Scripts/AnimationEditor.cs b/CreatureControl/Editor/Scripts/AnimationEditor.cs new file mode 100644 index 0000000..56dcca0 --- /dev/null +++ b/CreatureControl/Editor/Scripts/AnimationEditor.cs @@ -0,0 +1,117 @@ +using System.IO; +using UnityEditor; +using UnityEngine; +using System.Collections.Generic; + +public class AnimationEditor { + [MenuItem("Assets/Scale Animation Transforms...", true)] + private static bool ValidateScaleMenu() { + // enable only when an AnimationClip is selected + return Selection.objects != null && Selection.objects.Length > 0 && System.Array.Exists(Selection.objects, o => o is AnimationClip); + } + + [MenuItem("Assets/Scale Animation Transforms...")] + private static void ScaleSelectedClips() { + // default scale - you can change or prompt + float scale = 2.0f; + + var clips = new List(); + foreach (var o in Selection.objects) + if (o is AnimationClip clip) + clips.Add(clip); + + if (clips.Count == 0) { + EditorUtility.DisplayDialog("Scale Animation", "No AnimationClip selected.", "OK"); + return; + } + + if (!EditorUtility.DisplayDialog("Scale Animation", $"Scale translations in {clips.Count} clip(s) by {scale}?", "Yes", "No")) + return; + + foreach (AnimationClip clip in clips) { + ScaleClip(clip, scale); + } + + EditorUtility.DisplayDialog("Scale Animation", "Done scaling selected clips.", "OK"); + } + + public static void ScaleClip(AnimationClip clip, float scale, string saveFolder) { + string origPath = AssetDatabase.GetAssetPath(clip); + + string ext = Path.GetExtension(origPath); + string nameNoExt = Path.GetFileNameWithoutExtension(origPath); + string fileName = $"{nameNoExt}_scaled{ext}"; + string savePath = Path.Combine(saveFolder, fileName).Replace("\\", "/"); + + if (AssetDatabase.LoadAssetAtPath(savePath) != null) { + if (!AssetDatabase.DeleteAsset(savePath)) { + Debug.LogError($"Failed to delete existing asset at {savePath}"); + return; + } + Debug.Log($"Deleted old {savePath}"); + AssetDatabase.Refresh(); + } + + if (!AssetDatabase.CopyAsset(origPath, savePath)) { + Debug.LogError($"Failed to duplicate asset: {origPath} -> {savePath}"); + return; + } + + AssetDatabase.ImportAsset(savePath); + AnimationClip newClip = AssetDatabase.LoadAssetAtPath(savePath); + if (newClip == null) { + Debug.LogError($"Failed to load duplicated clip at: {savePath}"); + return; + } + ScaleClip(newClip, scale); + + } + + public static void ScaleClip(AnimationClip clip, float scale) { + // make editable copy if needed (if clip is in model import, make sure to duplicate or modify import settings) + Undo.RegisterCompleteObjectUndo(clip, "Scale Animation Translations"); + + // Collect curve bindings for position-like properties. + EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(clip); + foreach (EditorCurveBinding binding in bindings) { + string prop = binding.propertyName; + if (string.IsNullOrEmpty(prop)) + continue; + + // Identify position/localPosition/property patterns to scale: + // common property names: + // "m_LocalPosition.x", "m_LocalPosition.y", "m_LocalPosition.z" + // "localPosition.x", etc. or custom paths that animate transform.localPosition + // We'll scale any curve with "position" or "LocalPosition" in propertyName (case-insensitive). + + string lower = prop.ToLowerInvariant(); + bool isPos = + lower.Contains("m_localposition") || + lower.Contains("localposition") || + lower.Contains(".position") || + lower == "position.x" || lower == "position.y" || lower == "position.z"; + + if (!isPos) + continue; + + AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, binding); + if (curve == null) continue; + + // scale each keyframe value + Keyframe[] keys = curve.keys; + for (int i = 0; i < keys.Length; i++) { + Keyframe k = keys[i]; + k.value *= scale; + k.inTangent *= scale; + k.outTangent *= scale; + keys[i] = k; + } + + curve.keys = keys; + AnimationUtility.SetEditorCurve(clip, binding, curve); + } + + EditorUtility.SetDirty(clip); + AssetDatabase.SaveAssets(); + } +} \ No newline at end of file diff --git a/CreatureControl/Editor/Scripts/AnimationEditor.cs.meta b/CreatureControl/Editor/Scripts/AnimationEditor.cs.meta new file mode 100644 index 0000000..e0ff648 --- /dev/null +++ b/CreatureControl/Editor/Scripts/AnimationEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 60521eca66eefeadc8700de028cfc181 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/CreatureControl/Editor/Scripts/Creature_Editor.cs b/CreatureControl/Editor/Scripts/Creature_Editor.cs index e60705c..50151cf 100644 --- a/CreatureControl/Editor/Scripts/Creature_Editor.cs +++ b/CreatureControl/Editor/Scripts/Creature_Editor.cs @@ -1,7 +1,7 @@ using UnityEditor; using UnityEditor.SceneManagement; -namespace Passer.CreatureControl { +namespace CreatureControl { [CustomEditor(typeof(Creature), true)] public class Creature_Editor : Editor { diff --git a/CreatureControl/Editor/Scripts/Insect/InsectRig_Editor.cs b/CreatureControl/Editor/Scripts/Insect/InsectRig_Editor.cs index 519c9fc..2c77f04 100644 --- a/CreatureControl/Editor/Scripts/Insect/InsectRig_Editor.cs +++ b/CreatureControl/Editor/Scripts/Insect/InsectRig_Editor.cs @@ -1,13 +1,23 @@ -using UnityEngine; using UnityEditor; -namespace Passer.CreatureControl { +namespace CreatureControl { + [CustomEditor(typeof(InsectRig))] public class InsectRigEditor : Editor { SerializedProperty renderProp; void OnEnable() { + InsectRig insectRig = (InsectRig) target; + renderProp = serializedObject.FindProperty("render"); + + insectRig.legLength = float.PositiveInfinity; + foreach (TargetLeg leg in insectRig.legs) { + float legLength = leg.bones.length; + if (legLength > 0 && legLength < insectRig.legLength) + insectRig.legLength = legLength; + } + } public override void OnInspectorGUI() { @@ -40,4 +50,5 @@ namespace Passer.CreatureControl { } } + } \ No newline at end of file diff --git a/CreatureControl/Editor/Scripts/Insect/Insect_Editor.cs b/CreatureControl/Editor/Scripts/Insect/Insect_Editor.cs index e2a08d9..370896a 100644 --- a/CreatureControl/Editor/Scripts/Insect/Insect_Editor.cs +++ b/CreatureControl/Editor/Scripts/Insect/Insect_Editor.cs @@ -1,7 +1,9 @@ +using System.Collections.Generic; using UnityEditor; using UnityEngine; +using UnityEditor.Animations; -namespace Passer.CreatureControl { +namespace CreatureControl { [CustomEditor(typeof(Insect), true)] public class Insect_Editor : Creature_Editor { @@ -16,6 +18,46 @@ namespace Passer.CreatureControl { anythingChanged |= insect.CheckTargetRig("InsectRig"); insect.insectRig.MatchTo(insect, ref anythingChanged); + float prefabLegLength = 0.003f; + float modelLegLength = insect.insectRig.legLength; + float scale = prefabLegLength / modelLegLength; + Animator animator = insect.insectRig.GetComponent(); + + RuntimeAnimatorController rac = animator.runtimeAnimatorController; + if (rac == null) { + EditorUtility.DisplayDialog("No Controller", "Animator has no RuntimeAnimatorController assigned.", "OK"); + return; + } + + // Collect unique clips from controller, including BlendTree children + List clips = new(); + foreach (AnimationClip c in rac.animationClips) { + if (c != null && !clips.Contains(c)) + clips.Add(c); + } + + // Some clips referenced via AnimatorController layers/states (BlendTrees) may already be in animationClips, + // but to be thorough (and to access BlendTree children) we inspect the controller asset when possible. + string path = AssetDatabase.GetAssetPath(rac); + AnimatorController ac = AssetDatabase.LoadAssetAtPath(path); + if (ac != null) { + foreach (AnimatorControllerLayer layer in ac.layers) { + CollectFromStateMachine(layer.stateMachine, clips); + } + } + + if (clips.Count == 0) { + EditorUtility.DisplayDialog("No Clips", "No AnimationClips found on the controller.", "OK"); + return; + } + + if (insect.updateAnimations) { + AnimationEditor.ScaleClip(clips[0], scale, insect.animationsPath); + Debug.Log($"Scaled{clips[0].name} with {scale} and saved it to {insect.animationsPath}"); + } + else { + Debug.Log($"Did not scale {clips[0].name} with scale {scale} and save it to {insect.animationsPath}"); + } if (anythingChanged) { EditorUtility.SetDirty(creature); @@ -23,6 +65,33 @@ namespace Passer.CreatureControl { } } + + static void CollectFromStateMachine(AnimatorStateMachine sm, List outList) { + foreach (var state in sm.states) { + var motion = state.state.motion; + if (motion is AnimationClip clip) { + if (!outList.Contains(clip)) outList.Add(clip); + } + else if (motion is BlendTree bt) { + CollectFromBlendTree(bt, outList); + } + } + + foreach (var child in sm.stateMachines) + CollectFromStateMachine(child.stateMachine, outList); + } + + static void CollectFromBlendTree(BlendTree tree, List outList) { + foreach (var child in tree.children) { + if (child.motion is AnimationClip clip) { + if (!outList.Contains(clip)) outList.Add(clip); + } + else if (child.motion is BlendTree bt) { + CollectFromBlendTree(bt, outList); + } + } + } + #region Inspector public override void OnInspectorGUI() { @@ -38,6 +107,18 @@ namespace Passer.CreatureControl { static bool showTargets; private void TargetsInspector() { + bool configurationIncomplete = false; + if (!insect.leftFrontLeg.isConfigured || + !insect.leftMiddleLeg.isConfigured || + !insect.leftHindLeg.isConfigured || + !insect.rightFrontLeg.isConfigured || + !insect.rightMiddleLeg.isConfigured || + !insect.rightHindLeg.isConfigured) { + + showTargets = true; + configurationIncomplete = true; + } + GUIContent text = new( "Targets", "The target transforms controlling the body parts" @@ -46,7 +127,9 @@ namespace Passer.CreatureControl { if (showTargets) { EditorGUI.indentLevel++; - + if (configurationIncomplete) { + EditorGUILayout.HelpBox("Not all legs are configured", MessageType.Warning); + } SerializedProperty leftFrontLegProp = serializedObject.FindProperty(nameof(Insect.leftFrontLeg)); Leg_Editor.Inspector(leftFrontLegProp); SerializedProperty leftMiddleLegProp = serializedObject.FindProperty(nameof(Insect.leftMiddleLeg)); @@ -67,18 +150,25 @@ namespace Passer.CreatureControl { private void AnimatorInspector() { GUIContent text = new( - "Animator", - "Standard Unity Animator Controller for animating the character" + "Animator Controller", + "Unity Animator Controller for animating the character" ); SerializedProperty targetRigProp = serializedObject.FindProperty(nameof(Insect.targetRig)); if (targetRigProp == null) return; - SerializedObject targetRigObj = new(targetRigProp.objectReferenceValue); + TargetRig targetRig = targetRigProp.objectReferenceValue as TargetRig; + Animator animator = targetRig.GetComponent(); + if (animator == null) + return; - SerializedProperty animatorControllerProp = targetRigObj.FindProperty(nameof(InsectRig.animator)); - animatorControllerProp.objectReferenceValue = (Animator)EditorGUILayout.ObjectField(text, animatorControllerProp.objectReferenceValue, typeof(Animator), true); + SerializedObject animatorObj = new(animator); + + SerializedProperty animatorControllerProp = animatorObj.FindProperty("m_Controller"); + animatorControllerProp.objectReferenceValue = + (RuntimeAnimatorController)EditorGUILayout.ObjectField(text, animatorControllerProp.objectReferenceValue, typeof(RuntimeAnimatorController), true); + animatorObj.ApplyModifiedProperties(); EditorGUI.indentLevel++; ForwardSpeedInspector(); @@ -93,7 +183,7 @@ namespace Passer.CreatureControl { ); SerializedProperty forwardSpeedProp = serializedObject.FindProperty(nameof(Insect.forwardSpeed)); - forwardSpeedProp.floatValue = EditorGUILayout.FloatField(text, forwardSpeedProp.floatValue); + forwardSpeedProp.floatValue = EditorGUILayout.FloatField(text, forwardSpeedProp.floatValue); } private void RotationSpeedInspector() { @@ -103,7 +193,7 @@ namespace Passer.CreatureControl { ); SerializedProperty rotationSpeedProp = serializedObject.FindProperty(nameof(Insect.rotationSpeed)); - rotationSpeedProp.floatValue = EditorGUILayout.FloatField(text, rotationSpeedProp.floatValue); + rotationSpeedProp.floatValue = EditorGUILayout.FloatField(text, rotationSpeedProp.floatValue); } #endregion Inspector diff --git a/CreatureControl/Editor/Scripts/Leg_Editor.cs b/CreatureControl/Editor/Scripts/Leg_Editor.cs index 20256d3..5f7cace 100644 --- a/CreatureControl/Editor/Scripts/Leg_Editor.cs +++ b/CreatureControl/Editor/Scripts/Leg_Editor.cs @@ -1,16 +1,12 @@ using UnityEditor; using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { public class Leg_Editor { - //private string label = ""; + private static bool showfield = false; - public void Enable() { - - } - public static void Inspector(SerializedProperty legProp) { GUIStyle foldoutStyle = new(EditorStyles.foldout) { margin = EditorStyles.objectField.margin @@ -45,6 +41,7 @@ namespace Passer.CreatureControl { EditorGUI.indentLevel++; tibiaProp.objectReferenceValue = (Transform)EditorGUILayout.ObjectField("Lower Leg", tibiaProp.objectReferenceValue, typeof(Transform), true); tarsusProp.objectReferenceValue = (Transform)EditorGUILayout.ObjectField("Foot", tarsusProp.objectReferenceValue, typeof(Transform), true); + // Need to check if anythingChanged and update the projection if it did EditorGUI.indentLevel--; } } diff --git a/CreatureControl/Editor/Scripts/TargetLeg_Editor.cs b/CreatureControl/Editor/Scripts/TargetLeg_Editor.cs new file mode 100644 index 0000000..9886259 --- /dev/null +++ b/CreatureControl/Editor/Scripts/TargetLeg_Editor.cs @@ -0,0 +1,44 @@ +using UnityEngine; +using UnityEditor; + +namespace CreatureControl { + + [CustomEditor(typeof(TargetLeg))] + public class TargetLeg_Editor : Editor { + + protected TargetLeg targetLeg; + + private void OnEnable() { + targetLeg = (TargetLeg)target; + CheckLegTarget(targetLeg); + } + + void CheckLegTarget(TargetLeg targetLeg) { + LegTarget legTarget = targetLeg.target.GetComponent(); + if (legTarget == null) + legTarget = targetLeg.target.gameObject.AddComponent(); + legTarget.leg = targetLeg; + + } + + public override void OnInspectorGUI() { + base.OnInspectorGUI(); + + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.FloatField("Femur Length", targetLeg.bones.femurLength); + EditorGUI.EndDisabledGroup(); + } + + public float PrefabFemurLength() { + Object prefabSource = PrefabUtility.GetCorrespondingObjectFromSource(serializedObject.targetObject); + if (prefabSource == null) + return 0; + + SerializedObject targetLegPrefabObj = new(prefabSource); + SerializedProperty targetBonesPrefabProp = targetLegPrefabObj.FindProperty(nameof(TargetLeg.bones)); + + return 0; + } + } + +} \ No newline at end of file diff --git a/CreatureControl/Editor/Scripts/TargetLeg_Editor.cs.meta b/CreatureControl/Editor/Scripts/TargetLeg_Editor.cs.meta new file mode 100644 index 0000000..02da72b --- /dev/null +++ b/CreatureControl/Editor/Scripts/TargetLeg_Editor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c107e681ddd2a9ae833061e44e8a7d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/CreatureControl/Runtime/Scripts/Creature.cs b/CreatureControl/Runtime/Scripts/Creature.cs index b2a7f85..019f022 100644 --- a/CreatureControl/Runtime/Scripts/Creature.cs +++ b/CreatureControl/Runtime/Scripts/Creature.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { public class Creature : MonoBehaviour { /// @@ -24,6 +24,7 @@ namespace Passer.CreatureControl { public Quaternion targetToModelRotation; public Animator animator; + public string animationsPath = "Assets"; /// /// The maximum height of objects from the ground which do not stop the creature diff --git a/CreatureControl/Runtime/Scripts/Insect/Insect.cs b/CreatureControl/Runtime/Scripts/Insect/Insect.cs index c9e7fca..f798ea8 100644 --- a/CreatureControl/Runtime/Scripts/Insect/Insect.cs +++ b/CreatureControl/Runtime/Scripts/Insect/Insect.cs @@ -1,5 +1,8 @@ -namespace Passer.CreatureControl { +namespace CreatureControl { + /// + /// A creature with six legs + /// public class Insect : Creature { public InsectRig insectRig; @@ -13,7 +16,9 @@ namespace Passer.CreatureControl { public Leg rightFrontLeg; public Leg rightMiddleLeg; - public Leg rightHindLeg; + public Leg rightHindLeg; + + public bool updateAnimations = false; #region Init diff --git a/CreatureControl/Runtime/Scripts/Insect/InsectRig.cs b/CreatureControl/Runtime/Scripts/Insect/InsectRig.cs index a89fe96..64a2800 100644 --- a/CreatureControl/Runtime/Scripts/Insect/InsectRig.cs +++ b/CreatureControl/Runtime/Scripts/Insect/InsectRig.cs @@ -1,19 +1,58 @@ +using System.Collections.Generic; using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { - // An insect target rig.... + /// + /// A rig or skeleton for a six-legged insect + /// public class InsectRig : TargetRig { + /// + /// The left front leg + /// public TargetLeg leftFrontLeg; + /// + /// The left middle leg + /// public TargetLeg leftMiddleLeg; + /// + /// The left hind leg + /// public TargetLeg leftBackLeg; + /// + /// The right front leg + /// public TargetLeg rightFrontLeg; + /// + /// The right middle leg + /// public TargetLeg rightMiddleLeg; + /// + /// The right hindLeg + /// public TargetLeg rightBackLeg; + private TargetLeg[] _legs; + public TargetLeg[] legs { + get { + if (_legs == null) { + _legs = new TargetLeg[6]; + _legs[0] = leftFrontLeg; + _legs[1] = leftMiddleLeg; + _legs[2] = leftBackLeg; + _legs[3] = rightFrontLeg; + _legs[4] = rightMiddleLeg; + _legs[5] = rightBackLeg; + } + return _legs; + } + } + public bool render; + public float legLength; // smalled leg length + public override void Pose() { this.leftBackLeg.PoseLimb(); this.leftMiddleLeg.PoseLimb(); @@ -43,7 +82,6 @@ namespace Passer.CreatureControl { this.rightBackLeg.MatchTo(insect.rightHindLeg); } - // Public helper you can call from editor or runtime public void ApplyRenderToChildren(bool value) { // Find all renderers under this GameObject (including inactive) var renderers = GetComponentsInChildren(true); diff --git a/CreatureControl/Runtime/Scripts/Leg.cs b/CreatureControl/Runtime/Scripts/Leg.cs index 8940f64..cad5e56 100644 --- a/CreatureControl/Runtime/Scripts/Leg.cs +++ b/CreatureControl/Runtime/Scripts/Leg.cs @@ -1,8 +1,44 @@ using UnityEngine; -[System.Serializable] -public class Leg { - public Transform femur; // UpperLeg, Thigh - public Transform tibia; // LowerLeg, Shank - public Transform tarsus; // Foot +namespace CreatureControl { + + /// + /// A leg of a creature + /// + [System.Serializable] + public class Leg { + /// + /// The upper leg or thigh bone + /// + public Transform femur; + /// + /// The lower leg or shank bone + /// + public Transform tibia; + /// + /// The foot bone + /// + public Transform tarsus; + + [SerializeField] + private float _femurLength; + public float femurLength { + get { + if (_femurLength <= 0) + _femurLength = Vector3.Distance(this.femur.position, this.tibia.position); + return _femurLength; + } + } + // A bit inefficient is this is used a lot... + public float tibiaLength => Vector3.Distance(this.tibia.position, this.tarsus.position); + public float length => femurLength + tibiaLength; + + + /// + /// Check if all bones of the legs have been configured + /// + /// True when all bones are configured + public bool isConfigured => femur != null && tibia != null && tarsus != null; + } + } \ No newline at end of file diff --git a/CreatureControl/Runtime/Scripts/LegTarget.cs b/CreatureControl/Runtime/Scripts/LegTarget.cs index 4710f60..003096b 100644 --- a/CreatureControl/Runtime/Scripts/LegTarget.cs +++ b/CreatureControl/Runtime/Scripts/LegTarget.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { public class LegTarget : MonoBehaviour { public TargetLeg leg; diff --git a/CreatureControl/Runtime/Scripts/TargetLeg.cs b/CreatureControl/Runtime/Scripts/TargetLeg.cs index 5a7f9b4..69dff5a 100644 --- a/CreatureControl/Runtime/Scripts/TargetLeg.cs +++ b/CreatureControl/Runtime/Scripts/TargetLeg.cs @@ -1,83 +1,60 @@ using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { + /// + /// A leg in a TargetRig which is used to control a leg in a model + /// [System.Serializable] public class TargetLeg : MonoBehaviour { - public Transform femurTarget; // UpperLeg, Thigh - public Transform tibiaTarget; // LowerLeg, Shank - public Transform tarsusTarget; // Foot + public Leg bones; public Transform target; // for the tarsus - protected LegTarget legTarget; public Quaternion targetToBoneFemur; public Quaternion targetToBoneTibia; - public float femurLength; - public float tibiaLength; - public float length; - - /// - /// Update the lenghts of the leg bones - /// - private void CalculateLengths() { - this.femurLength = Vector3.Distance(this.femurTarget.position, this.tibiaTarget.position); - this.tibiaLength = Vector3.Distance(this.tibiaTarget.position, this.tarsusTarget.position); - this.length = femurLength + tibiaLength; - } - public void MatchTo(Leg leg) { - this.femurTarget.position = leg.femur.position; - this.tibiaTarget.position = leg.tibia.position; - this.tarsusTarget.position = leg.tarsus.position; + if (this.bones.femur == null || this.bones.tibia == null || this.bones.tarsus == null) + return; + if (leg.femur == null || leg.tibia == null || leg.tarsus == null) + return; + + this.bones.femur.position = leg.femur.position; + this.bones.tibia.position = leg.tibia.position; + this.bones.tarsus.position = leg.tarsus.position; + targetToBoneFemur = TargetRig.TargetToBoneRotation(leg.femur, leg.tibia); targetToBoneTibia = TargetRig.TargetToBoneRotation(leg.tibia, leg.tarsus); - CalculateLengths(); + float modelLegLength = leg.length; + float targetLegLength = this.bones.length; + Debug.Log($"model: {modelLegLength} rig: {targetLegLength}"); // Put the end-effector target for IK in a sensible place - Vector3 legDirection = (this.tarsusTarget.position - this.femurTarget.position).normalized; - Vector3 targetPosition = this.femurTarget.position + 0.7f * this.length * legDirection.normalized; + Vector3 legDirection = (this.bones.tarsus.position - this.bones.femur.position).normalized; + Vector3 targetPosition = this.bones.femur.position + 0.7f * this.bones.length * legDirection.normalized; Quaternion targetRotation = Quaternion.LookRotation(legDirection); this.target.SetPositionAndRotation(targetPosition, targetRotation); this.target.localPosition = new(this.target.localPosition.x, 0, this.target.localPosition.z); } - public virtual void OnDrawGizmosSelected() { - if (this.enabled == false) - return; - - if (target != null && legTarget == null) { - legTarget = target.GetComponent(); - if (legTarget == null) - legTarget = target.gameObject.AddComponent(); - legTarget.leg = this; - } - - Gizmos.color = Color.white; - if (this.femurTarget != null && this.tibiaTarget != null) - Gizmos.DrawLine(this.femurTarget.position, this.tibiaTarget.position); - if (tibiaTarget != null && this.tarsusTarget != null) - Gizmos.DrawLine(this.tibiaTarget.position, this.tarsusTarget.position); - - PoseLimb(); - } - /// /// Pose the target limb /// public void PoseLimb() { if (target == null) return; + if (bones.femur == null || bones.tibia == null || bones.tarsus == null) + return; Quaternion femurOrientation = FemurRotation(target.position); Quaternion tibiaOrientation = TibiaRotation(target.position); Quaternion tarsusOrientation = TarsusRotation(target.rotation); - femurTarget.rotation = femurOrientation; - tibiaTarget.rotation = tibiaOrientation; - tarsusTarget.rotation = tarsusOrientation; + bones.femur.rotation = femurOrientation; + bones.tibia.rotation = tibiaOrientation; + bones.tarsus.rotation = tarsusOrientation; } public void UpdateBones(Leg leg) { @@ -86,14 +63,14 @@ namespace Passer.CreatureControl { } protected Quaternion FemurRotation(Vector3 targetPosition) { - if (this.femurTarget == null || this.tibiaTarget == null || this.tarsusTarget == null) + if (this.bones.femur == null || this.bones.tibia == null || this.bones.tarsus == null) return Quaternion.identity; - Vector3 toTarget = targetPosition - this.femurTarget.position; + Vector3 toTarget = targetPosition - this.bones.femur.position; // Debug.DrawRay(femur.position, toTarget, Color.magenta); float targetDistance = toTarget.magnitude; - float femurLength = Vector3.Distance(this.femurTarget.position, this.tibiaTarget.position); - float tibiaLength = Vector3.Distance(this.tibiaTarget.position, this.tarsusTarget.position); + float femurLength = Vector3.Distance(this.bones.femur.position, this.bones.tibia.position); + float tibiaLength = Vector3.Distance(this.bones.tibia.position, this.bones.tarsus.position); float hipAngle = CosineRule(targetDistance, femurLength, tibiaLength); // NaN happens when the distance to the footTarget is longer than the length of the leg @@ -110,10 +87,10 @@ namespace Passer.CreatureControl { } protected Quaternion TibiaRotation(Vector3 targetPosition) { - if (this.tibiaTarget == null) + if (this.bones.tibia == null) return Quaternion.identity; - Vector3 directionToTarget = targetPosition - this.tibiaTarget.position; + Vector3 directionToTarget = targetPosition - this.bones.tibia.position; Quaternion tibiaOrientation = Quaternion.LookRotation(directionToTarget, Vector3.up); // femur.up); return tibiaOrientation; // In world space @@ -124,17 +101,17 @@ namespace Passer.CreatureControl { } public void UpdateFemur(Transform femurBone) { - if (femurBone == null || this.femurTarget == null) + if (femurBone == null || this.bones.femur == null) return; - femurBone.rotation = this.femurTarget.rotation * targetToBoneFemur; + femurBone.rotation = this.bones.femur.rotation * targetToBoneFemur; } public void UpdateTibia(Transform tibiaBone) { - if (tibiaBone == null || this.tibiaTarget == null) + if (tibiaBone == null || this.bones.tibia == null) return; - tibiaBone.rotation = this.tibiaTarget.rotation * targetToBoneTibia; + tibiaBone.rotation = this.bones.tibia.rotation * targetToBoneTibia; } #region Math @@ -151,6 +128,23 @@ namespace Passer.CreatureControl { } #endregion Math + + #region Scene + + public virtual void OnDrawGizmosSelected() { + if (this.enabled == false) + return; + + Gizmos.color = Color.white; + if (this.bones.femur != null && this.bones.tibia != null) + Gizmos.DrawLine(this.bones.femur.position, this.bones.tibia.position); + if (bones.tibia != null && this.bones.tarsus != null) + Gizmos.DrawLine(this.bones.tibia.position, this.bones.tarsus.position); + + PoseLimb(); + } + + #endregion Scene } } \ No newline at end of file diff --git a/CreatureControl/Runtime/Scripts/TargetRig.cs b/CreatureControl/Runtime/Scripts/TargetRig.cs index 0232505..23452e7 100644 --- a/CreatureControl/Runtime/Scripts/TargetRig.cs +++ b/CreatureControl/Runtime/Scripts/TargetRig.cs @@ -1,14 +1,11 @@ using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { /// - /// A target rig for a creature + /// A target rig or skeleton for a creature /// public class TargetRig : MonoBehaviour { - - public Animator animator; - /// /// Pose the target rig using the IK targets /// diff --git a/Documentation/Animations.md b/Documentation/Animations.md index e014d71..f292b09 100644 --- a/Documentation/Animations.md +++ b/Documentation/Animations.md @@ -1,9 +1,37 @@ Animations ========== -The NanoBrain Ant comes with walking animations and an animator. These can be used with any hexapod model but as the rigs of these hexapods can be very different[1](#notes-1) our software provides an animation projection to solve this. H2O +The NanoBrain [Ant](#CreatureControl.Ant) comes with walking animations and an animator. These can be used with any insect model but as the rigs of these hexapods can be very different[1](#notes-1) our software provides an animation projection to solve this. -Notes -===== +The animations are designed to work with the InsectTargetRig found in `Runtime/Resources`. When this is used with any other insect model, you will probably see only root motion and no leg movement. This is because there is no mapping from the animation to the bones in the rig of that model. + +If you want to use the animations on a different insect model, you should place the +[Insect component](#CreatureControl.Insect)[2](#notes-2) + on that model and assign the animator contoller to the `Animator Controller` parameter. *Do not* assign the animator to the Controller parameter of the models Animator component! Note that you probably also need to [configure the leg bones of the model](Models.md#custom-models). + +Animators +--------- +The package provides an animator In `Samples/Animation` called AntAnimator3. This provides a full 3 Degrees-of-Freedom walking with the following parameters: +- Forward: Forward/backward walking +- Rotate: Rotate left/right +- Strafe: Move sideward left/right +The corresponding animations will be blended together in a resulting walking animation. + +The [Ant component](#CreatureControl.Ant) only uses the Forward and Rotate parameters to move the ant. + +Animations +---------- +The package provides different walking animations, found in `Samples/Animation`: +- AntIdle: No movement +- AntWalkForward: Forward walking, can be reversed to backward walking +- AntWalkLeft: Left sideward walking +- AntWalkRight: Right sideward walking +- AntRotateLeft: Anti-clockwise turning on the spot +- AntRotateRight: Clockwise turning on the spot + +These animations are blended by the AntAnimator3 to enable all possible walking movements. + + +### Notes 1. The animation retargeting of Unity's Mecanim only works for Humanoid models. -2. bla bla \ No newline at end of file +2. or any other component derived from [Insect](#CreatureControl.Insect) \ No newline at end of file diff --git a/Documentation/Ant2.md b/Documentation/Ant.md similarity index 100% rename from Documentation/Ant2.md rename to Documentation/Ant.md diff --git a/Documentation/Ant2.md.meta b/Documentation/Ant.md.meta similarity index 100% rename from Documentation/Ant2.md.meta rename to Documentation/Ant.md.meta diff --git a/Documentation/Models.md b/Documentation/Models.md index 2fff92d..66baf5f 100644 --- a/Documentation/Models.md +++ b/Documentation/Models.md @@ -3,4 +3,14 @@ Models The package comes with a number of models which can be found in the [Samples][1] folder. These models are rigged and can be used in combination with the [Animations](Animations.md). -[1]: Installation.md (How to install the Samples) \ No newline at end of file +Custom Models +------------- +To use custom insect models, the [Insect component](#CreatureControl.Insect)[2](#notes-2) should be added to the model. +Additionally, the leg bones of the insect should be configured as the package is not able to find these automatically. +In most cases, only the upper leg bone (the femur) need to be configures, the lower leg (tibia) and foot (tarsus) bones are then assumed to be the descendant bones of the femur if those bones have only one child bone each. If this approach does not work, it is always possible to override the identified bones by manually replacing them by the correct bone. + +#### Notes + + +[1]: Installation.md (How to install the Samples) +2. or any other component derived from the Insect component \ No newline at end of file diff --git a/Editor/Scripts/Ant_Editor.cs b/Editor/Scripts/Ant_Editor.cs index f954a68..72b5f76 100644 --- a/Editor/Scripts/Ant_Editor.cs +++ b/Editor/Scripts/Ant_Editor.cs @@ -1,7 +1,7 @@ using UnityEditor; using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { [CustomEditor(typeof(Ant))] public class Ant_Editor : Insect_Editor { diff --git a/Runtime/Resources/InsectTargetRig.prefab b/Runtime/Resources/InsectTargetRig.prefab index 945feb8..e2de42f 100644 --- a/Runtime/Resources/InsectTargetRig.prefab +++ b/Runtime/Resources/InsectTargetRig.prefab @@ -77,15 +77,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f3394e8da3685a263901c13e2a231279, type: 3} m_Name: m_EditorClassIdentifier: - femurTarget: {fileID: 2087731612450819825} - tibiaTarget: {fileID: 7566832081299524197} - tarsusTarget: {fileID: 7011186323915432702} + bones: + femur: {fileID: 2087731612450819825} + tibia: {fileID: 7566832081299524197} + tarsus: {fileID: 7011186323915432702} + _femurLength: 0.004816547 target: {fileID: 8947192729555298471} targetToBoneFemur: {x: 0, y: 0, z: 0, w: 0} targetToBoneTibia: {x: 0, y: 0, z: 0, w: 0} - femurLength: 0 - tibiaLength: 0 - length: 0 --- !u!1 &714113386832462525 GameObject: m_ObjectHideFlags: 0 @@ -138,7 +137,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a25e8575da1d1cba48dc2b8da7a2b0ab, type: 3} m_Name: m_EditorClassIdentifier: - animator: {fileID: 5843436816833865534} leftFrontLeg: {fileID: 5655676289343650514} leftMiddleLeg: {fileID: 6327345715726789984} leftBackLeg: {fileID: 3124099709297356894} @@ -146,6 +144,7 @@ MonoBehaviour: rightMiddleLeg: {fileID: 4196034226083389076} rightBackLeg: {fileID: 8323677930838830493} render: 0 + legLength: 0.009770508 --- !u!95 &5843436816833865534 Animator: serializedVersion: 5 @@ -156,7 +155,7 @@ Animator: m_GameObject: {fileID: 714113386832462525} m_Enabled: 1 m_Avatar: {fileID: 0} - m_Controller: {fileID: 9100000, guid: d4b9f32bef604abd5953647ad53ca0f7, type: 2} + m_Controller: {fileID: 9100000, guid: ba169e741a830f910bdde9e04f7c88f4, type: 2} m_CullingMode: 0 m_UpdateMode: 0 m_ApplyRootMotion: 1 @@ -243,15 +242,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f3394e8da3685a263901c13e2a231279, type: 3} m_Name: m_EditorClassIdentifier: - femurTarget: {fileID: 976560727556484423} - tibiaTarget: {fileID: 3873135409852464941} - tarsusTarget: {fileID: 3355004770557811387} + bones: + femur: {fileID: 976560727556484423} + tibia: {fileID: 3873135409852464941} + tarsus: {fileID: 3355004770557811387} + _femurLength: 0.003806679 target: {fileID: 2041764967651498327} targetToBoneFemur: {x: 0, y: 0, z: 0, w: 0} targetToBoneTibia: {x: 0, y: 0, z: 0, w: 0} - femurLength: 0 - tibiaLength: 0 - length: 0 --- !u!1 &1274558016778403244 GameObject: m_ObjectHideFlags: 0 @@ -512,15 +510,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f3394e8da3685a263901c13e2a231279, type: 3} m_Name: m_EditorClassIdentifier: - femurTarget: {fileID: 7879963364189984297} - tibiaTarget: {fileID: 8557148899078362646} - tarsusTarget: {fileID: 2520372565419969361} + bones: + femur: {fileID: 7879963364189984297} + tibia: {fileID: 8557148899078362646} + tarsus: {fileID: 2520372565419969361} + _femurLength: 0.006008031 target: {fileID: 5692380185316106944} targetToBoneFemur: {x: 0, y: 0, z: 0, w: 0} targetToBoneTibia: {x: 0, y: 0, z: 0, w: 0} - femurLength: 0 - tibiaLength: 0 - length: 0 --- !u!1 &1713014906338526394 GameObject: m_ObjectHideFlags: 0 @@ -1198,15 +1195,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f3394e8da3685a263901c13e2a231279, type: 3} m_Name: m_EditorClassIdentifier: - femurTarget: {fileID: 1138231466888029713} - tibiaTarget: {fileID: 6229249450306020558} - tarsusTarget: {fileID: 3473835942814004862} + bones: + femur: {fileID: 1138231466888029713} + tibia: {fileID: 6229249450306020558} + tarsus: {fileID: 3473835942814004862} + _femurLength: 0.0031432603 target: {fileID: 2714894253296331867} targetToBoneFemur: {x: 0, y: 0, z: 0, w: 0} targetToBoneTibia: {x: 0, y: 0, z: 0, w: 0} - femurLength: 0 - tibiaLength: 0 - length: 0 --- !u!1 &6227205784071755847 GameObject: m_ObjectHideFlags: 0 @@ -1316,15 +1312,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f3394e8da3685a263901c13e2a231279, type: 3} m_Name: m_EditorClassIdentifier: - femurTarget: {fileID: 5158943779127512027} - tibiaTarget: {fileID: 5102382635668602733} - tarsusTarget: {fileID: 5832494694235077857} + bones: + femur: {fileID: 5158943779127512027} + tibia: {fileID: 5102382635668602733} + tarsus: {fileID: 5832494694235077857} + _femurLength: 0.004816545 target: {fileID: 8660658904332009209} targetToBoneFemur: {x: 0, y: 0, z: 0, w: 0} targetToBoneTibia: {x: 0, y: 0, z: 0, w: 0} - femurLength: 0 - tibiaLength: 0 - length: 0 --- !u!1 &6934656281848074513 GameObject: m_ObjectHideFlags: 0 @@ -1885,15 +1880,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: f3394e8da3685a263901c13e2a231279, type: 3} m_Name: m_EditorClassIdentifier: - femurTarget: {fileID: 7827425323228862897} - tibiaTarget: {fileID: 8607306932134183899} - tarsusTarget: {fileID: 5350519918537018444} + bones: + femur: {fileID: 7827425323228862897} + tibia: {fileID: 8607306932134183899} + tarsus: {fileID: 5350519918537018444} + _femurLength: 0.00380668 target: {fileID: 5063380583403966759} targetToBoneFemur: {x: 0, y: 0, z: 0, w: 0} targetToBoneTibia: {x: 0, y: 0, z: 0, w: 0} - femurLength: 0 - tibiaLength: 0 - length: 0 --- !u!1 &9173392299445808517 GameObject: m_ObjectHideFlags: 0 diff --git a/Runtime/Scripts/Ant.cs b/Runtime/Scripts/Ant.cs index 6c9f875..628967e 100644 --- a/Runtime/Scripts/Ant.cs +++ b/Runtime/Scripts/Ant.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using UnityEngine; using NanoBrain; -namespace Passer.CreatureControl { +namespace CreatureControl { /// /// Simulated ant using a NanoBrain @@ -58,8 +58,9 @@ namespace Passer.CreatureControl { protected override void Awake() { base.Awake(); + if (this.targetRig != null) - this.animator = this.targetRig.animator; + this.animator = this.targetRig.GetComponent(); this.nanoBrain = GetComponentInChildren(); } diff --git a/Runtime/Scripts/AntsNest.cs b/Runtime/Scripts/AntsNest.cs index 841dfe0..f32aa22 100644 --- a/Runtime/Scripts/AntsNest.cs +++ b/Runtime/Scripts/AntsNest.cs @@ -1,7 +1,7 @@ using System.Collections; using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { public class AntsNest : Odorant { public Ant antPrefab; diff --git a/Runtime/Scripts/Food.cs b/Runtime/Scripts/Food.cs index 2d4c443..2fd366f 100644 --- a/Runtime/Scripts/Food.cs +++ b/Runtime/Scripts/Food.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { public class Food : Odorant { diff --git a/Runtime/Scripts/Mouth.cs b/Runtime/Scripts/Mouth.cs index 1d70517..80e6ac9 100644 --- a/Runtime/Scripts/Mouth.cs +++ b/Runtime/Scripts/Mouth.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using UnityEngine; using NanoBrain; -namespace Passer.CreatureControl { +namespace CreatureControl { public class Mouth : MonoBehaviour { public GameObject foodPrefab; diff --git a/Runtime/Scripts/Odorant.cs b/Runtime/Scripts/Odorant.cs index 3008e0d..0046e4f 100644 --- a/Runtime/Scripts/Odorant.cs +++ b/Runtime/Scripts/Odorant.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { public class Odorant : MonoBehaviour { public float strength = 1; diff --git a/Runtime/Scripts/Pheromone.cs b/Runtime/Scripts/Pheromone.cs index 3dd260f..cf162bc 100644 --- a/Runtime/Scripts/Pheromone.cs +++ b/Runtime/Scripts/Pheromone.cs @@ -1,6 +1,6 @@ using UnityEngine; -namespace Passer.CreatureControl { +namespace CreatureControl { public class Pheromone : Odorant { public float duration = 30; // seconds diff --git a/Samples/Animation/AntWalkForward 1.anim b/Samples/Animation/AntWalkForward 1.anim new file mode 100644 index 0000000..6f0b52f --- /dev/null +++ b/Samples/Animation/AntWalkForward 1.anim @@ -0,0 +1,473 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: AntWalkForward 1 + serializedVersion: 7 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: {x: 0, y: 0, z: 0} + inSlope: {x: 0, y: 0, z: -0.0096} + outSlope: {x: 0, y: 0, z: -0.0096} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 0.41666666 + value: {x: 0, y: 0, z: -0.004} + inSlope: {x: 0, y: -0, z: -0.0096} + outSlope: {x: 0, y: 0.0096, z: 0.0096} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 0.8333333 + value: {x: 0, y: 0.004, z: -4.656613e-10} + inSlope: {x: 0, y: 0, z: 0.009599999} + outSlope: {x: 0, y: 0, z: 0.009599999} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.25 + value: {x: 0, y: 0, z: 0.004} + inSlope: {x: 0, y: 0, z: 0.0096} + outSlope: {x: 0, y: 0, z: -0.009600001} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.6666666 + value: {x: 0, y: 0, z: 0} + inSlope: {x: 0, y: 0, z: -0.009600001} + outSlope: {x: 0, y: 0, z: -0.009600001} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + path: Body/LeftFeetTarget + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: {x: 0, y: 0.004, z: 0} + inSlope: {x: 0, y: 0, z: 0.0096} + outSlope: {x: 0, y: 0, z: 0.0096} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 0.41666666 + value: {x: 0, y: 0, z: 0.004} + inSlope: {x: 0, y: -0.0096, z: 0.0096} + outSlope: {x: 0, y: 0, z: -0.0096} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.25 + value: {x: 0, y: 0, z: -0.004} + inSlope: {x: 0, y: -0, z: -0.0096} + outSlope: {x: 0, y: 0.009600001, z: 0.009600001} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.6666666 + value: {x: 0, y: 0.004, z: 0} + inSlope: {x: 0, y: 0, z: 0.009600001} + outSlope: {x: 0, y: 0, z: 0.009600001} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + path: Body/RightFeetTarget + - curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: {x: 0, y: 0, z: 0} + inSlope: {x: 0, y: 0, z: 0.0096} + outSlope: {x: 0, y: 0, z: 0.0096} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + - serializedVersion: 3 + time: 1.6666666 + value: {x: 0, y: 0, z: 0.016} + inSlope: {x: 0, y: 0, z: 0.0096} + outSlope: {x: 0, y: 0, z: 0.0096} + tangentMode: 0 + weightedMode: 0 + inWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + outWeight: {x: 0.33333334, y: 0.33333334, z: 0.33333334} + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + path: + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: [] + m_SampleRate: 24 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 683997697 + attribute: 1 + script: {fileID: 0} + typeID: 4 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 1250470035 + attribute: 1 + script: {fileID: 0} + typeID: 4 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + - serializedVersion: 2 + path: 0 + attribute: 1 + script: {fileID: 0} + typeID: 4 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1.6666666 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 1 + m_LoopBlend: 1 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: -0 + outSlope: 0.0096 + tangentMode: 69 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.8333333 + value: 0.004 + inSlope: 0 + outSlope: 0 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.25 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 65 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.6666666 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.y + path: Body/LeftFeetTarget + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: -0.0096 + outSlope: -0.0096 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: -0.004 + inSlope: -0.0096 + outSlope: 0.0096 + tangentMode: 69 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.25 + value: 0.004 + inSlope: 0.0096 + outSlope: -0.009600001 + tangentMode: 69 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.6666666 + value: 0 + inSlope: -0.009600001 + outSlope: -0.009600001 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.z + path: Body/LeftFeetTarget + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0.004 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0 + inSlope: -0.0096 + outSlope: 0 + tangentMode: 69 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.25 + value: 0 + inSlope: -0 + outSlope: 0.009600001 + tangentMode: 69 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.6666666 + value: 0.004 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.y + path: Body/RightFeetTarget + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0.0096 + outSlope: 0.0096 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 0.41666666 + value: 0.004 + inSlope: 0.0096 + outSlope: -0.0096 + tangentMode: 69 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.25 + value: -0.004 + inSlope: -0.0096 + outSlope: 0.009600001 + tangentMode: 69 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.6666666 + value: 0 + inSlope: 0.009600001 + outSlope: 0.009600001 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.z + path: Body/RightFeetTarget + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0.0096 + outSlope: 0.0096 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1.6666666 + value: 0.016 + inSlope: 0.0096 + outSlope: 0.0096 + tangentMode: 34 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.z + path: + classID: 4 + script: {fileID: 0} + flags: 0 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.x + path: + classID: 4 + script: {fileID: 0} + flags: 8 + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: m_LocalPosition.y + path: + classID: 4 + script: {fileID: 0} + flags: 8 + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 1 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/Samples/Animation/AntWalkForward 1.anim.meta b/Samples/Animation/AntWalkForward 1.anim.meta new file mode 100644 index 0000000..16f15af --- /dev/null +++ b/Samples/Animation/AntWalkForward 1.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c216474961242cb2ca482c52ec68c790 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: