Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Let us know a bit about your interests, and if you'd like to become more directly involved. Take our survey!
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  5. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Simple IdleWalkRunBlend Animation Job

Discussion in 'Animation' started by tarahugger, Jun 12, 2018.

  1. tarahugger

    tarahugger

    Joined:
    Jul 18, 2014
    Posts:
    53


    Code (CSharp):
    1. using Unity.Collections;
    2. using UnityEngine;
    3. using UnityEngine.Playables;
    4. using UnityEngine.Animations;
    5. using UnityEngine.Experimental.Animations;
    6.  
    7. public class IdleWalkRunBlend : MonoBehaviour
    8. {
    9.     private Animator Animator;
    10.  
    11.     [Range(0.0f, 1.0f)]
    12.     public float Forward;
    13.  
    14.     [Range(0.0f, 1.0f)]
    15.     public float WalkStart = 0.3f;
    16.  
    17.     [Range(0.0f, 1.0f)]
    18.     public float RunStart = 0.8f;
    19.  
    20.     NativeArray<TransformStreamHandle> m_Handles;
    21.     NativeArray<float> m_BoneWeights;
    22.  
    23.     PlayableGraph m_Graph;
    24.     AnimationScriptPlayable m_CustomMixerPlayable;
    25.  
    26.     public AnimationClip Idle;
    27.     public AnimationClip Walk;
    28.     public AnimationClip Run;
    29.  
    30.     void Start()
    31.     {
    32.         var animator = GetComponent<Animator>();
    33.  
    34.         // Get all the transforms in the hierarchy.
    35.         var transforms = animator.transform.GetComponentsInChildren<Transform>();
    36.         var numTransforms = transforms.Length - 1;
    37.  
    38.         // Fill native arrays (all the bones have a weight of 1.0).
    39.         m_Handles = new NativeArray<TransformStreamHandle>(numTransforms, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
    40.         m_BoneWeights = new NativeArray<float>(numTransforms, Allocator.Persistent, NativeArrayOptions.ClearMemory);
    41.         for (var i = 0; i < numTransforms; ++i)
    42.         {
    43.             m_Handles[i] = animator.BindStreamTransform(transforms[i + 1]);
    44.             m_BoneWeights[i] = 1.0f;
    45.         }
    46.  
    47.         // Create job.
    48.         var job = new PhaseBlendJob()
    49.         {
    50.             Handles = m_Handles,
    51.             BoneWeights = m_BoneWeights,
    52.             Weight = 0.0f,
    53.             PhaseStart = 0.3f,
    54.             PhaseEnd = 0.8f,
    55.         };
    56.  
    57.         // Create graph with custom mixer.
    58.         m_Graph = PlayableGraph.Create("AgentMotionMixer");
    59.         m_CustomMixerPlayable = AnimationScriptPlayable.Create(m_Graph, job);
    60.         m_CustomMixerPlayable.SetProcessInputs(false);
    61.  
    62.         var idleIndex = m_CustomMixerPlayable.AddInput(AnimationClipPlayable.Create(m_Graph, Idle), 0);
    63.         var walkIndex = m_CustomMixerPlayable.AddInput(AnimationClipPlayable.Create(m_Graph, Walk), 0);
    64.         var runIndex = m_CustomMixerPlayable.AddInput(AnimationClipPlayable.Create(m_Graph, Run), 0);
    65.  
    66.         var output = AnimationPlayableOutput.Create(m_Graph, "output", animator);
    67.         output.SetSourcePlayable(m_CustomMixerPlayable);
    68.  
    69.         m_Graph.Play();
    70.     }
    71.  
    72.     void Update()
    73.     {
    74.         var job = m_CustomMixerPlayable.GetJobData<PhaseBlendJob>();
    75.         job.Weight = Forward;
    76.         job.PhaseStart = WalkStart;
    77.         job.PhaseEnd = RunStart;
    78.         m_CustomMixerPlayable.SetJobData(job);
    79.     }
    80.  
    81.     void OnDisable()
    82.     {
    83.         m_Graph.Destroy();
    84.         m_Handles.Dispose();
    85.         m_BoneWeights.Dispose();
    86.     }
    87. }
    88.  
    89.  
    90. public struct PhaseBlendJob : IAnimationJob
    91. {
    92.     public NativeArray<TransformStreamHandle> Handles;
    93.     public NativeArray<float> BoneWeights;
    94.     public float Weight;
    95.     public float PhaseStart;
    96.     public float PhaseEnd;
    97.  
    98.     public void ProcessRootMotion(AnimationStream stream)
    99.     {
    100.         var streamA = stream.GetInputStream(0);
    101.         var streamB = stream.GetInputStream(1);
    102.  
    103.         var velocity = Vector3.Lerp(streamA.velocity, streamB.velocity, Weight);
    104.         var angularVelocity = Vector3.Lerp(streamA.angularVelocity, streamB.angularVelocity, Weight);
    105.  
    106.         stream.velocity = velocity;
    107.         stream.angularVelocity = angularVelocity;
    108.     }
    109.  
    110.     public void ProcessAnimation(AnimationStream stream)
    111.     {
    112.         var startStream = stream.GetInputStream(0);
    113.         var phaseStream = stream.GetInputStream(1);
    114.         var endStream = stream.GetInputStream(2);
    115.  
    116.         Vector3 pos;
    117.         Quaternion rot;
    118.         TransformStreamHandle handle;
    119.  
    120.         var prePhaseWeight = ConvertRange(0, PhaseStart, 0, 1, Weight);
    121.         var postPhaseWeight = ConvertRange(PhaseEnd, 1, 0, 1, Weight);
    122.  
    123.         var numHandles = Handles.Length;
    124.         for (var i = 0; i < numHandles; ++i)
    125.         {
    126.             handle = Handles[i];
    127.  
    128.             if (Weight < PhaseStart)
    129.             {
    130.                 var startPos = handle.GetLocalPosition(startStream);
    131.                 var phasePos = handle.GetLocalPosition(phaseStream);
    132.                 pos = Vector3.Lerp(startPos, phasePos, prePhaseWeight * BoneWeights[i]);
    133.  
    134.                 var startRot = handle.GetLocalRotation(startStream);
    135.                 var phaseRot = handle.GetLocalRotation(phaseStream);
    136.                 rot = Quaternion.Slerp(startRot, phaseRot, prePhaseWeight * BoneWeights[i]);
    137.             }
    138.             else if (Weight < PhaseEnd)
    139.             {
    140.                 pos = handle.GetLocalPosition(phaseStream);
    141.                 rot = handle.GetLocalRotation(phaseStream);
    142.             }
    143.             else
    144.             {
    145.                 var phasePos = handle.GetLocalPosition(phaseStream);
    146.                 var endPos = handle.GetLocalPosition(endStream);
    147.                 pos = Vector3.Lerp(phasePos, endPos, postPhaseWeight * BoneWeights[i]);
    148.  
    149.                 var phaseRot = handle.GetLocalRotation(phaseStream);
    150.                 var endRot = handle.GetLocalRotation(endStream);
    151.                 rot = Quaternion.Slerp(phaseRot, endRot, postPhaseWeight * BoneWeights[i]);
    152.             }
    153.  
    154.             handle.SetLocalPosition(stream, pos);
    155.             handle.SetLocalRotation(stream, rot);
    156.         }
    157.     }
    158.  
    159.     public float ConvertRange(float originalStart, float originalEnd, float newStart, float newEnd, float value)
    160.     {
    161.         float scale = (newEnd - newStart) / (originalEnd - originalStart);
    162.         return (float)(newStart + ((value - originalStart) * scale));
    163.     }
    164. }
    165.  
    166.  
     
    Xerioz likes this.