public void ProcessAnimation(AnimationStream stream) { float w = jobWeight.Get(stream); if (w > 0f) { //We only need to process if the weight is greater than 0 float minOffset = offsetFromGround.Get(stream); Vector3 normal = groundNormal.Get(stream); float angle = Vector3.Angle(Vector3.up, normal); float offset = minOffset / math.sin(math.radians(90 - angle)); Vector3 targetPosition = groundPoint.Get(stream) + Vector3.up * offset; Vector3 sourcePosition = source.GetPosition(stream); if (targetPosition.y > sourcePosition.y) { constrained.SetPosition(stream, math.lerp(sourcePosition, targetPosition, w)); Quaternion rotation = quaternion.LookRotation(source.GetRotation(stream) * Vector3.forward, normal); constrained.SetRotation(stream, rotation); } else { constrained.SetPosition(stream, sourcePosition); constrained.SetRotation(stream, source.GetRotation(stream)); } } }
public void ProcessAnimation(AnimationStream stream) { float w = jobWeight.Get(stream); if (w > 0f) { AnimationStreamHandleUtility.ReadFloats(stream, sourceWeights, weightBuffer); float sumWeights = AnimationRuntimeUtils.Sum(weightBuffer); if (sumWeights < k_Epsilon) { AnimationRuntimeUtils.PassThrough(stream, driven); return; } float weightScale = sumWeights > 1f ? 1f / sumWeights : 1f; Vector3 currentWPos = driven.GetPosition(stream); Vector3 accumPos = currentWPos; for (int i = 0; i < sourceTransforms.Length; ++i) { var normalizedWeight = weightBuffer[i] * weightScale; if (normalizedWeight < k_Epsilon) { continue; } ReadOnlyTransformHandle sourceTransform = sourceTransforms[i]; accumPos += (sourceTransform.GetPosition(stream) + sourceOffsets[i] - currentWPos) * normalizedWeight; // Required to update handles with binding info. sourceTransforms[i] = sourceTransform; } // Convert accumPos to local space if (drivenParent.IsValid(stream)) { drivenParent.GetGlobalTR(stream, out Vector3 parentWPos, out Quaternion parentWRot); var parentTx = new AffineTransform(parentWPos, parentWRot); accumPos = parentTx.InverseTransform(accumPos); } Vector3 currentLPos = driven.GetLocalPosition(stream); if (Vector3.Dot(axesMask, axesMask) < 3f) { accumPos = AnimationRuntimeUtils.Lerp(currentLPos, accumPos, axesMask); } driven.SetLocalPosition(stream, Vector3.Lerp(currentLPos, accumPos + drivenOffset.Get(stream), w)); } else { AnimationRuntimeUtils.PassThrough(stream, driven); } }
Vector3 ComputeWorldUpVector(AnimationStream stream) { var result = Vector3.up; switch (worldUpType) { case WorldUpType.None: result = Vector3.zero; break; case WorldUpType.SceneUp: // the scene Up vector and the World Up vector are the same thing break; case WorldUpType.ObjectUp: { // the target's Up vector points to the up object var referencePos = Vector3.zero; if (worldUpObject.IsValid(stream)) { referencePos = worldUpObject.GetPosition(stream); } var targetPos = driven.GetPosition(stream); result = (referencePos - targetPos).normalized; break; } case WorldUpType.ObjectRotationUp: { var upRotation = Quaternion.identity; if (worldUpObject.IsValid(stream)) { upRotation = worldUpObject.GetRotation(stream); } // if no object is specified, the up vector is defined relative to the scene world space result = upRotation * worldUpAxis; break; } case WorldUpType.Vector: result = worldUpAxis; break; default: break; } return(result); }
public void ProcessAnimation(AnimationStream stream) { float w = jobWeight.Get(stream); if (w > 0f) { if (blendPosition.Get(stream)) { Vector3 posBlend = Vector3.Lerp( sourceA.GetPosition(stream) + sourceAOffset.translation, sourceB.GetPosition(stream) + sourceBOffset.translation, positionWeight.Get(stream) ); driven.SetPosition(stream, Vector3.Lerp(driven.GetPosition(stream), posBlend, w)); } else { driven.SetLocalPosition(stream, driven.GetLocalPosition(stream)); } if (blendRotation.Get(stream)) { Quaternion rotBlend = Quaternion.Lerp( sourceA.GetRotation(stream) * sourceAOffset.rotation, sourceB.GetRotation(stream) * sourceBOffset.rotation, rotationWeight.Get(stream) ); driven.SetRotation(stream, Quaternion.Lerp(driven.GetRotation(stream), rotBlend, w)); } else { driven.SetLocalRotation(stream, driven.GetLocalRotation(stream)); } } else { AnimationRuntimeUtils.PassThrough(stream, driven); } }
public void ProcessAnimation(AnimationStream stream) { float w = jobWeight.Get(stream); if (w > 0f) { for (int i = 0; i < chain.Length; ++i) { var handle = chain[i]; linkPositions[i] = handle.GetPosition(stream); chain[i] = handle; } int tipIndex = chain.Length - 1; if (AnimationRuntimeUtils.SolveFABRIK(ref linkPositions, ref linkLengths, target.GetPosition(stream) + targetOffset.translation, cache.GetRaw(toleranceIdx), maxReach, (int)cache.GetRaw(maxIterationsIdx))) { var chainRWeight = chainRotationWeight.Get(stream) * w; for (int i = 0; i < tipIndex; ++i) { var prevDir = chain[i + 1].GetPosition(stream) - chain[i].GetPosition(stream); var newDir = linkPositions[i + 1] - linkPositions[i]; var rot = chain[i].GetRotation(stream); chain[i].SetRotation(stream, Quaternion.Lerp(rot, QuaternionExt.FromToRotation(prevDir, newDir) * rot, chainRWeight)); } } chain[tipIndex].SetRotation( stream, Quaternion.Lerp( chain[tipIndex].GetRotation(stream), target.GetRotation(stream) * targetOffset.rotation, tipRotationWeight.Get(stream) * w ) ); } else { for (int i = 0; i < chain.Length; ++i) { AnimationRuntimeUtils.PassThrough(stream, chain[i]); } } }
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 void ProcessAnimation(AnimationStream stream) { float w = jobWeight.Get(stream); if (w > 0f) { AnimationStreamHandleUtility.ReadFloats(stream, sourceWeights, weightBuffer); float sumWeights = AnimationRuntimeUtils.Sum(weightBuffer); if (sumWeights < k_Epsilon) { AnimationRuntimeUtils.PassThrough(stream, driven); return; } float weightScale = sumWeights > 1f ? 1f / sumWeights : 1f; Vector2 minMaxAngles = new Vector2(minLimit.Get(stream), maxLimit.Get(stream)); var drivenWPos = driven.GetPosition(stream); var drivenLRot = driven.GetLocalRotation(stream); var drivenParentInvRot = Quaternion.Inverse(drivenParent.GetRotation(stream)); Quaternion accumDeltaRot = QuaternionExt.zero; var fromDir = drivenLRot * aimAxis; float accumWeights = 0f; for (int i = 0; i < sourceTransforms.Length; ++i) { var normalizedWeight = weightBuffer[i] * weightScale; if (normalizedWeight < k_Epsilon) { continue; } ReadOnlyTransformHandle sourceTransform = sourceTransforms[i]; var toDir = drivenParentInvRot * (sourceTransform.GetPosition(stream) - drivenWPos); if (toDir.sqrMagnitude < k_Epsilon) { continue; } var crossDir = Vector3.Cross(fromDir, toDir).normalized; if (Vector3.Dot(axesMask, axesMask) < 3f) { crossDir = AnimationRuntimeUtils.Select(Vector3.zero, crossDir, axesMask).normalized; if (Vector3.Dot(crossDir, crossDir) > k_Epsilon) { fromDir = AnimationRuntimeUtils.ProjectOnPlane(fromDir, crossDir); toDir = AnimationRuntimeUtils.ProjectOnPlane(toDir, crossDir); } else { toDir = fromDir; } } var rotToSource = Quaternion.AngleAxis( Mathf.Clamp(Vector3.Angle(fromDir, toDir), minMaxAngles.x, minMaxAngles.y), crossDir ); accumDeltaRot = QuaternionExt.Add( accumDeltaRot, QuaternionExt.Scale(sourceOffsets[i] * rotToSource, normalizedWeight) ); // Required to update handles with binding info. sourceTransforms[i] = sourceTransform; accumWeights += normalizedWeight; } accumDeltaRot = QuaternionExt.NormalizeSafe(accumDeltaRot); if (accumWeights < 1f) { accumDeltaRot = Quaternion.Lerp(Quaternion.identity, accumDeltaRot, accumWeights); } Quaternion newRot = accumDeltaRot * drivenLRot; if (Vector3.Dot(axesMask, axesMask) < 3f) { newRot = Quaternion.Euler(AnimationRuntimeUtils.Select(drivenLRot.eulerAngles, newRot.eulerAngles, axesMask)); } var offset = drivenOffset.Get(stream); if (Vector3.Dot(offset, offset) > 0f) { newRot *= Quaternion.Euler(offset); } driven.SetLocalRotation(stream, Quaternion.Lerp(drivenLRot, newRot, w)); } else { AnimationRuntimeUtils.PassThrough(stream, driven); } }
public void ProcessAnimation(AnimationStream stream) { float w = jobWeight.Get(stream); if (w > 0f) { AnimationStreamHandleUtility.ReadFloats(stream, sourceWeights, weightBuffer); float sumWeights = AnimationRuntimeUtils.Sum(weightBuffer); if (sumWeights < k_Epsilon) { return; } float weightScale = sumWeights > 1f ? 1f / sumWeights : 1f; Vector2 minMaxAngles = new Vector2(minLimit.Get(stream), maxLimit.Get(stream)); driven.GetGlobalTR(stream, out Vector3 currentWPos, out Quaternion currentWRot); Vector3 currentDir = currentWRot * aimAxis; Quaternion accumDeltaRot = QuaternionExt.zero; float accumWeights = 0f; for (int i = 0; i < sourceTransforms.Length; ++i) { var normalizedWeight = weightBuffer[i] * weightScale; if (normalizedWeight < k_Epsilon) { continue; } ReadOnlyTransformHandle sourceTransform = sourceTransforms[i]; var toDir = sourceTransform.GetPosition(stream) - currentWPos; if (toDir.sqrMagnitude < k_Epsilon) { continue; } var rotToSource = Quaternion.AngleAxis( Mathf.Clamp(Vector3.Angle(currentDir, toDir), minMaxAngles.x, minMaxAngles.y), Vector3.Cross(currentDir, toDir).normalized ); accumDeltaRot = QuaternionExt.Add( accumDeltaRot, QuaternionExt.Scale(sourceOffsets[i] * rotToSource, normalizedWeight) ); // Required to update handles with binding info. sourceTransforms[i] = sourceTransform; accumWeights += normalizedWeight; } accumDeltaRot = QuaternionExt.NormalizeSafe(accumDeltaRot); if (accumWeights < 1f) { accumDeltaRot = Quaternion.Lerp(Quaternion.identity, accumDeltaRot, accumWeights); } Quaternion newRot = accumDeltaRot * currentWRot; // Convert newRot to local space if (drivenParent.IsValid(stream)) { newRot = Quaternion.Inverse(drivenParent.GetRotation(stream)) * newRot; } Quaternion currentLRot = driven.GetLocalRotation(stream); if (Vector3.Dot(axesMask, axesMask) < 3f) { newRot = Quaternion.Euler(AnimationRuntimeUtils.Lerp(currentLRot.eulerAngles, newRot.eulerAngles, axesMask)); } var offset = drivenOffset.Get(stream); if (Vector3.Dot(offset, offset) > 0f) { newRot *= Quaternion.Euler(offset); } driven.SetLocalRotation(stream, Quaternion.Lerp(currentLRot, newRot, w)); } else { AnimationRuntimeUtils.PassThrough(stream, driven); } }