public override ChainIKConstraintJob Create(Animator animator, ref T data, Component component)
        {
            List <Transform> chain = new List <Transform>();
            Transform        tmp   = data.tip;

            while (tmp != data.root)
            {
                chain.Add(tmp);
                tmp = tmp.parent;
            }
            chain.Add(data.root);
            chain.Reverse();

            var job = new ChainIKConstraintJob();

            job.chain         = new NativeArray <ReadWriteTransformHandle>(chain.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            job.linkLengths   = new NativeArray <float>(chain.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            job.linkPositions = new NativeArray <Vector3>(chain.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
            job.maxReach      = 0f;

            int tipIndex = chain.Count - 1;

            for (int i = 0; i < chain.Count; ++i)
            {
                job.chain[i]       = ReadWriteTransformHandle.Bind(animator, chain[i]);
                job.linkLengths[i] = (i != tipIndex) ? Vector3.Distance(chain[i].position, chain[i + 1].position) : 0f;
                job.maxReach      += job.linkLengths[i];
            }

            job.target       = ReadOnlyTransformHandle.Bind(animator, data.target);
            job.targetOffset = AffineTransform.identity;
            if (data.maintainTargetPositionOffset)
            {
                job.targetOffset.translation = data.tip.position - data.target.position;
            }
            if (data.maintainTargetRotationOffset)
            {
                job.targetOffset.rotation = Quaternion.Inverse(data.target.rotation) * data.tip.rotation;
            }

            job.chainRotationWeight = FloatProperty.Bind(animator, component, data.chainRotationWeightFloatProperty);
            job.tipRotationWeight   = FloatProperty.Bind(animator, component, data.tipRotationWeightFloatProperty);

            var cacheBuilder = new AnimationJobCacheBuilder();

            job.maxIterationsIdx = cacheBuilder.Add(data.maxIterations);
            job.toleranceIdx     = cacheBuilder.Add(data.tolerance);
            job.cache            = cacheBuilder.Build();

            return(job);
        }
        /// <inheritdoc />
        public override MultiAimConstraintJob Create(Animator animator, ref T data, Component component)
        {
            var job = new MultiAimConstraintJob();

            job.driven       = ReadWriteTransformHandle.Bind(animator, data.constrainedObject);
            job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent);
            job.aimAxis      = data.aimAxis;
            job.upAxis       = data.upAxis;

            job.worldUpType   = (MultiAimConstraintJob.WorldUpType)data.worldUpType;
            job.worldUpAxis   = data.worldUpAxis;
            job.worldUpObject = ReadOnlyTransformHandle.Bind(animator, data.worldUpObject);

            WeightedTransformArray sourceObjects = data.sourceObjects;

            WeightedTransformArrayBinder.BindReadOnlyTransforms(animator, component, sourceObjects, out job.sourceTransforms);
            WeightedTransformArrayBinder.BindWeights(animator, component, sourceObjects, data.sourceObjectsProperty, out job.sourceWeights);

            job.sourceOffsets = new NativeArray <Quaternion>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);

            job.weightBuffer = new NativeArray <float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);

            for (int i = 0; i < sourceObjects.Count; ++i)
            {
                if (data.maintainOffset)
                {
                    var constrainedAim = data.constrainedObject.rotation * data.aimAxis;
                    job.sourceOffsets[i] = QuaternionExt.FromToRotation(
                        sourceObjects[i].transform.position - data.constrainedObject.position,
                        constrainedAim
                        );
                }
                else
                {
                    job.sourceOffsets[i] = Quaternion.identity;
                }
            }

            job.minLimit     = FloatProperty.Bind(animator, component, data.minLimitFloatProperty);
            job.maxLimit     = FloatProperty.Bind(animator, component, data.maxLimitFloatProperty);
            job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property);

            job.axesMask = new Vector3(
                System.Convert.ToSingle(data.constrainedXAxis),
                System.Convert.ToSingle(data.constrainedYAxis),
                System.Convert.ToSingle(data.constrainedZAxis)
                );

            return(job);
        }