public override MultiRotationConstraintJob Create(Animator animator, ref T data) { var job = new MultiRotationConstraintJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.driven = TransformHandle.Bind(animator, data.constrainedObject); job.drivenParent = TransformHandle.Bind(animator, data.constrainedObject.parent); job.drivenOffsetIdx = cacheBuilder.Add(data.offset); var src = data.sourceObjects; var srcWeights = data.sourceWeights; job.sources = new NativeArray <TransformHandle>(src.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.sourceOffsets = new NativeArray <Quaternion>(src.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.sourceWeightStartIdx = cacheBuilder.AllocateChunk(srcWeights.Length); Quaternion drivenRot = data.constrainedObject.rotation; for (int i = 0; i < src.Length; ++i) { job.sources[i] = TransformHandle.Bind(animator, src[i]); cacheBuilder.SetValue(job.sourceWeightStartIdx, i, srcWeights[i]); job.sourceOffsets[i] = data.maintainOffset ? (Quaternion.Inverse(src[i].rotation) * drivenRot) : Quaternion.identity; } job.axesMask = new Vector3( System.Convert.ToSingle(data.constrainedXAxis), System.Convert.ToSingle(data.constrainedYAxis), System.Convert.ToSingle(data.constrainedZAxis) ); job.cache = cacheBuilder.Build(); return(job); }
public override TwoBoneIKConstraintJob Create(Animator animator, ref T data) { var job = new TwoBoneIKConstraintJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.root = TransformHandle.Bind(animator, data.root); job.mid = TransformHandle.Bind(animator, data.mid); job.tip = TransformHandle.Bind(animator, data.tip); job.target = TransformHandle.Bind(animator, data.target); if (data.hint != null) { job.hint = TransformHandle.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.targetPositionWeightIdx = cacheBuilder.Add(data.targetPositionWeight); job.targetRotationWeightIdx = cacheBuilder.Add(data.targetRotationWeight); job.hintWeightIdx = cacheBuilder.Add(data.hintWeight); job.cache = cacheBuilder.Build(); return(job); }
public override DampedTransformJob Create(Animator animator, ref T data) { var job = new DampedTransformJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.driven = TransformHandle.Bind(animator, data.constrainedObject); job.source = TransformHandle.Bind(animator, data.source); var drivenTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation); var sourceTx = new AffineTransform(data.source.position, data.source.rotation); job.localBindTx = sourceTx.InverseMul(drivenTx); job.prevDrivenTx = drivenTx; job.dampPositionIdx = cacheBuilder.Add(data.dampPosition); job.dampRotationIdx = cacheBuilder.Add(data.dampRotation); if (data.maintainAim && AnimationRuntimeUtils.SqrDistance(data.constrainedObject.position, data.source.position) > 0f) { job.aimBindAxis = Quaternion.Inverse(data.constrainedObject.rotation) * (sourceTx.translation - drivenTx.translation).normalized; } else { job.aimBindAxis = Vector3.zero; } job.cache = cacheBuilder.Build(); return(job); }
public override BlendConstraintJob Create(Animator animator, ref T data) { var job = new BlendConstraintJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.driven = TransformHandle.Bind(animator, data.constrainedObject); job.sourceA = TransformHandle.Bind(animator, data.sourceA); job.sourceB = TransformHandle.Bind(animator, data.sourceB); job.optionsIdx = cacheBuilder.Add(BlendConstraintJob.PackFlags(data.blendPosition, data.blendRotation)); job.sourceAOffset = job.sourceBOffset = AffineTransform.identity; if (data.maintainPositionOffsets) { var drivenPos = data.constrainedObject.position; job.sourceAOffset.translation = drivenPos - data.sourceA.position; job.sourceBOffset.translation = drivenPos - data.sourceB.position; } if (data.maintainRotationOffsets) { var drivenRot = data.constrainedObject.rotation; job.sourceAOffset.rotation = Quaternion.Inverse(data.sourceA.rotation) * drivenRot; job.sourceBOffset.rotation = Quaternion.Inverse(data.sourceB.rotation) * drivenRot; } job.positionWeightIdx = cacheBuilder.Add(data.positionWeight); job.rotationWeightIdx = cacheBuilder.Add(data.rotationWeight); job.cache = cacheBuilder.Build(); return(job); }
public override OverrideTransformJob Create(Animator animator, ref T data) { var job = new OverrideTransformJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.driven = TransformHandle.Bind(animator, data.constrainedObject); if (data.source != 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 = TransformHandle.Bind(animator, data.source); var sourceLocalTx = new AffineTransform(data.source.localPosition, data.source.localRotation); job.sourceInvLocalBindTx = sourceLocalTx.Inverse(); var sourceWorldTx = new AffineTransform(data.source.position, data.source.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.positionIdx = cacheBuilder.Add(data.position); job.rotationIdx = cacheBuilder.Add(data.rotation); job.positionWeightIdx = cacheBuilder.Add(data.positionWeight); job.rotationWeightIdx = cacheBuilder.Add(data.rotationWeight); job.cache = cacheBuilder.Build(); return(job); }
public override MultiParentConstraintJob Create(Animator animator, ref T data) { var job = new MultiParentConstraintJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.driven = TransformHandle.Bind(animator, data.constrainedObject); job.drivenParent = TransformHandle.Bind(animator, data.constrainedObject.parent); var src = data.sourceObjects; var srcWeights = data.sourceWeights; job.sources = new NativeArray <TransformHandle>(src.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.sourceOffsets = new NativeArray <AffineTransform>(src.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.sourceWeightStartIdx = cacheBuilder.AllocateChunk(srcWeights.Length); var drivenTx = new AffineTransform(data.constrainedObject.position, data.constrainedObject.rotation); for (int i = 0; i < src.Length; ++i) { job.sources[i] = TransformHandle.Bind(animator, src[i]); cacheBuilder.SetValue(job.sourceWeightStartIdx, i, srcWeights[i]); var srcTx = new AffineTransform(src[i].position, src[i].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) ); job.cache = cacheBuilder.Build(); return(job); }
public override ChainIKConstraintJob Create(Animator animator, ref T data) { 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 <TransformHandle>(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] = TransformHandle.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 = TransformHandle.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; } var cacheBuilder = new AnimationJobCacheBuilder(); job.chainRotationWeightIdx = cacheBuilder.Add(data.chainRotationWeight); job.tipRotationWeightIdx = cacheBuilder.Add(data.tipRotationWeight); job.maxIterationsIdx = cacheBuilder.Add(data.maxIterations); job.toleranceIdx = cacheBuilder.Add(data.tolerance); job.cache = cacheBuilder.Build(); return(job); }
public static TransformHandle Bind(Animator animator, Transform transform) { TransformHandle handle = new TransformHandle(); if (transform == null) { return(handle); } handle.m_InStream = (byte)(transform.IsChildOf(animator.transform) ? 1 : 0); if (handle.m_InStream == 1) { handle.m_StreamHandle = animator.BindStreamTransform(transform); } else { handle.m_SceneHandle = animator.BindSceneTransform(transform); } return(handle); }
public override MultiReferentialConstraintJob Create(Animator animator, ref T data) { var job = new MultiReferentialConstraintJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.driverIdx = cacheBuilder.Add(data.driver); var sources = data.sourceObjects; job.sources = new NativeArray <TransformHandle>(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] = TransformHandle.Bind(animator, sources[i].transform); job.sourceBindTx[i] = new AffineTransform(sources[i].position, sources[i].rotation); } job.cache = cacheBuilder.Build(); job.UpdateOffsets(); return(job); }
public override TwistCorrectionJob Create(Animator animator, ref T data) { var job = new TwistCorrectionJob(); var cacheBuilder = new AnimationJobCacheBuilder(); job.source = TransformHandle.Bind(animator, data.source); job.sourceInverseBindRotation = Quaternion.Inverse(data.source.localRotation); job.axisMask = data.twistAxis; var twistNodes = data.twistNodes; var twistNodeWeights = data.twistNodeWeights; job.twistNodes = new NativeArray <TransformHandle>(twistNodes.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); job.twistWeightStartIdx = cacheBuilder.AllocateChunk(twistNodes.Length); for (int i = 0; i < twistNodes.Length; ++i) { job.twistNodes[i] = TransformHandle.Bind(animator, twistNodes[i]); cacheBuilder.SetValue(job.twistWeightStartIdx, i, twistNodeWeights[i]); } job.cache = cacheBuilder.Build(); return(job); }
public static void PassThrough(AnimationStream stream, TransformHandle handle) { handle.SetLocalPosition(stream, handle.GetLocalPosition(stream)); handle.SetLocalRotation(stream, handle.GetLocalRotation(stream)); handle.SetLocalScale(stream, handle.GetLocalScale(stream)); }
public static void SolveTwoBoneIK( AnimationStream stream, TransformHandle root, TransformHandle mid, TransformHandle tip, TransformHandle target, TransformHandle hint, float posWeight, float rotWeight, float hintWeight, Vector2 limbLengths, AffineTransform targetOffset ) { Vector3 aPosition = root.GetPosition(stream); Vector3 bPosition = mid.GetPosition(stream); Vector3 cPosition = tip.GetPosition(stream); Vector3 tPosition = Vector3.Lerp(cPosition, target.GetPosition(stream) + targetOffset.translation, posWeight); Quaternion tRotation = Quaternion.Lerp(tip.GetRotation(stream), target.GetRotation(stream) * 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 oldAbcAngle = TriangleAngle(ac.magnitude, limbLengths[0], limbLengths[1]); float newAbcAngle = TriangleAngle(at.magnitude, limbLengths[0], limbLengths[1]); // 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 = Vector3.Cross(at, bc); if (axis.sqrMagnitude < k_SqrEpsilon) { axis = hasHint ? Vector3.Cross(hint.GetPosition(stream) - aPosition, bc) : 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 = limbLengths[0] + limbLengths[1]; 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); }