public void Solve(ref TransformBuffer localPose, float3 target) { ReadPose(ref localPose); quaternion tipGlobalRotation = globalTransforms[tipIndex].q; // 1. Force mid joint rotation to half stretch pose (override animation), forcing rotation will ensure the fold axis will be the same across all animation poses, // ensuring IK stability over time. This will also make sure the joint isn't broken by being fold along the wrong axis and in the wrong direction SetLocalRotation(midIndex, halfStretchedMidRotation); float3 midToRoot = RootPos - MidPos; float3 midToTip = TipPos - MidPos; // 2. Get current axis and angle rotation between 2 limbs quaternion upperToLowerRot = Missing.forRotation(midToRoot, midToTip); float upperToLowerAngle; float3 upperToLowerAxis = Missing.axisAngle(upperToLowerRot, out upperToLowerAngle); // 3. Extend or compress arm in order to reach distance to target float desiredAngle = GetTriangleAngle(midToRoot, midToTip, target - RootPos); quaternion unfoldRotation = quaternion.AxisAngle(upperToLowerAxis, desiredAngle - upperToLowerAngle); SetGlobalRotation(midIndex, math.mul(unfoldRotation, globalTransforms[midIndex].q)); // 4. Align tip of the arm with target quaternion alignRotation = Missing.forRotation(TipPos - RootPos, target - RootPos); SetGlobalRotation(rootIndex, math.mul(alignRotation, globalTransforms[rootIndex].q)); // 5. Preserve tip global rotation SetGlobalRotation(tipIndex, tipGlobalRotation); WritePose(ref localPose); }
void WritePose(ref TransformBuffer localPose) { for (int i = rootIndex; i < jointIndices.Length; ++i) { localPose[jointIndices[i]] = localTransforms[i]; } }
internal AffineTransform ComputeGlobalJointTransform(ref TransformBuffer localPose, int jointIndex) { AffineTransform globalTransform = localPose[jointIndex]; while (joints[jointIndex].parentIndex >= 0) { jointIndex = joints[jointIndex].parentIndex; globalTransform = localPose[jointIndex] * globalTransform; } return(globalTransform); }
void ReadPose(ref TransformBuffer localPose) { localTransforms[0] = localPose[jointIndices[0]]; globalTransforms[0] = rig.ComputeGlobalJointTransform(ref localPose, jointIndices[0]); for (int i = 1; i < jointIndices.Length; ++i) { AffineTransform localJoint = localPose[jointIndices[i]]; localTransforms[i] = localJoint; globalTransforms[i] = globalTransforms[i - 1] * localJoint; } }
public override void RetargetPose(ref TransformBuffer sourceTransformBuffer, ref TransformBuffer targetTransformBuffer) { #if USE_HUMAN_POSE_HANDLER_RETARGETING int affineTransformSize = UnsafeUtility.SizeOf <AffineTransform>(); AffineTransform leftFootSource = AffineTransform.identity; AffineTransform rightFootSource = AffineTransform.identity; AffineTransform leftHandSource = AffineTransform.identity; AffineTransform rightHandSource = AffineTransform.identity; // 1. Compute IK target positions from source if (enableIK) { leftFootSource = sourceRig.ComputeGlobalJointTransform(ref sourceTransformBuffer, feetIK.leftLimbSourceJointIndex); rightFootSource = sourceRig.ComputeGlobalJointTransform(ref sourceTransformBuffer, feetIK.rightLimbSourceJointIndex); leftHandSource = sourceRig.ComputeGlobalJointTransform(ref sourceTransformBuffer, handsIK.leftLimbSourceJointIndex); rightHandSource = sourceRig.ComputeGlobalJointTransform(ref sourceTransformBuffer, handsIK.rightLimbSourceJointIndex); } // 2. Convert source transform buffer (joint transforms) to human pose (universal muscles values) AffineTransform rootTransform = sourceTransformBuffer[0]; sourceTransformBuffer[0] = AffineTransform.identity; for (int i = 0; i < sourceTransformBuffer.Length; ++i) { sourceAvatarPose[i] = sourceTransformBuffer[i]; } sourceHumanPoseHandler.SetInternalAvatarPose(sourceAvatarPose.Reinterpret <float>(affineTransformSize)); sourceHumanPoseHandler.GetInternalHumanPose(ref humanPose); // 3. Convert human poses (muscles) to target transform buffer, retargeting targetHumanPoseHandler.SetInternalHumanPose(ref humanPose); targetHumanPoseHandler.GetInternalAvatarPose(targetAvatarPose.Reinterpret <float>(affineTransformSize)); for (int i = 0; i < targetTransformBuffer.Length; ++i) { targetTransformBuffer[i] = targetAvatarPose[i]; } // 4. Scale root motion and slightly lower pelvis targetTransformBuffer[0] = rootTransform * sourceToTargetScale; targetTransformBuffer[targetRig.BodyJointIndex] = new AffineTransform(targetTransformBuffer[targetRig.BodyJointIndex].t - new float3(0.0f, pelvisOffset, 0.0f), targetTransformBuffer[targetRig.BodyJointIndex].q); // 5. Solve feet & hands IK if (enableIK) { feetIK.Solve(ref targetTransformBuffer, leftFootSource.t * sourceToTargetScale, rightFootSource.t * sourceToTargetScale); handsIK.Solve(ref targetTransformBuffer, leftHandSource.t * sourceToTargetScale, rightHandSource.t * sourceToTargetScale); } #endif }
/// <summary> /// Function to perform clean up on the shader state. /// </summary> internal void CleanUp() { ConstantBuffers[0] = null; if (DefaultVertexShader != null) { DefaultVertexShader.Dispose(); } DefaultVertexShader = null; if (TransformBuffer == null) { return; } TransformBuffer.Dispose(); TransformBuffer = null; }
public void Solve(ref TransformBuffer targetTransformBuffer, float3 leftTargetPosition, float3 rightTargetPosition) { leftLimbChainIK.Solve(ref targetTransformBuffer, leftTargetPosition); rightLimbChainIK.Solve(ref targetTransformBuffer, rightTargetPosition); }