public override TwistChainStep1Job Create(Animator animator, ref TwistChainStep1Data data, Component component) { // Retrieve chain in-between root and tip transforms. Transform[] chain = ConstraintsUtils.ExtractChain(data.root, data.tip); // Extract steps from chain. float[] steps = ConstraintsUtils.ExtractSteps(chain); // Build Job. var job = new TwistChainStep1Job(); job.chain = new NativeArray <ReadWriteTransformHandle>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.steps = new NativeArray <float>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.rootTarget = ReadWriteTransformHandle.Bind(animator, data.rootTarget); job.tipTarget = ReadWriteTransformHandle.Bind(animator, data.tipTarget); // Set values in NativeArray. for (int i = 0; i < chain.Length; ++i) { job.chain[i] = ReadWriteTransformHandle.Bind(animator, chain[i]); job.steps[i] = steps[i]; } return(job); }
public override MultiPositionConstraintJob Create(Animator animator, ref T data, Component component) { var job = new MultiPositionConstraintJob(); job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject); job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent); job.drivenOffset = Vector3Property.Bind(animator, component, data.offsetVector3Property); 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 <Vector3>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.weightBuffer = new NativeArray <float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); Vector3 drivenPos = data.constrainedObject.position; for (int i = 0; i < sourceObjects.Count; ++i) { job.sourceOffsets[i] = data.maintainOffset ? (drivenPos - sourceObjects[i].transform.position) : Vector3.zero; } job.axesMask = new Vector3( System.Convert.ToSingle(data.constrainedXAxis), System.Convert.ToSingle(data.constrainedYAxis), System.Convert.ToSingle(data.constrainedZAxis) ); return(job); }
public override BlendConstraintJob Create(Animator animator, ref T data, Component component) { var job = new BlendConstraintJob(); job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject); job.sourceA = ReadOnlyTransformHandle.Bind(animator, data.sourceObjectA); job.sourceB = ReadOnlyTransformHandle.Bind(animator, data.sourceObjectB); job.sourceAOffset = job.sourceBOffset = AffineTransform.identity; if (data.maintainPositionOffsets) { var drivenPos = data.constrainedObject.position; job.sourceAOffset.translation = drivenPos - data.sourceObjectA.position; job.sourceBOffset.translation = drivenPos - data.sourceObjectB.position; } if (data.maintainRotationOffsets) { var drivenRot = data.constrainedObject.rotation; job.sourceAOffset.rotation = Quaternion.Inverse(data.sourceObjectA.rotation) * drivenRot; job.sourceBOffset.rotation = Quaternion.Inverse(data.sourceObjectB.rotation) * drivenRot; } job.blendPosition = BoolProperty.Bind(animator, component, data.blendPositionBoolProperty); job.blendRotation = BoolProperty.Bind(animator, component, data.blendRotationBoolProperty); job.positionWeight = FloatProperty.Bind(animator, component, data.positionWeightFloatProperty); job.rotationWeight = FloatProperty.Bind(animator, component, data.rotationWeightFloatProperty); return(job); }
/// <summary> /// Defines what to do when processing the animation. /// </summary> /// <param name="stream">The animation stream to work on.</param> public void ProcessAnimation(AnimationStream stream) { float w = jobWeight.Get(stream); if (w > 0f) { if (twistTransforms.Length == 0) { return; } AnimationStreamHandleUtility.ReadFloats(stream, twistWeights, weightBuffer); Quaternion twistRot = TwistRotation(axisMask, sourceInverseBindRotation * source.GetLocalRotation(stream)); Quaternion invTwistRot = Quaternion.Inverse(twistRot); for (int i = 0; i < twistTransforms.Length; ++i) { ReadWriteTransformHandle twistTransform = twistTransforms[i]; float twistWeight = Mathf.Clamp(weightBuffer[i], -1f, 1f); Quaternion rot = Quaternion.Lerp(Quaternion.identity, Mathf.Sign(twistWeight) < 0f ? invTwistRot : twistRot, Mathf.Abs(twistWeight)); twistTransform.SetLocalRotation(stream, Quaternion.Lerp(twistBindRotations[i], rot, w)); // Required to update handles with binding info. twistTransforms[i] = twistTransform; } } else { for (int i = 0; i < twistTransforms.Length; ++i) { AnimationRuntimeUtils.PassThrough(stream, twistTransforms[i]); } } }
public override DampedTransformJob Create(Animator animator, ref T data, Component component) { var job = new DampedTransformJob(); job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject); job.source = ReadOnlyTransformHandle.Bind(animator, data.sourceObject); var drivenTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation); var sourceTx = new AffineTransform(data.sourceObject.position, data.sourceObject.rotation); job.localBindTx = sourceTx.InverseMul(drivenTx); job.prevDrivenTx = drivenTx; job.dampPosition = FloatProperty.Bind(animator, component, data.dampPositionFloatProperty); job.dampRotation = FloatProperty.Bind(animator, component, data.dampRotationFloatProperty); if (data.maintainAim && AnimationRuntimeUtils.SqrDistance(data.constrainedObject.position, data.sourceObject.position) > 0f) { job.aimBindAxis = Quaternion.Inverse(data.constrainedObject.rotation) * (sourceTx.translation - drivenTx.translation).normalized; } else { job.aimBindAxis = Vector3.zero; } return(job); }
public override TwoBoneIKConstraintJob Create(Animator animator, ref T data, Component component) { var job = new TwoBoneIKConstraintJob(); job.root = ReadWriteTransformHandle.Bind(animator, data.root); job.mid = ReadWriteTransformHandle.Bind(animator, data.mid); job.tip = ReadWriteTransformHandle.Bind(animator, data.tip); job.target = ReadOnlyTransformHandle.Bind(animator, data.target); if (data.hint != null) { job.hint = ReadOnlyTransformHandle.Bind(animator, data.hint); } 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.linkLengths[0] = Vector3.Distance(data.root.position, data.mid.position); job.linkLengths[1] = Vector3.Distance(data.mid.position, data.tip.position); job.targetPositionWeight = FloatProperty.Bind(animator, component, data.targetPositionWeightFloatProperty); job.targetRotationWeight = FloatProperty.Bind(animator, component, data.targetRotationWeightFloatProperty); job.hintWeight = FloatProperty.Bind(animator, component, data.hintWeightFloatProperty); return(job); }
public static void BindReadWriteTransforms(Animator animator, Component component, WeightedTransformArray weightedTransformArray, out NativeArray <ReadWriteTransformHandle> transforms) { transforms = new NativeArray <ReadWriteTransformHandle>(weightedTransformArray.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); for (int index = 0; index < weightedTransformArray.Count; ++index) { transforms[index] = ReadWriteTransformHandle.Bind(animator, weightedTransformArray[index].transform); } }
public override OverrideTransformJob Create(Animator animator, ref T data, Component component) { var job = new OverrideTransformJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject); if (data.sourceObject != null) { // Cache source to possible space rotation offsets (world, local and pivot) // at bind time so we can switch dynamically between them at runtime. job.source = ReadOnlyTransformHandle.Bind(animator, data.sourceObject); var sourceLocalTx = new AffineTransform(data.sourceObject.localPosition, data.sourceObject.localRotation); job.sourceInvLocalBindTx = sourceLocalTx.Inverse(); var sourceWorldTx = new AffineTransform(data.sourceObject.position, data.sourceObject.rotation); var drivenWorldTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation); job.sourceToWorldRot = sourceWorldTx.Inverse().rotation; job.sourceToPivotRot = sourceWorldTx.InverseMul(drivenWorldTx).rotation; var drivenParent = data.constrainedObject.parent; if (drivenParent != null) { var drivenParentWorldTx = new AffineTransform(drivenParent.position, drivenParent.rotation); job.sourceToLocalRot = sourceWorldTx.InverseMul(drivenParentWorldTx).rotation; } else { job.sourceToLocalRot = job.sourceToPivotRot; } } job.spaceIdx = cacheBuilder.Add(data.space); if (data.space == (int)OverrideTransformJob.Space.Pivot) { job.sourceToCurrSpaceRotIdx = cacheBuilder.Add(job.sourceToPivotRot); } else if (data.space == (int)OverrideTransformJob.Space.Local) { job.sourceToCurrSpaceRotIdx = cacheBuilder.Add(job.sourceToLocalRot); } else { job.sourceToCurrSpaceRotIdx = cacheBuilder.Add(job.sourceToWorldRot); } job.position = Vector3Property.Bind(animator, component, data.positionVector3Property); job.rotation = Vector3Property.Bind(animator, component, data.rotationVector3Property); job.positionWeight = FloatProperty.Bind(animator, component, data.positionWeightFloatProperty); job.rotationWeight = FloatProperty.Bind(animator, component, data.rotationWeightFloatProperty); job.cache = cacheBuilder.Build(); return(job); }
public static ReadWriteTransformHandle Bind(Animator animator, Transform transform) { ReadWriteTransformHandle handle = new ReadWriteTransformHandle(); if (transform == null || !transform.IsChildOf(animator.transform)) { return(handle); } handle.m_Handle = animator.BindStreamTransform(transform); return(handle); }
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); }
public override MultiParentConstraintJob Create(Animator animator, ref T data, Component component) { var job = new MultiParentConstraintJob(); job.driven = ReadWriteTransformHandle.Bind(animator, data.constrainedObject); job.drivenParent = ReadOnlyTransformHandle.Bind(animator, data.constrainedObject.parent); 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 <AffineTransform>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.weightBuffer = new NativeArray <float>(sourceObjects.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); var drivenTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation); for (int i = 0; i < sourceObjects.Count; ++i) { var sourceTransform = sourceObjects[i].transform; var srcTx = new AffineTransform(sourceTransform.position, sourceTransform.rotation); var srcOffset = AffineTransform.identity; var tmp = srcTx.InverseMul(drivenTx); if (data.maintainPositionOffset) { srcOffset.translation = tmp.translation; } if (data.maintainRotationOffset) { srcOffset.rotation = tmp.rotation; } job.sourceOffsets[i] = srcOffset; } job.positionAxesMask = new Vector3( System.Convert.ToSingle(data.constrainedPositionXAxis), System.Convert.ToSingle(data.constrainedPositionYAxis), System.Convert.ToSingle(data.constrainedPositionZAxis) ); job.rotationAxesMask = new Vector3( System.Convert.ToSingle(data.constrainedRotationXAxis), System.Convert.ToSingle(data.constrainedRotationYAxis), System.Convert.ToSingle(data.constrainedRotationZAxis) ); 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); }
public override MultiReferentialConstraintJob Create(Animator animator, ref T data, Component component) { var job = new MultiReferentialConstraintJob(); var sources = data.sourceObjects; job.driver = IntProperty.Bind(animator, component, data.driverIntProperty); job.sources = new NativeArray <ReadWriteTransformHandle>(sources.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.sourceBindTx = new NativeArray <AffineTransform>(sources.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.offsetTx = new NativeArray <AffineTransform>(sources.Length - 1, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); for (int i = 0; i < sources.Length; ++i) { job.sources[i] = ReadWriteTransformHandle.Bind(animator, sources[i].transform); job.sourceBindTx[i] = new AffineTransform(sources[i].position, sources[i].rotation); } job.UpdateOffsets(data.driverValue); return(job); }
/// <inheritdoc /> public override TwistChainConstraintJob Create(Animator animator, ref T data, Component component) { // Retrieve chain in-between root and tip transforms. Transform[] chain = ConstraintsUtils.ExtractChain(data.root, data.tip); // Extract steps from chain. float[] steps = ConstraintsUtils.ExtractSteps(chain); // Build Job. var job = new TwistChainConstraintJob(); job.chain = new NativeArray <ReadWriteTransformHandle>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.steps = new NativeArray <float>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.weights = new NativeArray <float>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.rotations = new NativeArray <Quaternion>(chain.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.rootTarget = ReadWriteTransformHandle.Bind(animator, data.rootTarget); job.tipTarget = ReadWriteTransformHandle.Bind(animator, data.tipTarget); // Set values in NativeArray. for (int i = 0; i < chain.Length; ++i) { job.chain[i] = ReadWriteTransformHandle.Bind(animator, chain[i]); job.steps[i] = steps[i]; job.weights[i] = Mathf.Clamp01(data.curve.Evaluate(steps[i])); } job.rotations[0] = Quaternion.identity; job.rotations[chain.Length - 1] = Quaternion.identity; for (int i = 1; i < chain.Length - 1; ++i) { job.rotations[i] = Quaternion.Inverse(Quaternion.Lerp(chain[0].rotation, chain[chain.Length - 1].rotation, job.weights[i])) * chain[i].rotation; } return(job); }
public static void SolveTwoBoneIK( AnimationStream stream, ReadWriteTransformHandle root, ReadWriteTransformHandle mid, ReadWriteTransformHandle tip, ReadOnlyTransformHandle target, ReadOnlyTransformHandle hint, float posWeight, float rotWeight, float hintWeight, AffineTransform targetOffset ) { Vector3 aPosition = root.GetPosition(stream); Vector3 bPosition = mid.GetPosition(stream); Vector3 cPosition = tip.GetPosition(stream); target.GetGlobalTR(stream, out Vector3 targetPos, out Quaternion targetRot); Vector3 tPosition = Vector3.Lerp(cPosition, targetPos + targetOffset.translation, posWeight); Quaternion tRotation = Quaternion.Lerp(tip.GetRotation(stream), targetRot * targetOffset.rotation, rotWeight); bool hasHint = hint.IsValid(stream) && hintWeight > 0f; Vector3 ab = bPosition - aPosition; Vector3 bc = cPosition - bPosition; Vector3 ac = cPosition - aPosition; Vector3 at = tPosition - aPosition; float abLen = ab.magnitude; float bcLen = bc.magnitude; float acLen = ac.magnitude; float atLen = at.magnitude; float oldAbcAngle = TriangleAngle(acLen, abLen, bcLen); float newAbcAngle = TriangleAngle(atLen, abLen, bcLen); // Bend normal strategy is to take whatever has been provided in the animation // stream to minimize configuration changes, however if this is collinear // try computing a bend normal given the desired target position. // If this also fails, try resolving axis using hint if provided. Vector3 axis = Vector3.Cross(ab, bc); if (axis.sqrMagnitude < k_SqrEpsilon) { axis = hasHint ? Vector3.Cross(hint.GetPosition(stream) - aPosition, bc) : Vector3.zero; if (axis.sqrMagnitude < k_SqrEpsilon) { axis = Vector3.Cross(at, bc); } if (axis.sqrMagnitude < k_SqrEpsilon) { axis = Vector3.up; } } axis = Vector3.Normalize(axis); float a = 0.5f * (oldAbcAngle - newAbcAngle); float sin = Mathf.Sin(a); float cos = Mathf.Cos(a); Quaternion deltaR = new Quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos); mid.SetRotation(stream, deltaR * mid.GetRotation(stream)); cPosition = tip.GetPosition(stream); ac = cPosition - aPosition; root.SetRotation(stream, QuaternionExt.FromToRotation(ac, at) * root.GetRotation(stream)); if (hasHint) { float acSqrMag = ac.sqrMagnitude; if (acSqrMag > 0f) { bPosition = mid.GetPosition(stream); cPosition = tip.GetPosition(stream); ab = bPosition - aPosition; ac = cPosition - aPosition; Vector3 acNorm = ac / Mathf.Sqrt(acSqrMag); Vector3 ah = hint.GetPosition(stream) - aPosition; Vector3 abProj = ab - acNorm * Vector3.Dot(ab, acNorm); Vector3 ahProj = ah - acNorm * Vector3.Dot(ah, acNorm); float maxReach = abLen + bcLen; if (abProj.sqrMagnitude > (maxReach * maxReach * 0.001f) && ahProj.sqrMagnitude > 0f) { Quaternion hintR = QuaternionExt.FromToRotation(abProj, ahProj); hintR.x *= hintWeight; hintR.y *= hintWeight; hintR.z *= hintWeight; root.SetRotation(stream, hintR * root.GetRotation(stream)); } } } tip.SetRotation(stream, tRotation); }
public static void PassThrough(AnimationStream stream, ReadWriteTransformHandle handle) { handle.GetLocalTRS(stream, out Vector3 position, out Quaternion rotation, out Vector3 scale); handle.SetLocalTRS(stream, position, rotation, scale); }