ManipulationMoveLogic.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. using System;
  2. using UnityEngine;
  3. using Rokid.UXR.Utility;
  4. using Rokid.UXR.Exentesions;
  5. namespace Rokid.UXR.Interaction.ThirdParty
  6. {
  7. /// <summary>
  8. /// Use MRTK Phyisc
  9. /// Implements a move logic that will move an object based on the initial position of
  10. /// the grab point relative to the pointer and relative to the object, and subsequent
  11. /// changes to the pointer and the object's rotation
  12. ///
  13. /// Usage:
  14. /// When a manipulation starts, call Setup.
  15. /// Call Update any time to update the move logic and get a new rotation for the object.
  16. /// </summary>
  17. public class ManipulationMoveLogic
  18. {
  19. private float pointerRefDistance;
  20. private bool pointerPosIndependentOfHead = true;
  21. private Vector3 pointerLocalGrabPoint;
  22. private Vector3 objectLocalGrabPoint;
  23. private Vector3 grabToObject;
  24. private Vector3 objectLocalAttachPoint;
  25. private Vector3 attachToObject;
  26. /// <summary>
  27. /// Setup function
  28. /// </summary>
  29. public void Setup(Pose pointerCentroidPose, Vector3 grabCentroid, Pose objectPose, Vector3 objectScale)
  30. {
  31. pointerRefDistance = GetDistanceToBody(pointerCentroidPose);
  32. pointerPosIndependentOfHead = pointerRefDistance != 0;
  33. Quaternion worldToPointerRotation = Quaternion.Inverse(pointerCentroidPose.rotation);
  34. pointerLocalGrabPoint = worldToPointerRotation * (grabCentroid - pointerCentroidPose.position);
  35. attachToObject = objectPose.position - pointerCentroidPose.position;
  36. objectLocalAttachPoint = Quaternion.Inverse(objectPose.rotation) * (pointerCentroidPose.position - objectPose.position);
  37. objectLocalAttachPoint = objectLocalAttachPoint.Div(objectScale);
  38. grabToObject = objectPose.position - grabCentroid;
  39. objectLocalGrabPoint = Quaternion.Inverse(objectPose.rotation) * (grabCentroid - objectPose.position);
  40. objectLocalGrabPoint = objectLocalGrabPoint.Div(objectScale);
  41. }
  42. /// <summary>
  43. /// Update the position based on input.
  44. /// </summary>
  45. /// <returns>A Vector3 describing the desired position</returns>
  46. [Obsolete("This update function is out of date and does not properly support Near Manipulation. Use UpdateTransform instead")]
  47. public Vector3 Update(Pose pointerCentroidPose, Quaternion objectRotation, Vector3 objectScale, bool usePointerRotation)
  48. {
  49. return FarManipulationUpdate(pointerCentroidPose, objectRotation, objectScale, usePointerRotation);
  50. }
  51. /// <summary>
  52. /// Update the position based on input.
  53. /// </summary>
  54. /// <returns>A Vector3 describing the desired position</returns>
  55. public Vector3 UpdateTransform(Pose pointerCentroidPose, Transform currentTarget, bool isPointerAnchor, bool isNearManipulation)
  56. {
  57. if (isNearManipulation)
  58. {
  59. return NearManipulationUpdate(pointerCentroidPose, currentTarget);
  60. }
  61. else
  62. {
  63. return FarManipulationUpdate(pointerCentroidPose, currentTarget.rotation, currentTarget.localScale, isPointerAnchor);
  64. }
  65. }
  66. /// <summary>
  67. /// Updates the position during near manipulation
  68. /// </summary>
  69. /// <returns>A Vector3 describing the desired position during near manipulation</returns>
  70. private Vector3 NearManipulationUpdate(Pose pointerCentroidPose, Transform currentTarget)
  71. {
  72. Vector3 scaledLocalAttach = Vector3.Scale(objectLocalAttachPoint, currentTarget.localScale);
  73. Vector3 worldAttachPoint = currentTarget.rotation * scaledLocalAttach + currentTarget.position;
  74. return currentTarget.position + (pointerCentroidPose.position - worldAttachPoint);
  75. }
  76. /// <summary>
  77. /// Updates the position during far manipulation
  78. /// </summary>
  79. /// <returns>A Vector3 describing the desired position during far manipulation</returns>
  80. private Vector3 FarManipulationUpdate(Pose pointerCentroidPose, Quaternion objectRotation, Vector3 objectScale, bool isPointerAnchor)
  81. {
  82. float distanceRatio = 1.0f;
  83. if (pointerPosIndependentOfHead)
  84. {
  85. // Compute how far away the object should be based on the ratio of the current to original hand distance
  86. float currentHandDistance = GetDistanceToBody(pointerCentroidPose);
  87. distanceRatio = currentHandDistance / pointerRefDistance;
  88. }
  89. if (isPointerAnchor)
  90. {
  91. Vector3 scaledGrabToObject = Vector3.Scale(objectLocalGrabPoint, objectScale);
  92. Vector3 adjustedPointerToGrab = (pointerLocalGrabPoint * distanceRatio);
  93. adjustedPointerToGrab = pointerCentroidPose.rotation * adjustedPointerToGrab;
  94. return adjustedPointerToGrab - objectRotation * scaledGrabToObject + pointerCentroidPose.position;
  95. }
  96. else
  97. {
  98. return pointerCentroidPose.position + grabToObject + (pointerCentroidPose.rotation * pointerLocalGrabPoint) * distanceRatio;
  99. }
  100. }
  101. private float GetDistanceToBody(Pose pointerCentroidPose)
  102. {
  103. // The body is treated as a ray, parallel to the y-axis, where the start is head position.
  104. // This means that moving your hand down such that is the same distance from the body will
  105. // not cause the manipulated object to move further away from your hand. However, when you
  106. // move your hand upward, away from your head, the manipulated object will be pushed away.
  107. if (pointerCentroidPose.position.y > MainCameraCache.mainCamera.transform.position.y)
  108. {
  109. return Vector3.Distance(pointerCentroidPose.position, MainCameraCache.mainCamera.transform.position);
  110. }
  111. else
  112. {
  113. Vector2 headPosXZ = new Vector2(MainCameraCache.mainCamera.transform.position.x, MainCameraCache.mainCamera.transform.position.z);
  114. Vector2 pointerPosXZ = new Vector2(pointerCentroidPose.position.x, pointerCentroidPose.position.z);
  115. return Vector2.Distance(pointerPosXZ, headPosXZ);
  116. }
  117. }
  118. }
  119. }