/// <summary> /// Find the picker's angle of rotation from zero. /// </summary> /// <remarks> /// Once the picker is grasping the pickable object, it will stay on the "surface" of the /// pickable by maintaining a fixed displacement with a constrain point. The constrain point /// is a game object that will rotate together with this one. E.g. it can be the edge of the /// lever. When picker is moved to new position, the position of the new constrain point can /// be found in turn. Picker's angle of rotation can be calculated from the angle that needs /// to rotate from zero deg to the direction from centre of rotation to new constrain point. /// </remarks> /// <param name="picker">The picker that is grasping the object.</param> /// <returns>Picker's angle of rotation from zero.</returns> protected override float GetPickerAngleInRotationAxis(IPicker picker) { PickerDexmo pickerDexmo = picker as PickerDexmo; Transform pickerReference = pickerDexmo == null ? picker.Transform : pickerDexmo.PalmCenter; // We want the picker transform to maintain a fixed displacement in world space with the // constrain point, so when picker transform is moved to a new point, the new // constrain point can be obtained by subtracting the fixed displacement from // the picker transform. Vector3 newConstrainPoint = pickerReference.position - PickerFixedDisplacementWrtConstrainPoint; // Since the object itself is the centre of rotation and will rotate during runtime, // all the directions here is calculated in parent transform's coordinate. // transform.position is the centre of rotation. Find the direction pointing from // centre of rotation to new constrain point position. Vector3 pickerRelativeDirectionInParentCoordinate = Miscellaneous.InverseTransformDirectionInParentCoordinate(transform, newConstrainPoint - transform.position); // Find the angle of rotation from zero reference to the direction connecting the // centre of rotation to new constrain point position. float angle = RotationUtils.AngleInPlane(LocalRotationAxisInParentCoordinate, ZeroReferenceDirectionInParentCoordinate, pickerRelativeDirectionInParentCoordinate); return(angle); }
/// <summary> /// It contrains the picker by overwriting its position and rotation. In this function /// it constrains picker by keeping picker a fixed postion and rotation offset with /// the position and the rotation of the constrain point reference transform. /// </summary> /// <remarks> /// The position and rotation offset between the picker and the constrain point reference /// is determined when this object is just picked up in <see cref="OnPickedInit"/>. /// Then when this pickable moves towards the picker with certain constraint, the /// constraint reference will move accordingly. This function is called to bring back /// picker so it always have the some offset with the constrain reference. /// This is a virtual function and the mechanism to constrain picker may be overridden by /// derived classes. /// </remarks> /// <param name="picker">The picker to constrain</param> protected virtual void ConstrainPicker(IPicker picker) { PickerDexmo pickerDexmo = picker as PickerDexmo; Transform pickerReference = null; if (pickerDexmo == null) { pickerReference = picker.Transform; } else { switch (PickerDexmoConstrainPart) { case PickerDexmoConstrainPartType.Wrist: pickerReference = pickerDexmo.transform; break; case PickerDexmoConstrainPartType.PalmCenter: pickerReference = pickerDexmo.PalmCenter; break; } } if (_constrainPositionReference != null) { // Constrain picker's position to ensure it has fixed displacement // with constrain reference. pickerReference.position = _constrainPositionReference.position + PickerFixedDisplacementWrtConstrainPoint; } if (_constrainRotationReference != null) { // Constrain picker's position to ensure it has fixed relative rotation // with constrain reference. pickerReference.rotation = _constrainRotationReference.rotation * PickerFixedAngleDisplacementWrtConstrainPoint; } else { //pickerReference.rotation = InitialPickerRotation; } if (pickerDexmo != null) { Vector3 pickerReferenceTargetPosition = pickerReference.position; Quaternion pickerReferenceTargetRotation = pickerReference.rotation; // In Unity, moving child transform will not change its parent, but // moving parent's transform will change all of its children, so the // constrained position and rotation of the hand root tranform (the // most parent transform) needs to be calculated and modified to constrain // the entire hand model. Target position and rotation of hand root // transform can be calculated from the target position and rotation of // its children, e.g. palm center. Miscellaneous.MoveParentTransformGivenChildTransform( pickerDexmo.HandRootTransform, pickerReference, pickerReferenceTargetPosition, pickerReferenceTargetRotation, HandRootPositionRelativeToPicker, HandRootRotationRelativeToPicker); } }
/// <summary> /// It will be called when this object is just picked up. It will save some relative /// rotation variables to be used later. /// </summary> /// <param name="picker">The picker that picks it up.</param> public override void OnPickedInit(IPicker picker) { PickerDexmo pickerDexmo = picker as PickerDexmo; Transform pickerReference = pickerDexmo == null ? picker.Transform : pickerDexmo.PalmCenter; _pickerRelativeRotationWrtKnob = Quaternion.Inverse(transform.rotation) * pickerReference.rotation; base.OnPickedInit(picker); }
/// <summary> /// Find the target angle of rotation from zero based on current picker's rotation. /// </summary> /// <remarks> /// The picker will maintain a fixed relative rotation with knob since the start of /// grasping, so given the current rotation of picker, we can compute the new target /// rotation of knob. /// </remarks> /// <param name="picker">The picker that is grasping it.</param> /// <returns>Target angle of rotation of knob based on the picker's rotation.</returns> protected override float GetPickerAngleInRotationAxis(IPicker picker) { PickerDexmo pickerDexmo = picker as PickerDexmo; Transform pickerReference = pickerDexmo == null ? picker.Transform : pickerDexmo.PalmCenter; // Calculate the target rotation of knob based on current rotation of the picker Quaternion newKnobTargetRotation = pickerReference.rotation * Quaternion.Inverse(_pickerRelativeRotationWrtKnob); // Convert the current angle reference from world coordinate to parent transform's // coordinate. Angle reference is the direction that indicates the current angle // of rotation from zero. Vector3 newAngleReferenceDirectionInWorld = newKnobTargetRotation * ZeroReferenceDirection; Vector3 pickerRelativeDirectionInParentCoordinate = Miscellaneous.InverseTransformDirectionInParentCoordinate(transform, newAngleReferenceDirectionInWorld); // Find the target angle of rotation from zero in the plane normal to rotation axis float angle = RotationUtils.AngleInPlane(LocalRotationAxisInParentCoordinate, ZeroReferenceDirectionInParentCoordinate, pickerRelativeDirectionInParentCoordinate); return(angle); }
/// <summary> /// Constrain picker such that its centre position stays at the centre of rotation and /// its rotation changes with the knob. /// </summary> /// <param name="picker">The picker that is grasping it.</param> protected override void ConstrainPicker(IPicker picker) { PickerDexmo pickerDexmo = picker as PickerDexmo; if (pickerDexmo == null) { //Transform pickerReference = picker.Transform; //if (ConstrainPositionReference != null) //{ // pickerReference.position = ConstrainPositionReference.position + // PickerFixedDisplacementWrtConstrainPoint; //} //if (ConstrainRotationReference != null) //{ // pickerReference.rotation = ConstrainRotationReference.rotation * // PickerFixedAngleDisplacementWrtConstrainPoint; //} // Don't constrain picker if it is not dexmo. } else { // Only constrain picker if it is dexmo Transform pickerReference = pickerDexmo.PalmCenter; Vector3 pickerReferenceTargetPostion = ConstrainPositionReference.position; Quaternion pickerReferenceTargetRotation = transform.rotation * _pickerRelativeRotationWrtKnob; // In Unity, moving child transform will not change its parent, but // moving parent's transform will change all of its children, so the // constrained position and rotation of the hand root tranform (the // most parent transform) needs to be calculated and modified to constrain // the entire hand model. Target position and rotation of hand root // transform can be calculated from the target position and rotation of // its children, e.g. palm center. Miscellaneous.MoveParentTransformGivenChildTransform( pickerDexmo.HandRootTransform, pickerReference, pickerReferenceTargetPostion, pickerReferenceTargetRotation, HandRootPositionRelativeToPicker, HandRootRotationRelativeToPicker); } }
/// <summary> /// It is called when this object is just picked up. It records some initial /// position and rotation offset with the picker, which will be used later. /// </summary> /// <remarks> /// Note that the implementation of this function is a little different from /// that of <see cref="Pickable"/>. Here it does not need to change the rigidbody properties /// to kinematic in order to follow the movement of the picker. Its movement /// is entirely defined in function <see cref="MoveTowardsTargetWithConstraint"/>. /// </remarks> /// <param name="picker">The picker that picks it up.</param> public override void OnPickedInit(IPicker picker) { Rigidbody activeRb = GetActiveRb(); // Need to update the pickable mapping whenever a new object is picked up. PickableMapping.UpdatePickableMapping(activeRb, true, picker); PickerDexmo pickerDexmo = picker as PickerDexmo; Transform pickerReference = picker.Transform; if (pickerDexmo != null) { Transform handRootTransform = pickerDexmo.HandRootTransform; if (_pickerDexmoConstrainPart == PickerDexmoConstrainPartType.PalmCenter) { pickerReference = pickerDexmo.PalmCenter; } HandRootPositionRelativeToPicker = pickerReference.InverseTransformPoint(handRootTransform.position); HandRootRotationRelativeToPicker = Quaternion.Inverse(pickerReference.rotation) * handRootTransform.rotation; } if (_constrainPositionReference != null) { PickerFixedDisplacementWrtConstrainPoint = pickerReference.position - _constrainPositionReference.position; } if (_constrainRotationReference != null) { PickerFixedAngleDisplacementWrtConstrainPoint = Quaternion.Inverse(_constrainRotationReference.rotation) * pickerReference.rotation; } InitialPickerRotation = pickerReference.rotation; // Send the PickedInit event. OnPickedInitEvent(picker); }