/// <summary> /// Performs a blending based on the from posture and the to posture. In particular a blending weight and an additional blending mask is utilized. If the blending mask is set to null, all bones with position + rotation will be used for blending. /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="weight"></param> /// <param name="blendingMask"></param> /// <returns></returns> public static MAvatarPostureValues PerformBlend(IntermediateSkeleton skeleton, MAvatarPostureValues from, MAvatarPostureValues to, float weight, Dictionary <MJointType, BlendProperty> blendingMask = null) { //MAvatarPosture result = from.Clone(); MAvatarPosture zero = skeleton.GetAvatarDescription(from.AvatarID).ZeroPosture; skeleton.SetChannelData(from); List <MQuaternion> fromRot = skeleton.GetLocalJointRotations(from.AvatarID); skeleton.SetChannelData(to); List <MQuaternion> toRot = skeleton.GetLocalJointRotations(to.AvatarID); for (int i = 0; i < zero.Joints.Count; i++) { //By default belnd both position and rotation BlendProperty blendProperty = new BlendProperty(1.0f, 1.0f); MJointType joint = zero.Joints[i].Type; if (blendingMask != null && blendingMask.ContainsKey(joint)) { //Get the bone weight blendingMask.TryGetValue(joint, out blendProperty); } //Perform a linear interpolation of the position // Does not correspond to intermediate skeleton representation. // result.Joints[i].Position = result.Joints[i].Position.Lerp(to.Joints[i].Position, weight * blendProperty.PositionWeight); //Perform a slerp of the rotation skeleton.SetLocalJointRotation(to.AvatarID, joint, fromRot[i].Slerp(toRot[i], weight * blendProperty.RotationWeight)); } return(skeleton.RecomputeCurrentPostureValues(to.AvatarID)); }
/// <summary> /// Performs a blending based on the from posture and the to posture. /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="weight"></param> /// <param name="rootTransform">Specifies whether the root transform is blended as well</param> /// <returns></returns> public static MAvatarPostureValues PerformBlend(IntermediateSkeleton skeleton, MAvatarPostureValues from, MAvatarPostureValues to, float weight, bool rootTransform = true) { MAvatarPosture zero = skeleton.GetAvatarDescription(from.AvatarID).ZeroPosture; skeleton.SetChannelData(from); List <MQuaternion> fromRot = skeleton.GetLocalJointRotations(from.AvatarID); skeleton.SetChannelData(to); List <MQuaternion> toRot = skeleton.GetLocalJointRotations(to.AvatarID); for (int i = 0; i < zero.Joints.Count; i++) { //By default belnd both position and rotation MJointType joint = zero.Joints[i].Type; //Perform a linear interpolation of the position // Does not correspond to intermediate skeleton representation. // result.Joints[i].Position = result.Joints[i].Position.Lerp(to.Joints[i].Position, weight * blendProperty.PositionWeight); //Perform a slerp of the rotation skeleton.SetLocalJointRotation(to.AvatarID, joint, fromRot[i].Slerp(toRot[i], weight)); } return(skeleton.RecomputeCurrentPostureValues(to.AvatarID)); /* * MAvatarPosture result = from.Clone(); * * for (int i = 0; i < result.Joints.Count; i++) * { * //Skip if root transform should be ignored * if (i == 0 && rootTransform) * result.Joints[i].Position = result.Joints[i].Position.Lerp(to.Joints[i].Position, weight); * * //Perform a slerp of the rotation * result.Joints[i].Rotation = result.Joints[i].Rotation.Slerp(to.Joints[i].Rotation, weight); * } * * return result; */ }
public override MSimulationResult DoStep(double time, MSimulationState simulationState) { //Create a new result MSimulationResult result = new MSimulationResult() { Events = simulationState.Events ?? new List <MSimulationEvent>(), DrawingCalls = new List <MDrawingCall>(), SceneManipulations = simulationState.SceneManipulations ?? new List <MSceneManipulation>(), Posture = simulationState.Current, Constraints = simulationState.Constraints ?? new List <MConstraint>() }; //Cast to intermediate skeleton to get all functions IntermediateSkeleton iS = this.SkeletonAccess as IntermediateSkeleton; //Assign the approved posture of the last frame (proper finger rotations) this.SkeletonAccess.SetChannelData(simulationState.Initial); //First estimate the finger rotations //------------------------------------------------------------------------------------------------------------------ //Handle each active hand for (int i = this.ActiveHands.Count - 1; i >= 0; i--) { //Get the current hand HandContainer hand = this.ActiveHands[i]; if (hand.Release) { //Use all finger joint if in release mode foreach (MJointType jointType in fingerJoints) { //Get the current rotation of the finger if (!hand.CurrentFingerRotations.ContainsKey(jointType)) { hand.CurrentFingerRotations.Add(jointType, iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, jointType)); } else { hand.CurrentFingerRotations[jointType] = iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, jointType); } } } else { //Handle all joint constraints -> Use only the fingers that are constrained foreach (MJointConstraint joint in hand.FinalPosture.JointConstraints) { //Skip if the joint is no finger joint if (!this.IsFingerJoint(joint.JointType)) { continue; } //Get the current rotation of the finger if (!hand.CurrentFingerRotations.ContainsKey(joint.JointType)) { hand.CurrentFingerRotations.Add(joint.JointType, iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, joint.JointType)); } else { hand.CurrentFingerRotations[joint.JointType] = iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, joint.JointType); } } } } //Perform the blending //------------------------------------------------------------------------------------------------------------------ //Assign the approved posture of the last frame (proper finger rotations) this.SkeletonAccess.SetChannelData(simulationState.Current); //Handle each active hand for (int i = this.ActiveHands.Count - 1; i >= 0; i--) { //Get the current hand HandContainer hand = this.ActiveHands[i]; //Flag which indicates whether the fingers are positioned bool positioned = true; if (hand.Release) { //If in release mode again use all joints being finger joints foreach (MJointType jointType in fingerJoints) { //Get the current rotation of the finger MQuaternion currentRotation = hand.CurrentFingerRotations[jointType]; //The current rotation is the result of the last frame MQuaternion desiredRotation = iS.GetLocalJointRotation(this.AvatarDescription.AvatarID, jointType); //The weight used for blending double weight = 0; //The angle between the current rotation and the desired one double angle = MQuaternionExtensions.Angle(currentRotation, desiredRotation); //Compute the weight based on the elapsed time if the duration is set if (hand.HasDuration) { weight = hand.Elapsed / hand.Duration; } //By default use the angular velocity else { //The max allowed angle in this frame double maxAngle = time * hand.AngularVelocity; weight = Math.Min(1, maxAngle / angle); } //Compute the new rotation MQuaternion newRotation = MQuaternionExtensions.Slerp(currentRotation, desiredRotation, (float)weight); //Set the local joint rotation of the intermediate skeleton iS.SetLocalJointRotation(this.AvatarDescription.AvatarID, jointType, newRotation); //Goal criteria if (angle > 0.1f) { positioned = false; } } } else { //Handle all joint constraints foreach (MJointConstraint joint in hand.FinalPosture.JointConstraints) { //Skip if the joint is no finger joint if (!this.IsFingerJoint(joint.JointType)) { continue; } //Get the current rotation of the finger MQuaternion currentRotation = hand.CurrentFingerRotations[joint.JointType]; //Get the desired rotation MQuaternion desiredRotation = joint.GeometryConstraint.ParentToConstraint.Rotation; //The weight used for blending double weight = 0; //The angle between the current rotation and the desired one double angle = MQuaternionExtensions.Angle(currentRotation, desiredRotation); //Compute the weight based on the elapsed time if the duration is set if (hand.HasDuration) { weight = hand.Elapsed / hand.Duration; } //By default use the angular velocity else { //The max allowed angle in this frame double maxAngle = time * hand.AngularVelocity; weight = Math.Min(1, maxAngle / angle); } //Compute the new rotation MQuaternion newRotation = MQuaternionExtensions.Slerp(currentRotation, desiredRotation, (float)weight); //Set the local joint rotation of the intermediate skeleton iS.SetLocalJointRotation(this.AvatarDescription.AvatarID, joint.JointType, newRotation); //Goal criteria if (angle > 0.1f) { positioned = false; } } } //Provide event if positioned successfully if (positioned && !hand.Positioned) { hand.Positioned = true; result.Events.Add(new MSimulationEvent() { Name = "MoveFingersMMU", Type = "FingersPositioned", Reference = hand.Instruction.ID }); } //Increment the time hand.Elapsed += (float)time; } //Recompute the posture given the performed changes result.Posture = iS.RecomputeCurrentPostureValues(this.AvatarDescription.AvatarID); //Return the simulation result for the given frame return(result); }