123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- // Animancer // https://kybernetik.com.au/animancer // Copyright 2022 Kybernetik //
- #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value.
- using Unity.Collections;
- using UnityEngine;
- using UnityEngine.Animations;
- namespace Animancer.Examples.Jobs
- {
- /// <summary>An example of how to use Animation Jobs in Animancer to apply physics based damping to certain bones.</summary>
- ///
- /// <remarks>
- /// This example is based on Unity's
- /// <see href="https://github.com/Unity-Technologies/animation-jobs-samples">Animation Jobs Samples</see>.
- /// <para></para>
- /// This script sets up the job in place of
- /// <see href="https://github.com/Unity-Technologies/animation-jobs-samples/blob/master/Assets/animation-jobs-samples/Samples/Scripts/Damping/Damping.cs">
- /// Damping.cs</see>.
- /// <para></para>
- /// The <see cref="DampingJob"/> script is almost identical to the original
- /// <see href="https://github.com/Unity-Technologies/animation-jobs-samples/blob/master/Assets/animation-jobs-samples/Runtime/AnimationJobs/DampingJob.cs">
- /// DampingJob.cs</see>.
- /// <para></para>
- /// The <see href="https://learn.unity.com/tutorial/working-with-animation-rigging">Animation Rigging</see> package
- /// has a damping system which is likely better than this example.
- /// </remarks>
- ///
- /// <example><see href="https://kybernetik.com.au/animancer/docs/examples/jobs/damping">Damping</see></example>
- ///
- /// https://kybernetik.com.au/animancer/api/Animancer.Examples.Jobs/Damping
- ///
- [AddComponentMenu(Strings.ExamplesMenuPrefix + "Jobs - Damping")]
- [HelpURL(Strings.DocsURLs.ExampleAPIDocumentation + nameof(Jobs) + "/" + nameof(Damping))]
- public sealed class Damping : MonoBehaviour
- {
- /************************************************************************************************************************/
- [SerializeField] private AnimancerComponent _Animancer;
- [SerializeField] private Transform _EndBone;
- [SerializeField] private int _BoneCount = 1;
- /************************************************************************************************************************/
- private void Awake()
- {
- // Create the job and initialize all its arrays.
- // They are all Persistent because we want them to last for the full lifetime of the job.
- // Most of them can use UninitializedMemory which is faster because we will be immediately filling them.
- // But the velocities will use the default ClearMemory to make sure all the values start at zero.
- // Since we are about to use these values several times, we can shorten the following lines a bit by using constants:
- const Allocator Persistent = Allocator.Persistent;
- const NativeArrayOptions UninitializedMemory = NativeArrayOptions.UninitializedMemory;
- var job = new DampingJob()
- {
- jointHandles = new NativeArray<TransformStreamHandle>(_BoneCount, Persistent, UninitializedMemory),
- localPositions = new NativeArray<Vector3>(_BoneCount, Persistent, UninitializedMemory),
- localRotations = new NativeArray<Quaternion>(_BoneCount, Persistent, UninitializedMemory),
- positions = new NativeArray<Vector3>(_BoneCount, Persistent, UninitializedMemory),
- velocities = new NativeArray<Vector3>(_BoneCount, Persistent),
- };
- // Initialize the contents of the arrays for each bone.
- var animator = _Animancer.Animator;
- var bone = _EndBone;
- for (int i = _BoneCount - 1; i >= 0; i--)
- {
- job.jointHandles[i] = animator.BindStreamTransform(bone);
- job.localPositions[i] = bone.localPosition;
- job.localRotations[i] = bone.localRotation;
- job.positions[i] = bone.position;
- bone = bone.parent;
- }
- job.rootHandle = animator.BindStreamTransform(bone);
- // Add the job to Animancer's output.
- _Animancer.Playable.InsertOutputJob(job);
- // Make sure Animancer disposes the Native Arrays when it is destroyed so we don't leak memory.
- // If we were writing our own job rather than just using the sample, we could have it implement the
- // IDisposable interface to dispose its arrays so that we would only have to call ...Add(_Job); here.
- _Animancer.Playable.Disposables.Add(job.jointHandles);
- _Animancer.Playable.Disposables.Add(job.localPositions);
- _Animancer.Playable.Disposables.Add(job.localRotations);
- _Animancer.Playable.Disposables.Add(job.positions);
- _Animancer.Playable.Disposables.Add(job.velocities);
- }
- /************************************************************************************************************************/
- /// <summary>
- /// Ensures that the <see cref="_BoneCount"/> is positive and not larger than the number of bones between the
- /// <see cref="_EndBone"/> and the <see cref="Animator"/>.
- /// </summary>
- /// <remarks>Called in Edit Mode whenever this script is loaded or a value is changed in the Inspector.</remarks>
- private void OnValidate()
- {
- if (_BoneCount < 1)
- {
- _BoneCount = 1;
- }
- else if (_EndBone != null && _Animancer != null && _Animancer.Animator != null)
- {
- var root = _Animancer.Animator.transform;
- var bone = _EndBone;
- for (int i = 0; i < _BoneCount; i++)
- {
- bone = bone.parent;
- if (bone == root)
- {
- _BoneCount = i + 1;
- break;
- }
- else if (bone == null)
- {
- _EndBone = null;
- Debug.LogWarning("The End Bone must be a child of the Animator.");
- break;
- }
- }
- }
- }
- /************************************************************************************************************************/
- }
- }
|