Search Unity

  1. Unity 2018.1 has arrived! Read about it here
    Dismiss Notice
  2. Scriptable Render Pipeline improvements, Texture Mipmap Streaming, and more! Check out what we have in store for you in the 2018.2 Beta.
    Dismiss Notice
  3. If you couldn't join the live stream, take a peek at what you missed.
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Learn more.
    Dismiss Notice
  5. ARCore is out of developer preview! Read about it here.
    Dismiss Notice
  6. Magic Leap’s Lumin SDK Technical Preview for Unity lets you get started creating content for Magic Leap One™. Find more information on our blog!
    Dismiss Notice
  7. 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:
    34


    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.