Search Unity

  1. Are you interested in providing feedback directly to Unity teams? Sign up to become a member of Unity Pulse, our new product feedback and research community.
    Dismiss Notice

Animation C# jobs in 2018.2a5

Discussion in 'Animation' started by Mecanim-Dev, Apr 4, 2018.

  1. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    777
    Not sure what you mean with "correct", documentation clearly states "world position" while it's not - I'm not talking about a parent to the Animator but a parent to those bones inside the Animator hierarchy.
    Also, the exact same method seems to work fine for elements in that chain (they are using Get/SetGlobalTR to update, and each child gets the right parent position), so there must be some way to make the job aware of the parent transform...

    Edit: nearly all useful effects need some world space awareness, be it looking at a point, a pos/rot damper, foot placement, ...
     
    Last edited: Nov 6, 2019
    awesomedata likes this.
  2. Alex_StudioDrydock

    Alex_StudioDrydock

    Joined:
    Jan 16, 2019
    Posts:
    8
    Hi, is there a way to create the TransformStreamHandles for a rig that has "Optimize Game Objects" enabled on import?
     
    sl1nk3_ubi, littlepolygon and fherbst like this.
  3. littlepolygon

    littlepolygon

    Joined:
    Jul 7, 2013
    Posts:
    16
    I'm also working on collision integration with Animator/PlayableGraph (sample gif). I started a new thread, but then was pointed at this thread from twitter. TL;DR Both Physics.Raycast and RaycastCommand.ScheduleBatch are main-thread-only, which is a blocker on doing a terrain-fixup-ik-playable. Any word from internal devs on whether this kind of support is in the pipeline?
     
  4. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,674
    Hi @littlepolygon

    Unfortunatelly no, not in the current tech. The only ways to do that right now is to wait until LateUpdate, do your raycast and solve your IK from the main thread.

    We did try to improve the integration with physics in the current tech but we couldn't do it because the system was not design for multithreading and we can't change it without breaking all the current user projects.

    But for dots we want to support raycast from our animation graph which is multithreaded.
     
  5. littlepolygon

    littlepolygon

    Joined:
    Jul 7, 2013
    Posts:
    16
    I've been confused about DOTS for a while, and information is hard to verify -- does it live alongside legacy interfaces, or is it effectively a different project-type/engine under the unity "umbrella"?
     
  6. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,674
    it live alongside legacy interfaces, we do have an hybrid mode to mix both DOTS and legacy unity while we are working on completing the dots tech.

    So today in unity editor you can download all the dots package and start to play with them and see how the interact all togheter.

    https://github.com/Unity-Technologies/Unity.Animation.Samples

    This is not production ready and there is a lot of tools missing.
    Do not expect to much and stability because it still early.
     
    littlepolygon likes this.
  7. CptKen

    CptKen

    Joined:
    May 30, 2017
    Posts:
    216
    Hi,

    I'm trying to use animation jobs to apply some animation logic in between the 'base animation system' (usually mecanim) and the 'Animation Rigging' playable graph (or any other second graph for that matter).

    To do this I've made a second playable output with my AnimationScriptPlayable running an animation job on it as shown in the below image:

    upload_2020-1-23_9-44-49.png
    The code that I used to set this up is at the bottom of this post. However, it's mostly standard playable graph code. The only thing different I've done compared to usual, is that I use the following function to ensure that the animation stream from the first playable output is routed to my second output. From what I've seen, this seems to be the way the animation rigging package routes the stream to different layers.

    Code (CSharp):
    1. PlayableOutput.SetAnimationStreamSource(AnimationStreamSource.PreviousInputs)
    Now for the most part this works fine and the animation stream coming in is indeed from the first. However, the moment I set a position or rotation on a transform stream handle here, it changes the entire animation. It doesn't matter what I set even something as simple as setting the position of the hips to the same position that they are already in, adversary affects every transform in the model. HipHandle.SetPosition(stream, HipHandle.GetPosition(stream));

    You can see it in this image. The left character is normal and the right has my animation script. These animations should look exactly the same but for some reason the entire upper body is more bent over, the front leg is raised higher and the back leg is a little more forward than it should be. This all by simply setting the hip position to the exact same position as it was already in [HipHandle.SetPosition(stream, HipHandle.GetPosition(stream));]

    upload_2020-1-23_9-59-54.png

    Is there something I am doing wrong here in the setup. I don't know why the entire hierarchy is changing even though technically I'm changing nothing in this test animation job. Should I be making a second playable graph for this?

    Code (CSharp):
    1.  
    2. m_playableGraph = m_animator.playableGraph;
    3.  
    4. var playableOutput = AnimationPlayableOutput.Create(
    5.      m_playableGraph, "StrideWarpOutput", m_animator);
    6.  
    7. var strideWarpIKAnimJob = new StrideWarpIKJob()
    8. {
    9.      SpeedWarp = 1f,
    10.      CharPositionY = transform.position.y,
    11.      Offset = m_baseOffset,
    12.      DeltaTime = Time.deltaTime,
    13.      Hips = m_animator.BindStreamTransform(m_hips),
    14.      LeftThighJoint = m_animator.BindStreamTransform(m_leftThigh),
    15.      RightThighJoint = m_animator.BindStreamTransform(m_rightThigh),
    16.      LeftLowerLegJoint = m_animator.BindStreamTransform(m_leftLowerLeg),
    17.      RightLowerLegJoint = m_animator.BindStreamTransform(m_rightLowerLeg),
    18.      LeftFoot = m_animator.BindStreamTransform(m_leftFoot),
    19.      RightFoot = m_animator.BindStreamTransform(m_rightFoot),
    20. };
    21.  
    22. m_animScriptPlayable = AnimationScriptPlayable.Create(
    23.      m_playableGraph, strideWarpIKAnimJob, 0);
    24.  
    25. m_animScriptPlayable.SetProcessInputs(true);
    26. playableOutput.SetSourcePlayable(m_animScriptPlayable);
    27. playableOutput.SetAnimationStreamSource(AnimationStreamSource.PreviousInputs);
    28. playableOutput.SetWeight(1f);
    UPDATE: Same problem if I move my playable output to a second playableGraph
    UPDATE: Tested in 2019.1.14f and 2019.3.0f5, results are the same.
     
    Last edited: Jan 23, 2020
  8. Mecanim-Dev

    Mecanim-Dev

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    1,674
    @CptKen
    Hi, there is nothing obvious at first glance that would yield this behaviour.

    We are using the same technic in timeline to drive any kind of animation rig and to keyframe it and we don't see any pose change when we set some value in the stream. So I don't understand why you get this result.

    Could you log a bug with a project exposing this issue? that would help us to understand what is going on
     
    CptKen likes this.
  9. CptKen

    CptKen

    Joined:
    May 30, 2017
    Posts:
    216
    Thanks for the reply. Cheers, I'll log a bug report replicating this issue.
     
    Last edited: Feb 6, 2020
    Ali-Nagori likes this.
  10. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    1,775
    I recently reported two bugs relating to Animation Jobs which I haven't received any response about and I'm wondering if I might just be using the system wrong.
    • Case 1218166 - Jobs are playables, but they don't actually run when I simply connect them to another playable in the graph. They only run if I connect them directly to an AnimationPlayableOutput.
    • Case 1220865 - Only the first PropertyStreamHandle I create seems to work properly. I made the following class:
    Code (CSharp):
    1. public sealed class AnimatedProperty
    2. {
    3.     public AnimatedProperty(PlayableGraph graph, Animator animator, string name)
    4.     {
    5.         var property = animator.BindStreamProperty(animator.transform, typeof(Animator), name);
    6.  
    7.         var playable = AnimationScriptPlayable.Create(graph, new FloatJob() { property = property });
    8.         playable.Pause();
    9.  
    10.         var output = AnimationPlayableOutput.Create(graph, name, animator);
    11.         output.SetSourcePlayable(playable);
    12.     }
    13.  
    14.     private struct FloatJob : IAnimationJob
    15.     {
    16.         public PropertyStreamHandle property;
    17.         public float value;
    18.  
    19.         public void ProcessRootMotion(AnimationStream stream) { }
    20.  
    21.         public void ProcessAnimation(AnimationStream stream)
    22.         {
    23.             value = property.GetFloat(stream);
    24.             Debug.Log(value);
    25.         }
    26.     }
    27. }
    If I create one of them, it can properly read the specified value. But if I create a second one it always logs 0. And if I swap them around, it's always the first one to be created that works and the second doesn't.

    Any suggestions?
     
    quijijibo likes this.
  11. sdf

    sdf

    Joined:
    Sep 6, 2012
    Posts:
    7
    Is there way to integrate the animation ik job samples into timeline or run in editor? Any suggestion is welcome。
     
  12. jaeeunpark

    jaeeunpark

    Joined:
    Feb 3, 2020
    Posts:
    4
    I'm working on modifying a bunch of bones(transform) in runtime.
    Animation job is proper way to achieve this with acceptable performance cost, but there is wasting cost in AnimationScriptPlayable.ProcessRootMotion. Even though it is blank function.

    Can I prevent invoking processRootMotion? 1.4ms is too much to waist.

    I'm attaching profiling result.
    upload_2020-3-27_19-14-35.png
     
    sl1nk3_ubi likes this.
  13. Zzxcv

    Zzxcv

    Joined:
    Oct 31, 2016
    Posts:
    2
    hello.
    is there any way that in FullBodyIk read animation from Animator Component, instead of using only one animation clip?
    i mean this line:
    Code (CSharp):
    1. var clip = SampleUtility.LoadAnimationClipFromFbx("DefaultMale/Models/DefaultMale_Humanoid", "Idle");
     
  14. caste

    caste

    Joined:
    Dec 19, 2012
    Posts:
    9
    Also interesting for me
     
  15. Kybernetik

    Kybernetik

    Joined:
    Jan 3, 2013
    Posts:
    1,775
    When the Animation Jobs Samples need to communicate with their job, they always use Get/SetJobData which needs to copy the whole struct around and probably do a bunch of safety checks and other stuff.

    For example, every Update the WeightedMaskMixer needs to tell the job if the
    weight
    changed and modifies the bone weights. It also sets
    job.boneWeights = m_BoneWeights;
    which is actually unnecessary because native arrays function more like a reference type.

    So in my own jobs, I've instead been making read/write fields as native arrays with a single element so the container class can just keep the original job object and access that array element without needing to use Get/SetJobData.

    I'm just wondering if this approach is likely to cause problems. Needing to dispose the arrays adds a bit of complexity, but accessing the data from outside the job is much easier. Is there something I'm missing?
     
    SenseEater and Zzxcv like this.
  16. LudiKha

    LudiKha

    Joined:
    Feb 15, 2014
    Posts:
    128
    As far as I know, this is pretty much the way you can transfer data to and from jobs - it's commonly done in the ECS workflow and even recommended by Unity devs.
     
    awesomedata likes this.
  17. awesomedata

    awesomedata

    Joined:
    Oct 8, 2014
    Posts:
    1,334
    This sounds like a smart move.

    I wonder though about the allocations of the NativeArray -- Aren't there limits on how many indexes you can have in one of these buffers? (It's been a while since I went over this bit, so I am not sure -- as this is the only potential issue I can think of and was mentioned by one of the Unity devs).
     
    Last edited: Mar 19, 2021
  18. EZGVogan

    EZGVogan

    Joined:
    Mar 22, 2021
    Posts:
    2
    Hello,

    Im actually trying to edit a walking animation by accelerate it. To do so im trying to modify the amplitude of the front steps. It works fine with the goalLocalPosition, then the solver works and the body is pulled by the front foot. But here is the problem, the back foot dont follow the body moves. In the non modified animation the backfoot will for instance reach the front one in 1 seconde and in the modified it will be longer. It's because the root is not accurate with the bodyposition. So i'm looking for a way to modify the root global position.


    As shown in my image, the root of the modified animation (front one) stay where it was in the non modify animation (back one) even when the body is moved.
     

    Attached Files:

  19. sl1nk3_ubi

    sl1nk3_ubi

    Joined:
    Aug 21, 2019
    Posts:
    12
    There's another way to do this that involves a little bit of reflection, since the API is not exposed.
    In the PlayableHandle, there's actually a method that returns an IntPtr to the data, which you can store somewhere and then access the data directly, this is the code that we use to do that:

    Code (CSharp):
    1.  
    2.     /// <summary>
    3.     /// Use this method to retrieve the job data pointer of an AnimationScript directly
    4.     /// This will help avoiding the need to copy the job struct around when data needs to be modified
    5.     ///
    6.     /// This method should be called once at initialization
    7.     /// </summary>
    8.     /// <param name="playable">the job script to retrieve the job data from</param>
    9.     protected static IntPtr GetJobDataPointer(in AnimationScriptPlayable playable)
    10.     {
    11.         var getJobDataPointer = typeof(PlayableHandle).GetMethod("GetJobData", BindingFlags.NonPublic | BindingFlags.Instance);
    12.         if (getJobDataPointer != null)
    13.         {
    14.             return (IntPtr)getJobDataPointer.Invoke(playable.GetHandle(), null);
    15.         }
    16.         else
    17.         {
    18.             Asserts.Assert(false, "Unable to call GetJobData on PlayableHandle, please update the script");
    19.         }
    20.         return default;
    21.     }
    22.  
    23.     /// <summary>
    24.     /// Use this method to retrieve a reference to a previously retrieved job data pointer
    25.     /// You can then modify this reference directly without the need to copy the struct around
    26.     ///
    27.     /// The pointer can be retrieved with <see cref="GetJobDataPointer"/>
    28.     /// </summary>
    29.     /// <param name="playable">the job script to retrieve the job data from</param>
    30.     protected static unsafe ref T GetJobData<T>(IntPtr jobDataPointer) where T : unmanaged
    31.     {
    32.         return ref *(T*)jobDataPointer.ToPointer();
    33.     }
    34.  
    When creating your script playable, you then need to call `GetJobDataPointer`, store the pointer somewhere and then you no longer need to worry about copying the data around since you have a direct reference to it (using `GetJobData<T>(IntPtr jobDataPointer)`)
     
    twobob, awesomedata and Kybernetik like this.
  20. makaolachsiungca

    makaolachsiungca

    Joined:
    Sep 27, 2019
    Posts:
    4
    where should i process this mirror job?
    i been try switch muscle value to eachother via animationstream.GetMuscle/.SetMuscle
    and found some question about MuscleHandle
    1.the constructor of MuscleHandle seems doesn't match Muscle map in avatar config setting
    2.isn't the muscle value be as local space?why feet rotation be like this after mirror the rotation of hips
    Desktop Screenshot 2021.07.18 - 00.21.11.27.png Desktop Screenshot 2021.07.18 - 00.21.28.91.png
     
  21. LangTao92

    LangTao92

    Joined:
    May 13, 2017
    Posts:
    15
    Hi,I Want to drive my character by BVH-Topos data by json data,I try to set localRotation ,but it is error,and i set this localrotation in main thread is correct.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Newtonsoft.Json;
    3. using Unity.Collections;
    4. using UnityEngine;
    5. using UnityEngine.Playables;
    6. using UnityEngine.Animations;
    7. using UnityEngine.Profiling;
    8. using UnityEngine.Video;
    9.  
    10.  
    11. [RequireComponent(typeof(Animator))]
    12. public class AnimationScriptExample : MonoBehaviour
    13. {
    14.     PlayableGraph m_Graph;
    15.     AnimationScriptPlayable m_ScriptPlayable;
    16.     public VideoPlayer mVideoPlayer;
    17.     private int mSize = 0;
    18.  
    19.     private Animator animator;
    20.  
    21.     public TransformStreamHandle rootTfHandle; //Transfprm
    22.     //public TransformStreamHandle rootHandle; //Transfprm
    23.     NativeArray<TransformStreamHandle> m_Handles; //
    24.    
    25.     NativeArray<TransformStreamHandle> RootTfHandle;
    26.     NativeArray<Vector3> localPositions;
    27.     NativeArray<Quaternion> m_LocalRotations;
    28.     private List<FrameInfo> mFrameInfos;
    29.  
    30.    // Transform[] allTransforms;
    31. //差距 0.04 浮点精度
    32.    private  Vector3 vec = new Vector3(0f, 0.8939922f+0.04f, 0f);
    33.     int numTransforms;
    34.     Transform[] targetBoneTF;
    35.  
    36.     Transform rootTf;
    37.     //private List<string> removeBoneString = new List<string>();
    38.  
    39.  
    40.     //所有挂在 instance id 的
    41.     private GenterateId[] mGenterateIds;
    42.  
    43.     //骨骼名称与对应的物体关系表 key 骨骼名称 : value instanceid
    44.     private Dictionary<string, int> dicForBonesDependence;
    45.     // 骨骼 instance id 对应的 物体
    46.     private Dictionary<int, Transform> dicForInstanceForTfs;
    47. [SerializeField]
    48.     private bool isVideoLoop = false;
    49.  
    50. [SerializeField]
    51.     private bool controllerByAI = false;//外部控制是否被ai控制算法
    52.  
    53.     private bool currentController = false;//当前动动画是否AI控制算法
    54.     private static readonly int None = Animator.StringToHash("None");//ai 不跳舞
    55.     private static readonly int Dance1 = Animator.StringToHash("Dance");//跳舞 第一种
    56.  
    57.     void OnEnable()
    58.     {
    59.        
    60.        
    61.         InitData();
    62.         // Create the graph.
    63.         m_Graph = PlayableGraph.Create("AnimationScriptExample");
    64.         animator = GetComponent<Animator>();
    65.        
    66.  
    67.         m_Handles = new NativeArray<TransformStreamHandle>(numTransforms, Allocator.Persistent,
    68.             NativeArrayOptions.UninitializedMemory);
    69.  
    70.  
    71.         for (int i = 0; i < numTransforms; i++)
    72.         {
    73.             if (targetBoneTF[i] != null)
    74.             {
    75.                 m_Handles[i] = animator.BindStreamTransform(targetBoneTF[i]);
    76.             }
    77.         }
    78.        
    79.      
    80.  
    81.         m_LocalRotations =
    82.             new NativeArray<Quaternion>(numTransforms, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
    83.         for (var i = 0; i < m_LocalRotations.Length; i++)
    84.         {
    85.             if (targetBoneTF[i] != null)
    86.                 m_LocalRotations[i] = targetBoneTF[i].localRotation;
    87.         }
    88.         RootTfHandle = new NativeArray<TransformStreamHandle>(1, Allocator.Persistent,
    89.             NativeArrayOptions.UninitializedMemory);
    90.         rootTfHandle = animator.BindStreamTransform(transform);
    91.         RootTfHandle[0] = animator.BindStreamTransform(rootTf);
    92.  
    93.  
    94.         // Create the animation job and its playable.
    95.         var animationJob = new MyAnimationJob();
    96.  
    97.         animationJob.handles = m_Handles;
    98.         animationJob.rootHandle = RootTfHandle;
    99.         animationJob.rootTfHandle = rootTfHandle;
    100.         animationJob.localPositions = localPositions;
    101.         animationJob.localRotations = m_LocalRotations;
    102.        
    103.      
    104.         if (currentController)
    105.         {
    106.             //animator.SetTrigger(None);
    107.             mVideoPlayer.frameReady += OnFrameReady;
    108.             m_Graph.Play();
    109.             // 创建输出结果并将结果链接到Playable上
    110.         }
    111.         else
    112.         {
    113.             animator.SetTrigger(Dance1);
    114.         }
    115.         mVideoPlayer.Play();
    116.         m_ScriptPlayable = AnimationScriptPlayable.Create(m_Graph, animationJob);
    117.         m_ScriptPlayable.SetProcessInputs(false);
    118.         var output = AnimationPlayableOutput.Create(m_Graph, "Output", GetComponent<Animator>());
    119.         output.SetSourcePlayable(m_ScriptPlayable);
    120.     }
    121.  
    122.     private void InitData()
    123.     {
    124.  
    125.  
    126.         currentController = controllerByAI;
    127.         // 将test01 中的内容加载进txt文本中
    128.         TextAsset txt = Resources.Load(TmpSystemString.testDanceJsonName) as TextAsset;
    129.         mFrameInfos = JsonUtility.FromJson<MyDanceJson>(txt.text).mFrameInfos;
    130.         //之后会迁移到 addressable 中去使用
    131.         Profiler.BeginSample("TestDicBoneDics");
    132.         TextAsset dicTxt = Resources.Load("BoneDicFloader/BoneDics") as TextAsset;
    133.         dicForBonesDependence = JsonConvert.DeserializeObject<Dictionary<string, int>>(dicTxt.text);
    134.         Profiler.EndSample();
    135.  
    136.         mSize = mFrameInfos.Count;
    137.         mVideoPlayer.sendFrameReadyEvents = true;
    138.         mVideoPlayer.prepareCompleted += OnPrepareFinished;
    139.         mVideoPlayer.loopPointReached += OnPlayFinished;
    140.      
    141.         mVideoPlayer.isLooping = isVideoLoop;
    142.  
    143.         // allTransforms = animator.transform.GetComponentsInChildren<Transform>();
    144.         mGenterateIds = gameObject.GetComponentsInChildren<GenterateId>();
    145.         dicForInstanceForTfs = new Dictionary<int, Transform>();
    146.  
    147.         for (var i = 0; i < mGenterateIds.Length; i++)
    148.         {
    149.             var tmpGenerateIdComponent = mGenterateIds[i];
    150.             dicForInstanceForTfs.Add(tmpGenerateIdComponent.myId, tmpGenerateIdComponent.transform);
    151.         }
    152.  
    153.         rootTf = transform.Find(TmpSystemString.RootStr);
    154.         FrameInfo firstInfo = new FrameInfo();
    155.         if (mFrameInfos !=null&& mFrameInfos.Count>0)
    156.         {
    157.             firstInfo = mFrameInfos[0];
    158.         }
    159.         else
    160.         {
    161.             Debug.LogError("序列为空,请检查");
    162.             return;
    163.         }
    164.  
    165.        // targetBoneTF = new Transform[firstInfo.keypoints.Count-1];
    166.        List<Transform> tmpTfs = new List<Transform>();
    167.        localPositions =  new NativeArray<Vector3>(1, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
    168.        // var tfList = allTransforms.ToList();
    169.         //removeBoneString.Clear();
    170.         //分析第一条数据排除不需要的transforms
    171.         for (int i = 0,j=0; i < firstInfo.keypoints.Count; i++)
    172.         {
    173.             var keypoint = firstInfo.keypoints[i];
    174.             //var findTargetTf = tfList.Find(p => p.name == keypoint.name);
    175.             if (dicForBonesDependence.ContainsKey(keypoint.name))
    176.             {
    177.                 var tragetTf =
    178.                     dicForInstanceForTfs[dicForBonesDependence[keypoint.name]];
    179.  
    180.                 if (tragetTf != null)
    181.                 {
    182.                     if (keypoint.name.Equals(TmpSystemString.HipTranslationStr))
    183.                     {
    184.                         SetTFLocalPot(rootTf, keypoint);
    185.                         localPositions[0] = rootTf.localPosition+vec;
    186.                     }
    187.                     else
    188.                     {
    189.                         tmpTfs.Add(tragetTf);
    190.                         SetTFLocalRot(tragetTf, keypoint);
    191.                         j++;
    192.                     }
    193.                 }
    194.             }
    195.         }
    196.  
    197.         targetBoneTF = tmpTfs.ToArray();
    198.         numTransforms = targetBoneTF.Length;
    199.  
    200.     }
    201.  
    202.     void SetTFLocalPot(Transform tf,Point keypoint)
    203.     {
    204.         tf.localPosition = new Vector3(-keypoint.x, -keypoint.y, keypoint.z) / 100;
    205.     }
    206.  
    207.  
    208.     void SetTFLocalRot(Transform tf, Point keypoint)
    209.     {
    210.         tf.localRotation = new Quaternion(keypoint.x, -keypoint.y, -keypoint.z, keypoint.w);
    211.     }
    212.  
    213.  
    214.     private void OnFrameReady(VideoPlayer source, long frameidx)
    215.     {
    216.         Dance(mFrameInfos[(int) (frameidx)]);
    217.     }
    218.  
    219.     private void OnPlayFinished(VideoPlayer source)
    220.     {
    221.         if (!isVideoLoop)
    222.         {
    223.             source.Stop();
    224.         }
    225.         else
    226.         {
    227.             Debug.Log("循环播放");
    228.         }
    229.     }
    230.  
    231.     private void OnPrepareFinished(VideoPlayer source)
    232.     {
    233.     }
    234.  
    235.     private void Update()
    236.     {
    237.         if (currentController!=controllerByAI)
    238.         {
    239.             //发现不相等,需要做处理 这里实时的话应该是 根据是否获取 pts 动画数据
    240.             currentController = controllerByAI;
    241.             if (currentController)
    242.             {
    243.                 m_Graph.Play();
    244.                 mVideoPlayer.frameReady += OnFrameReady;
    245.                 //animator.SetTrigger(None);
    246.             }
    247.             else
    248.             {
    249.                 mVideoPlayer.frameReady -= OnFrameReady;
    250.                 m_Graph.Stop();
    251.                 //animator.SetTrigger(Dance1);
    252.             }
    253.         }
    254.      
    255.     }
    256.  
    257.     void Dance(FrameInfo frameInfo)
    258.     {
    259.      
    260.  
    261.         if (frameInfo!=null)
    262.         {
    263.             var points = frameInfo.keypoints;
    264.             Point rootPoint=new Point();
    265.             for (int i = 0,j=0; i < points.Count; i++)
    266.             {
    267.  
    268.                 // if(removeBoneString.Contains(points[i].name))
    269.                 //     continue;
    270.                 if (!dicForBonesDependence.ContainsKey(points[i].name))
    271.                     continue;
    272.                     var keypoint = points[i];
    273.                     string tmpName = points[i].name;
    274.                 if (points[i].name == TmpSystemString.HipTranslationStr)
    275.                 {
    276.                     rootPoint = keypoint;
    277.                 }
    278.                 else
    279.                 {
    280.                     m_LocalRotations[j++] = new Quaternion(keypoint.x, -keypoint.y -0.04f, -keypoint.z, keypoint.w);
    281.                 }
    282.             }
    283.          
    284.  
    285.             var animationJob = new MyAnimationJob();
    286.             //刷新数据 go to jump
    287.             // 需要将配置表中的信息传递进来
    288.             animationJob.rootTfHandle = rootTfHandle;
    289.             animationJob.rootHandle = RootTfHandle;
    290.             animationJob.handles = m_Handles;
    291.             localPositions[0] = new Vector3(-rootPoint.x, -rootPoint.y, rootPoint.z) / 100 +vec;
    292.             animationJob.localPositions = localPositions;
    293.             animationJob.localRotations = m_LocalRotations;
    294.             m_ScriptPlayable.SetJobData(animationJob);
    295.         }
    296.  
    297.  
    298.    
    299.     }
    300.  
    301.  
    302.     void OnDisable()
    303.     {
    304.         m_Graph.Destroy();
    305.         m_Handles.Dispose();
    306.         m_LocalRotations.Dispose();
    307.         localPositions.Dispose();
    308.         RootTfHandle.Dispose();
    309.     }
    310. }
    and my jobdatda
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Collections;
    3. using Unity.Mathematics;
    4. using UnityEngine;
    5. using UnityEngine.Animations;
    6.  
    7. public struct MyAnimationJob : IAnimationJob
    8. {
    9.     public TransformStreamHandle rootTfHandle; //Transform
    10.     public NativeArray<TransformStreamHandle> rootHandle; //Root 盆骨位置
    11.     public NativeArray<TransformStreamHandle> handles; //bones
    12.     public NativeArray<Vector3> localPositions;
    13.     public NativeArray<Quaternion> localRotations;
    14.  
    15.     public void ProcessRootMotion(AnimationStream stream)
    16.     {
    17.         var rootPosition = rootTfHandle.GetPosition(stream);
    18.         var rootRotation = rootTfHandle.GetRotation(stream);
    19.         // The root always follow the given position and rotation.
    20.         rootTfHandle.SetLocalPosition(stream, rootPosition);
    21.         rootTfHandle.SetRotation(stream, rootRotation);
    22.     }
    23.  
    24.     public void ProcessAnimation(AnimationStream stream)
    25.     {
    26.         // Get root position and rotation.
    27.         var rootPosition = rootTfHandle.GetPosition(stream);
    28.          var rootRotation = rootTfHandle.GetRotation(stream);
    29.         rootHandle[0].SetPosition(stream, localPositions[0]);
    30.         var handleLength = handles.Length;
    31.         for (int i = 0; i < handleLength; i++)
    32.         {
    33.            // var rota =  rootHandle[0].GetLocalRotation(stream);
    34.             handles[i].SetLocalRotation(stream, localRotations[i]);
    35.         }
    36.     }
    37.  
    38.     // private void ComputeDampedPositions(AnimationStream stream)
    39.     // {
    40.     //     // Get root position and rotation.
    41.     //     var rootPosition = rootHandle.GetPosition(stream);
    42.     //     var rootRotation = rootHandle.GetRotation(stream);
    43.     //
    44.     //     var parentPosition = rootPosition + localPositions[0] + rootRotation *localPositions[0] ;
    45.     //     var parentRotation = rootRotation ;
    46.     //
    47.     //     for (int i = 0; i < handleLength; i++)
    48.     //     {
    49.     //         handles[i].SetLocalPosition(stream, localRotations[i].eulerAngles);
    50.     //     }
    51.     //
    52.     // }
    53. }
    “handles.SetLocalRotation(stream, localRotations);” is not set the correctly Quaternion.
     
unityunity