TransitionArmModel.cs 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. // Copyright 2017 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Modified by Unity from original:
  15. // https://github.com/googlevr/daydream-elements/blob/master/Assets/DaydreamElements/Elements/ArmModels/Scripts/ArmModels/TransitionArmModel.cs
  16. using System;
  17. using System.Collections;
  18. using System.Collections.Generic;
  19. using System.Runtime.CompilerServices;
  20. using UnityEngine;
  21. using UnityEngine.Events;
  22. #if ENABLE_VR || ENABLE_AR
  23. using UnityEngine.Experimental.XR.Interaction;
  24. using UnityEngine.SpatialTracking;
  25. [assembly: InternalsVisibleTo("UnityEditor.XR.LegacyInputHelpers")]
  26. namespace UnityEngine.XR.LegacyInputHelpers
  27. {
  28. [Serializable]
  29. public class ArmModelTransition
  30. {
  31. [SerializeField]
  32. String m_KeyName;
  33. /// <summary>
  34. /// the string name that will be used to trigger a transition
  35. /// </summary>
  36. public string transitionKeyName
  37. {
  38. get { return m_KeyName; }
  39. set { m_KeyName = value; }
  40. }
  41. [SerializeField]
  42. ArmModel m_ArmModel;
  43. /// <summary>
  44. /// the arm model that will be transitioned to on receiving this event.
  45. /// </summary>
  46. public ArmModel armModel
  47. {
  48. get { return m_ArmModel; }
  49. set { m_ArmModel = value; }
  50. }
  51. }
  52. public class TransitionArmModel : ArmModel
  53. {
  54. [SerializeField]
  55. ArmModel m_CurrentArmModelComponent = null;
  56. /// <summary>
  57. /// This field contains the current active arm model that will be used as the input to the tracked pose driver which is
  58. /// using the transitional arm model.
  59. /// </summary>
  60. public ArmModel currentArmModelComponent
  61. {
  62. get { return m_CurrentArmModelComponent; }
  63. set { m_CurrentArmModelComponent = value; }
  64. }
  65. [SerializeField]
  66. public List<ArmModelTransition> m_ArmModelTransitions = new List<ArmModelTransition>();
  67. /// Max number of active transitions that can be going on at one time.
  68. /// Transitions are only completed when the controller rotates, so if TransitionToArmModel
  69. /// is called several times without the controller moving, the number of active transitions can
  70. /// add up.
  71. private const int MAX_ACTIVE_TRANSITIONS = 10;
  72. /// When transitioning to a new arm model, drop any old transitions that have barely begun.
  73. private const float DROP_TRANSITION_THRESHOLD = 0.035f;
  74. /// Threshold for clamping transitions that have been completed.
  75. private const float LERP_CLAMP_THRESHOLD = 0.95f;
  76. /// Minimum amount of angular velocity on the controller before transitioning occurs.
  77. private const float MIN_ANGULAR_VELOCITY = 0.2f;
  78. /// Unit less weight for how much the angular velocity impacts the transition.
  79. private const float ANGULAR_VELOCITY_DIVISOR = 45.0f;
  80. internal struct ArmModelBlendData
  81. {
  82. public ArmModel armModel;
  83. public float currentBlendAmount;
  84. }
  85. internal List<ArmModelBlendData> armModelBlendData = new List<ArmModelBlendData>(MAX_ACTIVE_TRANSITIONS);
  86. ArmModelBlendData currentBlendingArmModel;
  87. public bool Queue(string key)
  88. {
  89. // attempt to find the arm model to blend to using the supplied key.
  90. foreach(var am in m_ArmModelTransitions)
  91. {
  92. if(am.transitionKeyName == key)
  93. {
  94. Queue(am.armModel);
  95. return true;
  96. }
  97. }
  98. return false;
  99. }
  100. public void Queue(ArmModel newArmModel)
  101. {
  102. if(newArmModel == null)
  103. {
  104. return;
  105. }
  106. if(m_CurrentArmModelComponent == null)
  107. {
  108. m_CurrentArmModelComponent = newArmModel;
  109. }
  110. RemoveJustStartingTransitions();
  111. if (armModelBlendData.Count == MAX_ACTIVE_TRANSITIONS)
  112. {
  113. RemoveOldestTransition();
  114. }
  115. var ambd = new ArmModelBlendData();
  116. ambd.armModel = newArmModel;
  117. ambd.currentBlendAmount = 0.0f;
  118. armModelBlendData.Add(ambd);
  119. }
  120. void RemoveJustStartingTransitions()
  121. {
  122. for( int i = 0; i < armModelBlendData.Count; ++i)
  123. {
  124. ArmModelBlendData ambd = armModelBlendData[i];
  125. if (ambd.currentBlendAmount < DROP_TRANSITION_THRESHOLD)
  126. {
  127. armModelBlendData.RemoveAt(i);
  128. }
  129. }
  130. }
  131. void RemoveOldestTransition()
  132. {
  133. armModelBlendData.RemoveAt(0);
  134. }
  135. public override PoseDataFlags GetPoseFromProvider(out Pose output)
  136. {
  137. if (UpdateBlends())
  138. {
  139. output = finalPose;
  140. return PoseDataFlags.Position | PoseDataFlags.Rotation;
  141. }
  142. output = Pose.identity;
  143. return PoseDataFlags.NoData;
  144. }
  145. bool UpdateBlends()
  146. {
  147. if (currentArmModelComponent == null)
  148. {
  149. return false;
  150. }
  151. if (m_CurrentArmModelComponent.OnControllerInputUpdated())
  152. {
  153. m_NeckPosition = m_CurrentArmModelComponent.neckPosition;
  154. m_ElbowPosition = m_CurrentArmModelComponent.elbowPosition;
  155. m_WristPosition = m_CurrentArmModelComponent.wristPosition;
  156. m_ControllerPosition = m_CurrentArmModelComponent.controllerPosition;
  157. m_ElbowRotation = m_CurrentArmModelComponent.elbowRotation;
  158. m_WristRotation = m_CurrentArmModelComponent.wristRotation;
  159. m_ControllerRotation = m_CurrentArmModelComponent.controllerRotation;
  160. #if UNITY_EDITOR
  161. m_TorsoDirection = m_CurrentArmModelComponent.torsoDirection;
  162. m_TorsoRotation = m_CurrentArmModelComponent.torsoRotation;
  163. #endif
  164. Vector3 angVel;
  165. if (TryGetAngularVelocity(poseSource, out angVel) && armModelBlendData.Count > 0)
  166. {
  167. float angularVelocity = angVel.magnitude;
  168. float lerpValue = Mathf.Clamp(((angularVelocity) - MIN_ANGULAR_VELOCITY) / ANGULAR_VELOCITY_DIVISOR, 0.0f, 0.1f);
  169. for (int i = 0; i < armModelBlendData.Count; ++i)
  170. {
  171. ArmModelBlendData ambd = armModelBlendData[i];
  172. ambd.currentBlendAmount = Mathf.Lerp(ambd.currentBlendAmount, 1.0f, lerpValue);
  173. if (ambd.currentBlendAmount > LERP_CLAMP_THRESHOLD)
  174. {
  175. ambd.currentBlendAmount = 1.0f;
  176. }
  177. else
  178. {
  179. ambd.armModel.OnControllerInputUpdated();
  180. m_NeckPosition = Vector3.Slerp(neckPosition, ambd.armModel.neckPosition, ambd.currentBlendAmount);
  181. m_ElbowPosition = Vector3.Slerp(elbowPosition, ambd.armModel.elbowPosition, ambd.currentBlendAmount);
  182. m_WristPosition = Vector3.Slerp(wristPosition, ambd.armModel.wristPosition, ambd.currentBlendAmount);
  183. m_ControllerPosition = Vector3.Slerp(controllerPosition, ambd.armModel.controllerPosition, ambd.currentBlendAmount);
  184. m_ElbowRotation = Quaternion.Slerp(elbowRotation, ambd.armModel.elbowRotation, ambd.currentBlendAmount);
  185. m_WristRotation = Quaternion.Slerp(wristRotation, ambd.armModel.wristRotation, ambd.currentBlendAmount);
  186. m_ControllerRotation = Quaternion.Slerp(controllerRotation, ambd.armModel.controllerRotation, ambd.currentBlendAmount);
  187. }
  188. // write back.
  189. armModelBlendData[i] = ambd;
  190. if (ambd.currentBlendAmount >= 1.0f)
  191. {
  192. m_CurrentArmModelComponent = ambd.armModel;
  193. armModelBlendData.RemoveRange(0, i + 1);
  194. }
  195. }
  196. }
  197. else if (armModelBlendData.Count > 0)
  198. {
  199. Debug.LogErrorFormat(this.gameObject, "Unable to get angular acceleration for node");
  200. return false;
  201. }
  202. finalPose = new Pose(controllerPosition, controllerRotation);
  203. return true;
  204. }
  205. else
  206. {
  207. return false;
  208. }
  209. }
  210. #if UNITY_EDITOR
  211. internal List<ArmModelBlendData> GetActiveBlends()
  212. {
  213. return armModelBlendData;
  214. }
  215. #endif
  216. }
  217. }
  218. #endif