ControllerButtonHints.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Displays text and button hints on the controllers
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using UnityEngine.UI;
  10. using System.Text;
  11. namespace Valve.VR.InteractionSystem
  12. {
  13. //-------------------------------------------------------------------------
  14. public class ControllerButtonHints : MonoBehaviour
  15. {
  16. public Material controllerMaterial;
  17. public Material urpControllerMaterial;
  18. public Material usingMaterial
  19. {
  20. get
  21. {
  22. #if UNITY_URP
  23. return urpControllerMaterial;
  24. #else
  25. return controllerMaterial;
  26. #endif
  27. }
  28. }
  29. public Color flashColor = new Color( 1.0f, 0.557f, 0.0f );
  30. public GameObject textHintPrefab;
  31. public SteamVR_Action_Vibration hapticFlash = SteamVR_Input.GetAction<SteamVR_Action_Vibration>("Haptic");
  32. public bool autoSetWithControllerRangeOfMotion = true;
  33. [Header( "Debug" )]
  34. public bool debugHints = false;
  35. private SteamVR_RenderModel renderModel;
  36. private Player player;
  37. private List<MeshRenderer> renderers = new List<MeshRenderer>();
  38. private List<MeshRenderer> flashingRenderers = new List<MeshRenderer>();
  39. private float startTime;
  40. private float tickCount;
  41. private enum OffsetType
  42. {
  43. Up,
  44. Right,
  45. Forward,
  46. Back
  47. }
  48. //Info for each of the buttons
  49. private class ActionHintInfo
  50. {
  51. public string componentName;
  52. public List<MeshRenderer> renderers;
  53. public Transform localTransform;
  54. //Text hint
  55. public GameObject textHintObject;
  56. public Transform textStartAnchor;
  57. public Transform textEndAnchor;
  58. public Vector3 textEndOffsetDir;
  59. public Transform canvasOffset;
  60. public Text text;
  61. public TextMesh textMesh;
  62. public Canvas textCanvas;
  63. public LineRenderer line;
  64. public float distanceFromCenter;
  65. public bool textHintActive = false;
  66. }
  67. private Dictionary<ISteamVR_Action_In_Source, ActionHintInfo> actionHintInfos;
  68. private Transform textHintParent;
  69. private int colorID;
  70. public bool initialized { get; private set; }
  71. private Vector3 centerPosition = Vector3.zero;
  72. SteamVR_Events.Action renderModelLoadedAction;
  73. protected SteamVR_Input_Sources inputSource;
  74. //-------------------------------------------------
  75. void Awake()
  76. {
  77. renderModelLoadedAction = SteamVR_Events.RenderModelLoadedAction( OnRenderModelLoaded );
  78. #if UNITY_URP
  79. colorID = Shader.PropertyToID( "_BaseColor" );
  80. #else
  81. colorID = Shader.PropertyToID( "_Color" );
  82. #endif
  83. }
  84. //-------------------------------------------------
  85. void Start()
  86. {
  87. player = Player.instance;
  88. }
  89. //-------------------------------------------------
  90. private void HintDebugLog( string msg )
  91. {
  92. if ( debugHints )
  93. {
  94. Debug.Log("<b>[SteamVR Interaction]</b> Hints: " + msg );
  95. }
  96. }
  97. //-------------------------------------------------
  98. void OnEnable()
  99. {
  100. renderModelLoadedAction.enabled = true;
  101. }
  102. //-------------------------------------------------
  103. void OnDisable()
  104. {
  105. renderModelLoadedAction.enabled = false;
  106. Clear();
  107. }
  108. //-------------------------------------------------
  109. private void OnParentHandInputFocusLost()
  110. {
  111. //Hide all the hints when the controller is no longer the primary attached object
  112. HideAllButtonHints();
  113. HideAllText();
  114. }
  115. public virtual void SetInputSource(SteamVR_Input_Sources newInputSource)
  116. {
  117. inputSource = newInputSource;
  118. if (renderModel != null)
  119. renderModel.SetInputSource(newInputSource);
  120. }
  121. //-------------------------------------------------
  122. // Gets called when the hand has been initialized and a render model has been set
  123. //-------------------------------------------------
  124. private void OnHandInitialized(int deviceIndex)
  125. {
  126. //Create a new render model for the controller hints
  127. renderModel = new GameObject( "SteamVR_RenderModel" ).AddComponent<SteamVR_RenderModel>();
  128. renderModel.transform.parent = transform;
  129. renderModel.transform.localPosition = Vector3.zero;
  130. renderModel.transform.localRotation = Quaternion.identity;
  131. renderModel.transform.localScale = Vector3.one;
  132. renderModel.SetInputSource(inputSource);
  133. renderModel.SetDeviceIndex(deviceIndex);
  134. if ( !initialized )
  135. {
  136. //The controller hint render model needs to be active to get accurate transforms for all the individual components
  137. renderModel.gameObject.SetActive( true );
  138. }
  139. }
  140. private Dictionary<string, Transform> componentTransformMap = new Dictionary<string, Transform>();
  141. //-------------------------------------------------
  142. void OnRenderModelLoaded(SteamVR_RenderModel renderModel, bool succeess)
  143. {
  144. //Only initialize when the render model for the controller hints has been loaded
  145. if (renderModel == this.renderModel)
  146. {
  147. //Debug.Log("<b>[SteamVR Interaction]</b> OnRenderModelLoaded: " + this.renderModel.renderModelName);
  148. if (initialized)
  149. {
  150. Destroy(textHintParent.gameObject);
  151. componentTransformMap.Clear();
  152. flashingRenderers.Clear();
  153. }
  154. renderModel.SetMeshRendererState(false);
  155. StartCoroutine(DoInitialize(renderModel));
  156. }
  157. }
  158. private IEnumerator DoInitialize(SteamVR_RenderModel renderModel)
  159. {
  160. while (renderModel.initializedAttachPoints == false)
  161. yield return null;
  162. textHintParent = new GameObject("Text Hints").transform;
  163. textHintParent.SetParent(this.transform);
  164. textHintParent.localPosition = Vector3.zero;
  165. textHintParent.localRotation = Quaternion.identity;
  166. textHintParent.localScale = Vector3.one;
  167. //Get the button mask for each component of the render model
  168. var renderModels = OpenVR.RenderModels;
  169. if (renderModels != null)
  170. {
  171. string renderModelDebug = "";
  172. if (debugHints)
  173. renderModelDebug = "Components for render model " + renderModel.index;
  174. for (int childIndex = 0; childIndex < renderModel.transform.childCount; childIndex++)
  175. {
  176. Transform child = renderModel.transform.GetChild(childIndex);
  177. if (componentTransformMap.ContainsKey(child.name))
  178. {
  179. if (debugHints)
  180. renderModelDebug += "\n\t! Child component already exists with name: " + child.name;
  181. }
  182. else
  183. componentTransformMap.Add(child.name, child);
  184. if (debugHints)
  185. renderModelDebug += "\n\t" + child.name + ".";
  186. }
  187. //Uncomment to show the button mask for each component of the render model
  188. HintDebugLog(renderModelDebug);
  189. }
  190. actionHintInfos = new Dictionary<ISteamVR_Action_In_Source, ActionHintInfo>();
  191. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsNonPoseNonSkeletonIn.Length; actionIndex++)
  192. {
  193. ISteamVR_Action_In action = SteamVR_Input.actionsNonPoseNonSkeletonIn[actionIndex];
  194. if (action.GetActive(inputSource))
  195. CreateAndAddButtonInfo(action, inputSource);
  196. }
  197. ComputeTextEndTransforms();
  198. initialized = true;
  199. //Set the controller hints render model to not active
  200. renderModel.SetMeshRendererState(true);
  201. renderModel.gameObject.SetActive(false);
  202. }
  203. //-------------------------------------------------
  204. private void CreateAndAddButtonInfo(ISteamVR_Action_In action, SteamVR_Input_Sources inputSource)
  205. {
  206. Transform buttonTransform = null;
  207. List<MeshRenderer> buttonRenderers = new List<MeshRenderer>();
  208. StringBuilder buttonDebug = new StringBuilder();
  209. buttonDebug.Append("Looking for action: ");
  210. buttonDebug.AppendLine(action.GetShortName());
  211. buttonDebug.Append("Action localized origin: ");
  212. buttonDebug.AppendLine(action.GetLocalizedOrigin(inputSource));
  213. string actionComponentName = action.GetRenderModelComponentName(inputSource);
  214. if (componentTransformMap.ContainsKey(actionComponentName))
  215. {
  216. buttonDebug.AppendLine(string.Format("Found component: {0} for {1}", actionComponentName, action.GetShortName()));
  217. Transform componentTransform = componentTransformMap[actionComponentName];
  218. buttonTransform = componentTransform;
  219. buttonDebug.AppendLine(string.Format("Found componentTransform: {0}. buttonTransform: {1}", componentTransform, buttonTransform));
  220. buttonRenderers.AddRange(componentTransform.GetComponentsInChildren<MeshRenderer>());
  221. }
  222. else
  223. {
  224. buttonDebug.AppendLine(string.Format("Can't find component transform for action: {0}. Component name: \"{1}\"", action.GetShortName(), actionComponentName));
  225. }
  226. buttonDebug.AppendLine(string.Format("Found {0} renderers for {1}", buttonRenderers.Count, action.GetShortName()));
  227. foreach ( MeshRenderer renderer in buttonRenderers )
  228. {
  229. buttonDebug.Append("\t");
  230. buttonDebug.AppendLine(renderer.name);
  231. }
  232. HintDebugLog( buttonDebug.ToString() );
  233. if ( buttonTransform == null )
  234. {
  235. HintDebugLog( "Couldn't find buttonTransform for " + action.GetShortName());
  236. return;
  237. }
  238. ActionHintInfo hintInfo = new ActionHintInfo();
  239. actionHintInfos.Add( action, hintInfo );
  240. hintInfo.componentName = buttonTransform.name;
  241. hintInfo.renderers = buttonRenderers;
  242. //Get the local transform for the button
  243. for (int childIndex = 0; childIndex < buttonTransform.childCount; childIndex++)
  244. {
  245. Transform child = buttonTransform.GetChild(childIndex);
  246. if (child.name == SteamVR_RenderModel.k_localTransformName)
  247. hintInfo.localTransform = child;
  248. }
  249. OffsetType offsetType = OffsetType.Right;
  250. /*
  251. switch ( buttonID )
  252. {
  253. case EVRButtonId.k_EButton_SteamVR_Trigger:
  254. {
  255. offsetType = OffsetType.Right;
  256. }
  257. break;
  258. case EVRButtonId.k_EButton_ApplicationMenu:
  259. {
  260. offsetType = OffsetType.Right;
  261. }
  262. break;
  263. case EVRButtonId.k_EButton_System:
  264. {
  265. offsetType = OffsetType.Right;
  266. }
  267. break;
  268. case Valve.VR.EVRButtonId.k_EButton_Grip:
  269. {
  270. offsetType = OffsetType.Forward;
  271. }
  272. break;
  273. case Valve.VR.EVRButtonId.k_EButton_SteamVR_Touchpad:
  274. {
  275. offsetType = OffsetType.Up;
  276. }
  277. break;
  278. }
  279. */
  280. //Offset for the text end transform
  281. switch ( offsetType )
  282. {
  283. case OffsetType.Forward:
  284. hintInfo.textEndOffsetDir = hintInfo.localTransform.forward;
  285. break;
  286. case OffsetType.Back:
  287. hintInfo.textEndOffsetDir = -hintInfo.localTransform.forward;
  288. break;
  289. case OffsetType.Right:
  290. hintInfo.textEndOffsetDir = hintInfo.localTransform.right;
  291. break;
  292. case OffsetType.Up:
  293. hintInfo.textEndOffsetDir = hintInfo.localTransform.up;
  294. break;
  295. }
  296. //Create the text hint object
  297. Vector3 hintStartPos = hintInfo.localTransform.position + ( hintInfo.localTransform.forward * 0.01f );
  298. hintInfo.textHintObject = GameObject.Instantiate( textHintPrefab, hintStartPos, Quaternion.identity ) as GameObject;
  299. hintInfo.textHintObject.name = "Hint_" + hintInfo.componentName + "_Start";
  300. hintInfo.textHintObject.transform.SetParent( textHintParent );
  301. hintInfo.textHintObject.layer = gameObject.layer;
  302. hintInfo.textHintObject.tag = gameObject.tag;
  303. //Get all the relevant child objects
  304. hintInfo.textStartAnchor = hintInfo.textHintObject.transform.Find( "Start" );
  305. hintInfo.textEndAnchor = hintInfo.textHintObject.transform.Find( "End" );
  306. hintInfo.canvasOffset = hintInfo.textHintObject.transform.Find( "CanvasOffset" );
  307. hintInfo.line = hintInfo.textHintObject.transform.Find( "Line" ).GetComponent<LineRenderer>();
  308. hintInfo.textCanvas = hintInfo.textHintObject.GetComponentInChildren<Canvas>();
  309. hintInfo.text = hintInfo.textCanvas.GetComponentInChildren<Text>();
  310. hintInfo.textMesh = hintInfo.textCanvas.GetComponentInChildren<TextMesh>();
  311. hintInfo.textHintObject.SetActive( false );
  312. hintInfo.textStartAnchor.position = hintStartPos;
  313. if ( hintInfo.text != null )
  314. {
  315. hintInfo.text.text = hintInfo.componentName;
  316. }
  317. if ( hintInfo.textMesh != null )
  318. {
  319. hintInfo.textMesh.text = hintInfo.componentName;
  320. }
  321. centerPosition += hintInfo.textStartAnchor.position;
  322. // Scale hint components to match player size
  323. hintInfo.textCanvas.transform.localScale = Vector3.Scale( hintInfo.textCanvas.transform.localScale, player.transform.localScale );
  324. hintInfo.textStartAnchor.transform.localScale = Vector3.Scale( hintInfo.textStartAnchor.transform.localScale, player.transform.localScale );
  325. hintInfo.textEndAnchor.transform.localScale = Vector3.Scale( hintInfo.textEndAnchor.transform.localScale, player.transform.localScale );
  326. hintInfo.line.transform.localScale = Vector3.Scale( hintInfo.line.transform.localScale, player.transform.localScale );
  327. }
  328. //-------------------------------------------------
  329. private void ComputeTextEndTransforms()
  330. {
  331. //This is done as a separate step after all the ButtonHintInfos have been initialized
  332. //to make the text hints fan out appropriately based on the button's position on the controller.
  333. centerPosition /= actionHintInfos.Count;
  334. float maxDistanceFromCenter = 0.0f;
  335. foreach ( var hintInfo in actionHintInfos )
  336. {
  337. hintInfo.Value.distanceFromCenter = Vector3.Distance( hintInfo.Value.textStartAnchor.position, centerPosition );
  338. if ( hintInfo.Value.distanceFromCenter > maxDistanceFromCenter )
  339. {
  340. maxDistanceFromCenter = hintInfo.Value.distanceFromCenter;
  341. }
  342. }
  343. foreach ( var hintInfo in actionHintInfos )
  344. {
  345. Vector3 centerToButton = hintInfo.Value.textStartAnchor.position - centerPosition;
  346. centerToButton.Normalize();
  347. centerToButton = Vector3.Project( centerToButton, renderModel.transform.forward );
  348. //Spread out the text end positions based on the distance from the center
  349. float t = hintInfo.Value.distanceFromCenter / maxDistanceFromCenter;
  350. float scale = hintInfo.Value.distanceFromCenter * Mathf.Pow( 2, 10 * ( t - 1.0f ) ) * 20.0f;
  351. //Flip the direction of the end pos based on which hand this is
  352. float endPosOffset = 0.1f;
  353. Vector3 hintEndPos = hintInfo.Value.textStartAnchor.position + ( hintInfo.Value.textEndOffsetDir * endPosOffset ) + ( centerToButton * scale * 0.1f );
  354. if (SteamVR_Utils.IsValid(hintEndPos))
  355. {
  356. hintInfo.Value.textEndAnchor.position = hintEndPos;
  357. hintInfo.Value.canvasOffset.position = hintEndPos;
  358. }
  359. else
  360. {
  361. Debug.LogWarning("<b>[SteamVR Interaction]</b> Invalid end position for: " + hintInfo.Value.textStartAnchor.name, hintInfo.Value.textStartAnchor.gameObject);
  362. }
  363. hintInfo.Value.canvasOffset.localRotation = Quaternion.identity;
  364. }
  365. }
  366. //-------------------------------------------------
  367. private void ShowButtonHint( params ISteamVR_Action_In_Source[] actions )
  368. {
  369. renderModel.gameObject.SetActive( true );
  370. renderModel.GetComponentsInChildren<MeshRenderer>( renderers );
  371. for ( int i = 0; i < renderers.Count; i++ )
  372. {
  373. Texture mainTexture = renderers[i].material.mainTexture;
  374. renderers[i].sharedMaterial = usingMaterial;
  375. renderers[i].material.mainTexture = mainTexture;
  376. // This is to poke unity into setting the correct render queue for the model
  377. #if UNITY_URP
  378. renderers[i].material.renderQueue = usingMaterial.renderQueue;
  379. #else
  380. renderers[i].material.renderQueue = usingMaterial.shader.renderQueue;
  381. #endif
  382. }
  383. for ( int i = 0; i < actions.Length; i++ )
  384. {
  385. if ( actionHintInfos.ContainsKey( actions[i] ) )
  386. {
  387. ActionHintInfo hintInfo = actionHintInfos[actions[i]];
  388. foreach ( MeshRenderer renderer in hintInfo.renderers )
  389. {
  390. if ( !flashingRenderers.Contains( renderer ) )
  391. {
  392. flashingRenderers.Add( renderer );
  393. }
  394. }
  395. }
  396. }
  397. startTime = Time.realtimeSinceStartup;
  398. tickCount = 0.0f;
  399. }
  400. //-------------------------------------------------
  401. private void HideAllButtonHints()
  402. {
  403. Clear();
  404. if (renderModel != null && renderModel.gameObject != null)
  405. renderModel.gameObject.SetActive( false );
  406. }
  407. //-------------------------------------------------
  408. private void HideButtonHint( params ISteamVR_Action_In_Source[] actions )
  409. {
  410. Color baseColor = usingMaterial.GetColor( colorID );
  411. for ( int i = 0; i < actions.Length; i++ )
  412. {
  413. if ( actionHintInfos.ContainsKey(actions[i] ) )
  414. {
  415. ActionHintInfo hintInfo = actionHintInfos[actions[i]];
  416. foreach ( MeshRenderer renderer in hintInfo.renderers )
  417. {
  418. renderer.material.color = baseColor;
  419. flashingRenderers.Remove( renderer );
  420. }
  421. }
  422. }
  423. if ( flashingRenderers.Count == 0 )
  424. {
  425. renderModel.gameObject.SetActive( false );
  426. }
  427. }
  428. //-------------------------------------------------
  429. private bool IsButtonHintActive(ISteamVR_Action_In_Source action )
  430. {
  431. if ( actionHintInfos.ContainsKey(action) )
  432. {
  433. ActionHintInfo hintInfo = actionHintInfos[action];
  434. foreach ( MeshRenderer buttonRenderer in hintInfo.renderers )
  435. {
  436. if ( flashingRenderers.Contains( buttonRenderer ) )
  437. {
  438. return true;
  439. }
  440. }
  441. }
  442. return false;
  443. }
  444. //-------------------------------------------------
  445. private IEnumerator TestButtonHints()
  446. {
  447. while ( true )
  448. {
  449. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsNonPoseNonSkeletonIn.Length; actionIndex++)
  450. {
  451. ISteamVR_Action_In action = SteamVR_Input.actionsNonPoseNonSkeletonIn[actionIndex];
  452. if (action.GetActive(inputSource))
  453. {
  454. ShowButtonHint(action);
  455. yield return new WaitForSeconds(1.0f);
  456. }
  457. yield return null;
  458. }
  459. }
  460. }
  461. //-------------------------------------------------
  462. private IEnumerator TestTextHints()
  463. {
  464. while ( true )
  465. {
  466. for (int actionIndex = 0; actionIndex < SteamVR_Input.actionsNonPoseNonSkeletonIn.Length; actionIndex++)
  467. {
  468. ISteamVR_Action_In action = SteamVR_Input.actionsNonPoseNonSkeletonIn[actionIndex];
  469. if (action.GetActive(inputSource))
  470. {
  471. ShowText(action, action.GetShortName());
  472. yield return new WaitForSeconds(3.0f);
  473. }
  474. yield return null;
  475. }
  476. HideAllText();
  477. yield return new WaitForSeconds( 3.0f );
  478. }
  479. }
  480. //-------------------------------------------------
  481. void Update()
  482. {
  483. if ( renderModel != null && renderModel.gameObject.activeInHierarchy && flashingRenderers.Count > 0 )
  484. {
  485. Color baseColor = usingMaterial.GetColor( colorID );
  486. float flash = ( Time.realtimeSinceStartup - startTime ) * Mathf.PI * 2.0f;
  487. flash = Mathf.Cos( flash );
  488. flash = Util.RemapNumberClamped( flash, -1.0f, 1.0f, 0.0f, 1.0f );
  489. float ticks = ( Time.realtimeSinceStartup - startTime );
  490. if ( ticks - tickCount > 1.0f )
  491. {
  492. tickCount += 1.0f;
  493. hapticFlash.Execute(0, 0.005f, 0.005f, 1, inputSource);
  494. }
  495. for ( int i = 0; i < flashingRenderers.Count; i++ )
  496. {
  497. Renderer r = flashingRenderers[i];
  498. r.material.SetColor( colorID, Color.Lerp( baseColor, flashColor, flash ) );
  499. }
  500. if ( initialized )
  501. {
  502. foreach ( var hintInfo in actionHintInfos )
  503. {
  504. if ( hintInfo.Value.textHintActive )
  505. {
  506. UpdateTextHint( hintInfo.Value );
  507. }
  508. }
  509. }
  510. }
  511. }
  512. //-------------------------------------------------
  513. private void UpdateTextHint( ActionHintInfo hintInfo )
  514. {
  515. Transform playerTransform = player.hmdTransform;
  516. Vector3 vDir = playerTransform.position - hintInfo.canvasOffset.position;
  517. Quaternion standardLookat = Quaternion.LookRotation( vDir, Vector3.up );
  518. Quaternion upsideDownLookat = Quaternion.LookRotation( vDir, playerTransform.up );
  519. float flInterp;
  520. if ( playerTransform.forward.y > 0.0f )
  521. {
  522. flInterp = Util.RemapNumberClamped( playerTransform.forward.y, 0.6f, 0.4f, 1.0f, 0.0f );
  523. }
  524. else
  525. {
  526. flInterp = Util.RemapNumberClamped( playerTransform.forward.y, -0.8f, -0.6f, 1.0f, 0.0f );
  527. }
  528. hintInfo.canvasOffset.rotation = Quaternion.Slerp( standardLookat, upsideDownLookat, flInterp );
  529. Transform lineTransform = hintInfo.line.transform;
  530. hintInfo.line.useWorldSpace = false;
  531. hintInfo.line.SetPosition( 0, lineTransform.InverseTransformPoint( hintInfo.textStartAnchor.position ) );
  532. hintInfo.line.SetPosition( 1, lineTransform.InverseTransformPoint( hintInfo.textEndAnchor.position ) );
  533. }
  534. //-------------------------------------------------
  535. private void Clear()
  536. {
  537. renderers.Clear();
  538. flashingRenderers.Clear();
  539. }
  540. //-------------------------------------------------
  541. private void ShowText(ISteamVR_Action_In_Source action, string text, bool highlightButton = true )
  542. {
  543. if ( actionHintInfos.ContainsKey(action) )
  544. {
  545. ActionHintInfo hintInfo = actionHintInfos[action];
  546. hintInfo.textHintObject.SetActive( true );
  547. hintInfo.textHintActive = true;
  548. if ( hintInfo.text != null )
  549. {
  550. hintInfo.text.text = text;
  551. }
  552. if ( hintInfo.textMesh != null )
  553. {
  554. hintInfo.textMesh.text = text;
  555. }
  556. UpdateTextHint( hintInfo );
  557. if ( highlightButton )
  558. {
  559. ShowButtonHint(action);
  560. }
  561. renderModel.gameObject.SetActive( true );
  562. }
  563. }
  564. //-------------------------------------------------
  565. private void HideText(ISteamVR_Action_In_Source action)
  566. {
  567. if ( actionHintInfos.ContainsKey(action) )
  568. {
  569. ActionHintInfo hintInfo = actionHintInfos[action];
  570. hintInfo.textHintObject.SetActive( false );
  571. hintInfo.textHintActive = false;
  572. HideButtonHint(action);
  573. }
  574. }
  575. //-------------------------------------------------
  576. private void HideAllText()
  577. {
  578. if (actionHintInfos != null)
  579. {
  580. foreach (var hintInfo in actionHintInfos)
  581. {
  582. hintInfo.Value.textHintObject.SetActive(false);
  583. hintInfo.Value.textHintActive = false;
  584. }
  585. HideAllButtonHints();
  586. }
  587. }
  588. //-------------------------------------------------
  589. private string GetActiveHintText(ISteamVR_Action_In_Source action )
  590. {
  591. if ( actionHintInfos.ContainsKey(action) )
  592. {
  593. ActionHintInfo hintInfo = actionHintInfos[action];
  594. if ( hintInfo.textHintActive )
  595. {
  596. return hintInfo.text.text;
  597. }
  598. }
  599. return string.Empty;
  600. }
  601. //-------------------------------------------------
  602. // These are the static functions which are used to show/hide the hints
  603. //-------------------------------------------------
  604. //-------------------------------------------------
  605. private static ControllerButtonHints GetControllerButtonHints( Hand hand )
  606. {
  607. if ( hand != null )
  608. {
  609. ControllerButtonHints hints = hand.GetComponentInChildren<ControllerButtonHints>();
  610. if ( hints != null && hints.initialized )
  611. {
  612. return hints;
  613. }
  614. }
  615. return null;
  616. }
  617. //-------------------------------------------------
  618. public static void ShowButtonHint( Hand hand, params ISteamVR_Action_In_Source[] actions )
  619. {
  620. ControllerButtonHints hints = GetControllerButtonHints( hand );
  621. if ( hints != null )
  622. {
  623. hints.ShowButtonHint( actions );
  624. }
  625. }
  626. //-------------------------------------------------
  627. public static void HideButtonHint( Hand hand, params ISteamVR_Action_In_Source[] actions )
  628. {
  629. ControllerButtonHints hints = GetControllerButtonHints( hand );
  630. if ( hints != null )
  631. {
  632. hints.HideButtonHint( actions );
  633. }
  634. }
  635. //-------------------------------------------------
  636. public static void HideAllButtonHints( Hand hand )
  637. {
  638. ControllerButtonHints hints = GetControllerButtonHints( hand );
  639. if ( hints != null )
  640. {
  641. hints.HideAllButtonHints();
  642. }
  643. }
  644. //-------------------------------------------------
  645. public static bool IsButtonHintActive( Hand hand, ISteamVR_Action_In_Source action )
  646. {
  647. ControllerButtonHints hints = GetControllerButtonHints( hand );
  648. if ( hints != null )
  649. {
  650. return hints.IsButtonHintActive(action);
  651. }
  652. return false;
  653. }
  654. //-------------------------------------------------
  655. public static void ShowTextHint( Hand hand, ISteamVR_Action_In_Source action, string text, bool highlightButton = true )
  656. {
  657. ControllerButtonHints hints = GetControllerButtonHints( hand );
  658. if ( hints != null )
  659. {
  660. hints.ShowText(action, text, highlightButton );
  661. if (hand != null)
  662. {
  663. if (hints.autoSetWithControllerRangeOfMotion)
  664. hand.SetTemporarySkeletonRangeOfMotion(SkeletalMotionRangeChange.WithController);
  665. }
  666. }
  667. }
  668. //-------------------------------------------------
  669. public static void HideTextHint( Hand hand, ISteamVR_Action_In_Source action)
  670. {
  671. ControllerButtonHints hints = GetControllerButtonHints( hand );
  672. if ( hints != null )
  673. {
  674. hints.HideText(action);
  675. if (hand != null)
  676. {
  677. if (hints.autoSetWithControllerRangeOfMotion)
  678. hand.ResetTemporarySkeletonRangeOfMotion();
  679. }
  680. }
  681. }
  682. //-------------------------------------------------
  683. public static void HideAllTextHints( Hand hand )
  684. {
  685. ControllerButtonHints hints = GetControllerButtonHints( hand );
  686. if ( hints != null )
  687. {
  688. hints.HideAllText();
  689. }
  690. }
  691. //-------------------------------------------------
  692. public static string GetActiveHintText( Hand hand, ISteamVR_Action_In_Source action)
  693. {
  694. ControllerButtonHints hints = GetControllerButtonHints( hand );
  695. if ( hints != null )
  696. {
  697. return hints.GetActiveHintText(action);
  698. }
  699. return string.Empty;
  700. }
  701. }
  702. }