public void ProcessAnimation(AnimationStream stream) { float jobWeight = stream.GetInputWeight(0); if (jobWeight > 0f) { AffineTransform overrideTx; if (source.IsValid(stream)) { var sourceLocalTx = new AffineTransform(source.GetLocalPosition(stream), source.GetLocalRotation(stream)); var sourceToSpaceRot = cache.Get <Quaternion>(sourceToCurrSpaceRotIdx); overrideTx = Quaternion.Inverse(sourceToSpaceRot) * (sourceInvLocalBindTx * sourceLocalTx) * sourceToSpaceRot; } else { overrideTx = new AffineTransform(cache.Get <Vector3>(positionIdx), Quaternion.Euler(cache.Get <Vector3>(rotationIdx))); } Space overrideSpace = (Space)cache.GetRaw(spaceIdx); var posW = cache.GetRaw(positionWeightIdx) * jobWeight; var rotW = cache.GetRaw(rotationWeightIdx) * jobWeight; switch (overrideSpace) { case Space.World: driven.SetPosition(stream, Vector3.Lerp(driven.GetPosition(stream), overrideTx.translation, posW)); driven.SetRotation(stream, Quaternion.Lerp(driven.GetRotation(stream), overrideTx.rotation, rotW)); break; case Space.Local: driven.SetLocalPosition(stream, Vector3.Lerp(driven.GetLocalPosition(stream), overrideTx.translation, posW)); driven.SetLocalRotation(stream, Quaternion.Lerp(driven.GetLocalRotation(stream), overrideTx.rotation, rotW)); break; case Space.Pivot: var drivenLocalTx = new AffineTransform(driven.GetLocalPosition(stream), driven.GetLocalRotation(stream)); overrideTx = drivenLocalTx * overrideTx; driven.SetLocalPosition(stream, Vector3.Lerp(drivenLocalTx.translation, overrideTx.translation, posW)); driven.SetLocalRotation(stream, Quaternion.Lerp(drivenLocalTx.rotation, overrideTx.rotation, rotW)); break; default: break; } } else { AnimationRuntimeUtils.PassThrough(stream, driven); } }
public void ProcessAnimation(AnimationStream stream) { float jobWeight = stream.GetInputWeight(0); if (jobWeight > 0f) { var flags = (int)cache.GetRaw(optionsIdx); if ((flags & k_BlendTranslationMask) != 0) { Vector3 posBlend = Vector3.Lerp( sourceA.GetPosition(stream) + sourceAOffset.translation, sourceB.GetPosition(stream) + sourceBOffset.translation, cache.GetRaw(positionWeightIdx) ); driven.SetPosition(stream, Vector3.Lerp(driven.GetPosition(stream), posBlend, jobWeight)); } else { driven.SetLocalPosition(stream, driven.GetLocalPosition(stream)); } if ((flags & k_BlendRotationMask) != 0) { Quaternion rotBlend = Quaternion.Lerp( sourceA.GetRotation(stream) * sourceAOffset.rotation, sourceB.GetRotation(stream) * sourceBOffset.rotation, cache.GetRaw(rotationWeightIdx) ); driven.SetRotation(stream, Quaternion.Lerp(driven.GetRotation(stream), rotBlend, jobWeight)); } else { driven.SetLocalRotation(stream, driven.GetLocalRotation(stream)); } } else { AnimationRuntimeUtils.PassThrough(stream, driven); } }
public void ProcessAnimation(AnimationStream stream) { float jobWeight = stream.GetInputWeight(0); if (jobWeight > 0f) { var sourceTx = new AffineTransform(source.GetPosition(stream), source.GetRotation(stream)); var targetTx = sourceTx * localBindTx; var drivenPos = driven.GetPosition(stream); targetTx.translation = Vector3.Lerp(drivenPos, targetTx.translation, jobWeight); var factorDeltaTime = k_DampFactor * stream.deltaTime; var dampPosW = 1f - cache.GetRaw(dampPositionIdx); var finalPos = Vector3.Lerp(prevDrivenTx.translation, targetTx.translation, dampPosW * dampPosW * factorDeltaTime); var drivenRot = driven.GetRotation(stream); if (Vector3.Dot(aimBindAxis, aimBindAxis) > 0f) { var fromDir = drivenRot * aimBindAxis; var toDir = sourceTx.translation - finalPos; targetTx.rotation = Quaternion.AngleAxis(Vector3.Angle(fromDir, toDir), Vector3.Cross(fromDir, toDir).normalized) * drivenRot; } targetTx.rotation = Quaternion.Lerp(drivenRot, targetTx.rotation, jobWeight); var dampRotW = 1f - cache.GetRaw(dampRotationIdx); var finalRot = Quaternion.Lerp(prevDrivenTx.rotation, targetTx.rotation, dampRotW * dampRotW * factorDeltaTime); driven.SetPosition(stream, finalPos); driven.SetRotation(stream, finalRot); prevDrivenTx.translation = finalPos; prevDrivenTx.rotation = finalRot; } else { AnimationRuntimeUtils.PassThrough(stream, driven); } }
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); }