public void Execute(RenderContext ctx, KernelData data, ref KernelDefs ports) { data.ProfilerMarker.Begin(); var output = ctx.Resolve(ref ports.Output); output.CopyFrom(ctx.Resolve(in ports.Input)); var weightValue = ctx.Resolve(ports.Weight); if (weightValue > 0f) { var stream = AnimationStreamProvider.Create(data.RigDefinition, output); if (stream.IsNull) { data.ProfilerMarker.End(); return; } var pos = stream.GetLocalToRigTranslation(data.Data.BoneIndex); pos += data.Data.offset * weightValue; stream.SetLocalToRigTranslation(data.Data.BoneIndex, pos); } data.ProfilerMarker.End(); }
public void Execute(RenderContext ctx, KernelData data, ref KernelDefs ports) { data.ProfilerMarker.Begin(); CopyInputToOutputBuffer(ctx, ports.Input, ports.Output); var weightValue = ctx.Resolve(ports.Weight); if (weightValue > 0f) { var ouptutArray = ctx.Resolve(ref ports.Output); var blendPosition = ctx.Resolve(ports.BlendPosition); var blendRotation = ctx.Resolve(ports.BlendRotation); var stream = AnimationStreamProvider.Create(data.RigDefinition, ouptutArray); if (stream.IsNull || (blendPosition == 0 && blendRotation == 0)) { data.ProfilerMarker.End(); return; } stream.GetLocalToRigTR(data.Data.Constrained, out float3 constrainedT, out quaternion constrainedR); if (blendPosition == 1) { var positionWeight = ctx.Resolve(ports.PositionWeight); float3 posBlend = math.lerp( stream.GetLocalToRigTranslation(data.Data.SourceA) + data.Data.SourceAOffset.pos, stream.GetLocalToRigTranslation(data.Data.SourceB) + data.Data.SourceBOffset.pos, positionWeight ); stream.SetLocalToRigTranslation( data.Data.Constrained, math.lerp(constrainedT, posBlend, weightValue) ); } if (blendRotation == 1) { var rotationWeight = ctx.Resolve(ports.RotationWeight); quaternion rotBlend = math.nlerp( math.mul(stream.GetLocalToRigRotation(data.Data.SourceA), data.Data.SourceAOffset.rot), math.mul(stream.GetLocalToRigRotation(data.Data.SourceB), data.Data.SourceBOffset.rot), rotationWeight ); stream.SetLocalToRigRotation( data.Data.Constrained, math.nlerp(constrainedR, rotBlend, weightValue) ); } } data.ProfilerMarker.End(); }
public void Execute(RenderContext context, KernelData data, ref KernelDefs ports) { data.ProfileMarker.Begin(); var output = context.Resolve(ref ports.Output); output.CopyFrom(context.Resolve(in ports.Input)); var stream = AnimationStreamProvider.Create(data.RigDefinition, output); if (stream.IsNull) { data.ProfileMarker.End(); return; } var driverIndex = data.Settings.boneReferences.DriverIndex; var twistIndexA = data.Settings.boneReferences.TwistJointA; var twistIndexB = data.Settings.boneReferences.TwistJointB; var twistIndexC = data.Settings.boneReferences.TwistJointC; if (driverIndex != -1) { var driverRot = stream.GetLocalToParentRotation(driverIndex); var driverBindRot = data.RigDefinition.Value.DefaultValues.LocalRotations[driverIndex]; var driverDelta = math.mul(math.inverse(driverBindRot), driverRot); var twist = new quaternion(0.0f, driverDelta.value.y * data.Settings.twistMult, 0.0f, driverDelta.value.w); if (twistIndexA != -1) { var twistRotation = mathex.lerp(quaternion.identity, twist, data.Settings.factors.FactorA); stream.SetLocalToParentRotation(data.Settings.boneReferences.TwistJointA, twistRotation); } if (twistIndexB != -1) { var twistRotation = mathex.lerp(quaternion.identity, twist, data.Settings.factors.FactorB); stream.SetLocalToParentRotation(data.Settings.boneReferences.TwistJointB, twistRotation); } if (twistIndexC != -1) { var twistRotation = mathex.lerp(quaternion.identity, twist, data.Settings.factors.FactorC); stream.SetLocalToParentRotation(data.Settings.boneReferences.TwistJointC, twistRotation); } } data.ProfileMarker.End(); }
public void Execute(RenderContext context, KernelData data, ref KernelDefs ports) { data.ProfileMarker.Begin(); var output = context.Resolve(ref ports.Output); output.CopyFrom(context.Resolve(in ports.Input)); var bankAmount = context.Resolve(ports.BankAmount); if (math.abs(bankAmount) < 0.001f) { data.ProfileMarker.End(); return; } var stream = AnimationStreamProvider.Create(data.RigDefinition, output); if (stream.IsNull) { data.ProfileMarker.End(); return; } var bankPosition = data.BankingData.Position * bankAmount * 0.01f; var weightedBankRotation = quaternion.Euler(math.radians(data.BankingData.EulerRotation * bankAmount * (1 - data.BankingData.SpineMultiplier))); var bankRotation = quaternion.Euler(math.radians(data.BankingData.EulerRotation * bankAmount)); var footPosition = data.BankingData.Position * bankAmount * 0.01f * data.BankingData.FootMultiplier; //TODO: A multiplier here?? // Rig axis are reverted for left and right feet. var leftFootRotation = quaternion.Euler(math.radians(-1.0f * data.BankingData.EulerRotation * bankAmount * data.BankingData.FootMultiplier)); var rightFootRotation = quaternion.Euler(math.radians(data.BankingData.EulerRotation * bankAmount * data.BankingData.FootMultiplier)); // No centre of mass so for now we use the hips var hipPos = stream.GetLocalToRigTranslation(data.BankingData.boneReferences.HipsIndex); var hipRot = stream.GetLocalToRigRotation(data.BankingData.boneReferences.HipsIndex); stream.SetLocalToRigRotation(data.BankingData.boneReferences.HipsIndex, math.mul(weightedBankRotation, hipRot)); stream.SetLocalToRigTranslation(data.BankingData.boneReferences.HipsIndex, math.mul(bankRotation, hipPos) + bankPosition); // Head banking var multiplier = bankAmount * 0.075f * data.BankingData.HeadMultiplier / k_numHeadHandles; // Head and neck have the same range of movement [-40, 40] degrees. var axis = quaternion.AxisAngle(new float3(0f, -1f, -1f), math.radians(40f)); var weightedRot = mathex.quatWeight(axis, multiplier); var neck = stream.GetLocalToRigRotation(data.BankingData.boneReferences.NeckLeftRightIndex); stream.SetLocalToRigRotation(data.BankingData.boneReferences.NeckLeftRightIndex, math.mul(weightedRot, neck)); var head = stream.GetLocalToRigRotation(data.BankingData.boneReferences.HeadLeftRightIndex); stream.SetLocalToRigRotation(data.BankingData.boneReferences.HeadLeftRightIndex, math.mul(weightedRot, head)); // Spine banking multiplier = bankAmount * 0.075f * data.BankingData.SpineMultiplier / k_numSpineHandles; // Spine and chest have the same range of movement [-40, 40] degrees. axis = quaternion.AxisAngle(new float3(0f, 0f, -1f), math.radians(40f)); weightedRot = mathex.quatWeight(axis, multiplier); var spine = stream.GetLocalToRigRotation(data.BankingData.boneReferences.SpineLeftRightIndex); var chest = stream.GetLocalToRigRotation(data.BankingData.boneReferences.ChestLeftRightIndex); stream.SetLocalToRigRotation(data.BankingData.boneReferences.SpineLeftRightIndex, math.mul(weightedRot, spine)); stream.SetLocalToRigRotation(data.BankingData.boneReferences.ChestLeftRightIndex, math.mul(weightedRot, chest)); // Upper chest has a range of movement of [-20, 20] degrees. axis = quaternion.AxisAngle(new float3(0f, 0f, -1f), math.radians(20f)); weightedRot = mathex.quatWeight(axis, multiplier); var upperChest = stream.GetLocalToRigRotation(data.BankingData.boneReferences.UpperChestLeftRightIndex); stream.SetLocalToRigRotation(data.BankingData.boneReferences.UpperChestLeftRightIndex, math.mul(weightedRot, upperChest)); // Feet IK var leftFootPos = stream.GetLocalToRigTranslation(data.BankingData.boneReferences.LeftFootIKIndex); stream.SetLocalToRigTranslation(data.BankingData.boneReferences.LeftFootIKIndex, leftFootPos + footPosition); var leftFootRot = stream.GetLocalToRigRotation(data.BankingData.boneReferences.LeftFootIKIndex); stream.SetLocalToRigRotation(data.BankingData.boneReferences.LeftFootIKIndex, math.mul(leftFootRot, leftFootRotation)); var rightFootPos = stream.GetLocalToRigTranslation(data.BankingData.boneReferences.RightFootIKIndex); stream.SetLocalToRigTranslation(data.BankingData.boneReferences.RightFootIKIndex, rightFootPos + footPosition); var rightFootRot = stream.GetLocalToRigRotation(data.BankingData.boneReferences.RightFootIKIndex); stream.SetLocalToRigRotation(data.BankingData.boneReferences.RightFootIKIndex, math.mul(rightFootRot, rightFootRotation)); data.ProfileMarker.End(); }
public void Execute(RenderContext ctx, KernelData data, ref KernelDefs ports) { data.ProfilerMarker.Begin(); var output = ctx.Resolve(ref ports.Output); output.CopyFrom(ctx.Resolve(in ports.Input)); var weightValue = ctx.Resolve(ports.Weight); if (weightValue > 0f) { var stream = AnimationStreamProvider.Create(data.RigDefinition, output); if (stream.IsNull) { data.ProfilerMarker.End(); return; } // TODO: (sunek) Get a real number! Requires replicating and incrementing the IK weight in update // ikWeight = Mathf.Clamp01(ikWeight + (1 - settings.enterStateEaseIn)); var ikWeight = data.Data.Weight; var settings = data.Data.Settings; var leftToePos = stream.GetLocalToRigTranslation(data.Data.LeftToeIdx); var rightToePos = stream.GetLocalToRigTranslation(data.Data.RightToeIdx); var leftIkOffset = data.Data.ikOffset.x * ikWeight; var rightIkOffset = data.Data.ikOffset.y * ikWeight; leftToePos += new float3(0f, leftIkOffset, 0f); rightToePos += new float3(0f, rightIkOffset, 0f); var leftAnklePos = stream.GetLocalToRigTranslation(data.Data.LeftFootIkIdx); var rightAnklePos = stream.GetLocalToRigTranslation(data.Data.RightFootIkIdx); var leftAnkleRot = stream.GetLocalToRigRotation(data.Data.LeftFootIkIdx); var rightAnkleRot = stream.GetLocalToRigRotation(data.Data.RightFootIkIdx); var leftAnkleIkPos = new float3(leftAnklePos.x, leftAnklePos.y + leftIkOffset, leftAnklePos.z); var rightAnkleIkPos = new float3(rightAnklePos.x, rightAnklePos.y + rightIkOffset, rightAnklePos.z); var hipHeightOffset = (leftIkOffset + rightIkOffset) * 0.5f; var forwardBackBias = (leftIkOffset - rightIkOffset) * settings.weightShiftHorizontal; // TODO: (sunek) Rework weight shift to move towards actual lower foot? hipHeightOffset += Mathf.Abs(leftIkOffset - rightIkOffset) * settings.weightShiftVertical; var standAngle = math.mul(quaternion.AxisAngle(Vector3.up, math.radians(settings.weightShiftAngle)), data.VectorForward); var hipsPosition = stream.GetLocalToRigTranslation(data.Data.HipsIdx); hipsPosition += new float3(standAngle.x * forwardBackBias, hipHeightOffset, standAngle.z * forwardBackBias); stream.SetLocalToRigTranslation(data.Data.HipsIdx, hipsPosition); // Figure out the normal rotation var leftNormalRot = quaternion.identity; var rightNormalRot = quaternion.identity; if (!data.Data.normalLeftFoot.Equals(float3.zero)) { leftNormalRot = quaternion.LookRotationSafe(data.Data.normalLeftFoot, data.VectorForward); rightNormalRot = quaternion.LookRotationSafe(data.Data.normalRightFoot, data.VectorForward); leftNormalRot = math.mul(leftNormalRot, data.OffsetRotation); rightNormalRot = math.mul(rightNormalRot, data.OffsetRotation); } // Clamp normal rotation var leftAngle = Angle(quaternion.identity, leftNormalRot); var rightAngle = Angle(quaternion.identity, rightNormalRot); if (leftAngle > settings.maxFootRotationOffset && settings.maxFootRotationOffset > 0f) { var fraction = settings.maxFootRotationOffset / leftAngle; leftNormalRot = math.nlerp(Quaternion.identity, leftNormalRot, fraction); } if (rightAngle > settings.maxFootRotationOffset && settings.maxFootRotationOffset > 0f) { var fraction = settings.maxFootRotationOffset / rightAngle; rightNormalRot = math.nlerp(Quaternion.identity, rightNormalRot, fraction); } // Apply rotation to ankle var leftToesMatrix = Matrix4x4.TRS(leftToePos, quaternion.identity, data.VectorOne); var rightToesMatrix = Matrix4x4.TRS(rightToePos, quaternion.identity, data.VectorOne); leftNormalRot = math.normalize(leftNormalRot); rightNormalRot = math.normalize(rightNormalRot); leftAnkleRot = math.normalize(leftAnkleRot); rightAnkleRot = math.normalize(rightAnkleRot); var leftToesNormalDeltaMatrix = Matrix4x4.TRS(leftToePos, leftNormalRot, data.VectorOne) * leftToesMatrix.inverse; var rightToesNormalDeltaMatrix = Matrix4x4.TRS(rightToePos, rightNormalRot, data.VectorOne) * rightToesMatrix.inverse; var leftAnkleMatrix = Matrix4x4.TRS(leftAnkleIkPos, leftAnkleRot, data.VectorOne) * leftToesMatrix.inverse; var rightAnkleMatrix = Matrix4x4.TRS(rightAnkleIkPos, rightAnkleRot, data.VectorOne) * rightToesMatrix.inverse; leftAnkleMatrix = leftToesNormalDeltaMatrix * leftAnkleMatrix * leftToesMatrix; rightAnkleMatrix = rightToesNormalDeltaMatrix * rightAnkleMatrix * rightToesMatrix; // Todo:Find a better way to do this? var leftColumn = leftAnkleMatrix.GetColumn(3); leftAnkleIkPos = new float3(leftColumn[0], leftColumn[1], leftColumn[2]); // TODO: (sunek) Is there a slicing syntax instead? var rightColumn = rightAnkleMatrix.GetColumn(3); rightAnkleIkPos = new float3(rightColumn[0], rightColumn[1], rightColumn[2]); leftAnkleRot = math.nlerp(leftAnkleRot, leftAnkleMatrix.rotation, ikWeight); rightAnkleRot = math.nlerp(rightAnkleRot, rightAnkleMatrix.rotation, ikWeight); // Update ik position // TODO: (sunek) Consider combating leg overstretch var leftPosition = math.lerp(leftAnklePos, leftAnkleIkPos, ikWeight); var rightPosition = math.lerp(rightAnklePos, rightAnkleIkPos, ikWeight); stream.SetLocalToRigTranslation(data.Data.LeftFootIkIdx, leftPosition); stream.SetLocalToRigTranslation(data.Data.RightFootIkIdx, rightPosition); stream.SetLocalToRigRotation(data.Data.LeftFootIkIdx, leftAnkleRot); stream.SetLocalToRigRotation(data.Data.RightFootIkIdx, rightAnkleRot); } data.ProfilerMarker.End(); }
public void Execute(RenderContext ctx, KernelData data, ref KernelDefs ports) { data.ProfilerMarker.Begin(); var output = ctx.Resolve(ref ports.Output); output.CopyFrom(ctx.Resolve(in ports.Input)); var weightValue = ctx.Resolve(ports.Weight); if (weightValue > 0f) { var stream = AnimationStreamProvider.Create(data.RigDefinition, output); if (stream.IsNull) { data.ProfilerMarker.End(); return; } // Use the curve value if defined if (data.IKData.WeightChannelIdx != -1) { weightValue *= stream.GetFloat(data.IKData.WeightChannelIdx); } weightValue = math.clamp(weightValue, 0f, 1f); var targetPositionWeightValue = ctx.Resolve(ports.TargetPositionWeight); var targetRotationWeightValue = ctx.Resolve(ports.TargetRotationWeight); var hintWeightValue = ctx.Resolve(ports.HintWeight); float3 aPos = stream.GetLocalToRigTranslation(data.IKData.Root); float3 bPos = stream.GetLocalToRigTranslation(data.IKData.Mid); float3 cPos = stream.GetLocalToRigTranslation(data.IKData.Tip); stream.GetLocalToRigTR(data.IKData.Target, out float3 targetPos, out quaternion targetRot); float3 tPos = math.lerp(cPos, targetPos + data.IKData.TargetOffset.pos, targetPositionWeightValue * weightValue); quaternion tRot = math.nlerp(stream.GetLocalToRigRotation(data.IKData.Tip), math.mul(targetRot, data.IKData.TargetOffset.rot), targetRotationWeightValue * weightValue); float hintWeight = hintWeightValue * weightValue; bool hasHint = data.IKData.Hint > -1 && hintWeight > 0f; float3 ab = bPos - aPos; float3 bc = cPos - bPos; float3 ac = cPos - aPos; float3 at = tPos - aPos; float oldAbcAngle = TriangleAngle(math.length(ac), data.IKData.LimbLengths); float newAbcAngle = TriangleAngle(math.length(at), data.IKData.LimbLengths); // 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. float3 axis = math.cross(ab, bc); if (math.lengthsq(axis) < k_SqEpsilon) { axis = math.cross(at, bc); if (math.lengthsq(axis) < k_SqEpsilon) { axis = hasHint ? math.cross(stream.GetLocalToRigTranslation(data.IKData.Hint) - aPos, bc) : math.up(); } } axis = math.normalize(axis); float a = 0.5f * (oldAbcAngle - newAbcAngle); float sin = math.sin(a); float cos = math.cos(a); quaternion deltaRot = new quaternion(axis.x * sin, axis.y * sin, axis.z * sin, cos); stream.SetLocalToRigRotation(data.IKData.Mid, math.mul(deltaRot, stream.GetLocalToRigRotation(data.IKData.Mid))); cPos = stream.GetLocalToRigTranslation(data.IKData.Tip); ac = cPos - aPos; stream.SetLocalToRigRotation(data.IKData.Root, math.mul(mathex.fromTo(ac, at), stream.GetLocalToRigRotation(data.IKData.Root))); if (hasHint) { float acLengthSq = math.lengthsq(ac); if (acLengthSq > 0f) { bPos = stream.GetLocalToRigTranslation(data.IKData.Mid); cPos = stream.GetLocalToRigTranslation(data.IKData.Tip); ab = bPos - aPos; ac = cPos - aPos; float3 acNorm = ac / math.sqrt(acLengthSq); float3 ah = stream.GetLocalToRigTranslation(data.IKData.Hint) - aPos; float3 abProj = ab - acNorm * math.dot(ab, acNorm); float3 ahProj = ah - acNorm * math.dot(ah, acNorm); float maxReach = data.IKData.LimbLengths.x + data.IKData.LimbLengths.y; if (math.lengthsq(abProj) > (maxReach * maxReach * 0.001f) && math.lengthsq(ahProj) > 0f) { quaternion hintRot = mathex.fromTo(abProj, ahProj); hintRot.value.xyz *= hintWeight; stream.SetLocalToRigRotation(data.IKData.Root, math.mul(hintRot, stream.GetLocalToRigRotation(data.IKData.Root))); } } } stream.SetLocalToRigRotation(data.IKData.Tip, tRot); } data.ProfilerMarker.End(); }