SteamVR_RenderModel.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. //======= Copyright (c) Valve Corporation, All rights reserved. ===============
  2. //
  3. // Purpose: Render model of associated tracked object
  4. //
  5. //=============================================================================
  6. using UnityEngine;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using System.Runtime.InteropServices;
  10. using Valve.VR;
  11. [ExecuteInEditMode]
  12. public class SteamVR_RenderModel : MonoBehaviour
  13. {
  14. public SteamVR_TrackedObject.EIndex index = SteamVR_TrackedObject.EIndex.None;
  15. public const string modelOverrideWarning = "Model override is really only meant to be used in " +
  16. "the scene view for lining things up; using it at runtime is discouraged. Use tracked device " +
  17. "index instead to ensure the correct model is displayed for all users.";
  18. [Tooltip(modelOverrideWarning)]
  19. public string modelOverride;
  20. [Tooltip("Shader to apply to model.")]
  21. public Shader shader;
  22. [Tooltip("Enable to print out when render models are loaded.")]
  23. public bool verbose = false;
  24. [Tooltip("If available, break down into separate components instead of loading as a single mesh.")]
  25. public bool createComponents = true;
  26. [Tooltip("Update transforms of components at runtime to reflect user action.")]
  27. public bool updateDynamically = true;
  28. // Additional controller settings for showing scrollwheel, etc.
  29. public RenderModel_ControllerMode_State_t controllerModeState;
  30. // Name of the sub-object which represents the "local" coordinate space for each component.
  31. public const string k_localTransformName = "attach";
  32. // Cached name of this render model for updating component transforms at runtime.
  33. public string renderModelName { get; private set; }
  34. // If someone knows how to keep these from getting cleaned up every time
  35. // you exit play mode, let me know. I've tried marking the RenderModel
  36. // class below as [System.Serializable] and switching to normal public
  37. // variables for mesh and material to get them to serialize properly,
  38. // as well as tried marking the mesh and material objects as
  39. // DontUnloadUnusedAsset, but Unity was still unloading them.
  40. // The hashtable is preserving its entries, but the mesh and material
  41. // variables are going null.
  42. public class RenderModel
  43. {
  44. public RenderModel(Mesh mesh, Material material)
  45. {
  46. this.mesh = mesh;
  47. this.material = material;
  48. }
  49. public Mesh mesh { get; private set; }
  50. public Material material { get; private set; }
  51. }
  52. public static Hashtable models = new Hashtable();
  53. public static Hashtable materials = new Hashtable();
  54. // Helper class to load render models interface on demand and clean up when done.
  55. public sealed class RenderModelInterfaceHolder : System.IDisposable
  56. {
  57. private bool needsShutdown, failedLoadInterface;
  58. private CVRRenderModels _instance;
  59. public CVRRenderModels instance
  60. {
  61. get
  62. {
  63. if (_instance == null && !failedLoadInterface)
  64. {
  65. if (!SteamVR.active && !SteamVR.usingNativeSupport)
  66. {
  67. var error = EVRInitError.None;
  68. OpenVR.Init(ref error, EVRApplicationType.VRApplication_Utility);
  69. needsShutdown = true;
  70. }
  71. _instance = OpenVR.RenderModels;
  72. if (_instance == null)
  73. {
  74. Debug.LogError("Failed to load IVRRenderModels interface version " + OpenVR.IVRRenderModels_Version);
  75. failedLoadInterface = true;
  76. }
  77. }
  78. return _instance;
  79. }
  80. }
  81. public void Dispose()
  82. {
  83. if (needsShutdown)
  84. OpenVR.Shutdown();
  85. }
  86. }
  87. private void OnModelSkinSettingsHaveChanged(VREvent_t vrEvent)
  88. {
  89. if (!string.IsNullOrEmpty(renderModelName))
  90. {
  91. renderModelName = "";
  92. UpdateModel();
  93. }
  94. }
  95. private void OnHideRenderModels(bool hidden)
  96. {
  97. var meshRenderer = GetComponent<MeshRenderer>();
  98. if (meshRenderer != null)
  99. meshRenderer.enabled = !hidden;
  100. foreach (var child in transform.GetComponentsInChildren<MeshRenderer>())
  101. child.enabled = !hidden;
  102. }
  103. private void OnDeviceConnected(int i, bool connected)
  104. {
  105. if (i != (int)index)
  106. return;
  107. if (connected)
  108. {
  109. UpdateModel();
  110. }
  111. }
  112. public void UpdateModel()
  113. {
  114. var system = OpenVR.System;
  115. if (system == null)
  116. return;
  117. var error = ETrackedPropertyError.TrackedProp_Success;
  118. var capacity = system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, null, 0, ref error);
  119. if (capacity <= 1)
  120. {
  121. Debug.LogError("Failed to get render model name for tracked object " + index);
  122. return;
  123. }
  124. var buffer = new System.Text.StringBuilder((int)capacity);
  125. system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, buffer, capacity, ref error);
  126. var s = buffer.ToString();
  127. if (renderModelName != s)
  128. {
  129. renderModelName = s;
  130. StartCoroutine(SetModelAsync(s));
  131. }
  132. }
  133. IEnumerator SetModelAsync(string renderModelName)
  134. {
  135. if (string.IsNullOrEmpty(renderModelName))
  136. yield break;
  137. // Preload all render models before asking for the data to create meshes.
  138. using (var holder = new RenderModelInterfaceHolder())
  139. {
  140. var renderModels = holder.instance;
  141. if (renderModels == null)
  142. yield break;
  143. // Gather names of render models to preload.
  144. string[] renderModelNames;
  145. var count = renderModels.GetComponentCount(renderModelName);
  146. if (count > 0)
  147. {
  148. renderModelNames = new string[count];
  149. for (int i = 0; i < count; i++)
  150. {
  151. var capacity = renderModels.GetComponentName(renderModelName, (uint)i, null, 0);
  152. if (capacity == 0)
  153. continue;
  154. var componentName = new System.Text.StringBuilder((int)capacity);
  155. if (renderModels.GetComponentName(renderModelName, (uint)i, componentName, capacity) == 0)
  156. continue;
  157. capacity = renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), null, 0);
  158. if (capacity == 0)
  159. continue;
  160. var name = new System.Text.StringBuilder((int)capacity);
  161. if (renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), name, capacity) == 0)
  162. continue;
  163. var s = name.ToString();
  164. // Only need to preload if not already cached.
  165. var model = models[s] as RenderModel;
  166. if (model == null || model.mesh == null)
  167. {
  168. renderModelNames[i] = s;
  169. }
  170. }
  171. }
  172. else
  173. {
  174. // Only need to preload if not already cached.
  175. var model = models[renderModelName] as RenderModel;
  176. if (model == null || model.mesh == null)
  177. {
  178. renderModelNames = new string[] { renderModelName };
  179. }
  180. else
  181. {
  182. renderModelNames = new string[0];
  183. }
  184. }
  185. // Keep trying every 100ms until all components finish loading.
  186. while (true)
  187. {
  188. var loading = false;
  189. foreach (var name in renderModelNames)
  190. {
  191. if (string.IsNullOrEmpty(name))
  192. continue;
  193. var pRenderModel = System.IntPtr.Zero;
  194. var error = renderModels.LoadRenderModel_Async(name, ref pRenderModel);
  195. if (error == EVRRenderModelError.Loading)
  196. {
  197. loading = true;
  198. }
  199. else if (error == EVRRenderModelError.None)
  200. {
  201. // Preload textures as well.
  202. var renderModel = MarshalRenderModel(pRenderModel);
  203. // Check the cache first.
  204. var material = materials[renderModel.diffuseTextureId] as Material;
  205. if (material == null || material.mainTexture == null)
  206. {
  207. var pDiffuseTexture = System.IntPtr.Zero;
  208. error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
  209. if (error == EVRRenderModelError.Loading)
  210. {
  211. loading = true;
  212. }
  213. }
  214. }
  215. }
  216. if (loading)
  217. {
  218. yield return new WaitForSecondsRealtime(0.1f);
  219. }
  220. else
  221. {
  222. break;
  223. }
  224. }
  225. }
  226. bool success = SetModel(renderModelName);
  227. SteamVR_Events.RenderModelLoaded.Send(this, success);
  228. }
  229. private bool SetModel(string renderModelName)
  230. {
  231. StripMesh(gameObject);
  232. using (var holder = new RenderModelInterfaceHolder())
  233. {
  234. if (createComponents)
  235. {
  236. if (LoadComponents(holder, renderModelName))
  237. {
  238. UpdateComponents(holder.instance);
  239. return true;
  240. }
  241. Debug.Log("[" + gameObject.name + "] Render model does not support components, falling back to single mesh.");
  242. }
  243. if (!string.IsNullOrEmpty(renderModelName))
  244. {
  245. var model = models[renderModelName] as RenderModel;
  246. if (model == null || model.mesh == null)
  247. {
  248. var renderModels = holder.instance;
  249. if (renderModels == null)
  250. return false;
  251. if (verbose)
  252. Debug.Log("Loading render model " + renderModelName);
  253. model = LoadRenderModel(renderModels, renderModelName, renderModelName);
  254. if (model == null)
  255. return false;
  256. models[renderModelName] = model;
  257. }
  258. gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
  259. gameObject.AddComponent<MeshRenderer>().sharedMaterial = model.material;
  260. return true;
  261. }
  262. }
  263. return false;
  264. }
  265. RenderModel LoadRenderModel(CVRRenderModels renderModels, string renderModelName, string baseName)
  266. {
  267. var pRenderModel = System.IntPtr.Zero;
  268. EVRRenderModelError error;
  269. while ( true )
  270. {
  271. error = renderModels.LoadRenderModel_Async(renderModelName, ref pRenderModel);
  272. if (error != EVRRenderModelError.Loading)
  273. break;
  274. Sleep();
  275. }
  276. if (error != EVRRenderModelError.None)
  277. {
  278. Debug.LogError(string.Format("Failed to load render model {0} - {1}", renderModelName, error.ToString()));
  279. return null;
  280. }
  281. var renderModel = MarshalRenderModel(pRenderModel);
  282. var vertices = new Vector3[renderModel.unVertexCount];
  283. var normals = new Vector3[renderModel.unVertexCount];
  284. var uv = new Vector2[renderModel.unVertexCount];
  285. var type = typeof(RenderModel_Vertex_t);
  286. for (int iVert = 0; iVert < renderModel.unVertexCount; iVert++)
  287. {
  288. var ptr = new System.IntPtr(renderModel.rVertexData.ToInt64() + iVert * Marshal.SizeOf(type));
  289. var vert = (RenderModel_Vertex_t)Marshal.PtrToStructure(ptr, type);
  290. vertices[iVert] = new Vector3(vert.vPosition.v0, vert.vPosition.v1, -vert.vPosition.v2);
  291. normals[iVert] = new Vector3(vert.vNormal.v0, vert.vNormal.v1, -vert.vNormal.v2);
  292. uv[iVert] = new Vector2(vert.rfTextureCoord0, vert.rfTextureCoord1);
  293. }
  294. int indexCount = (int)renderModel.unTriangleCount * 3;
  295. var indices = new short[indexCount];
  296. Marshal.Copy(renderModel.rIndexData, indices, 0, indices.Length);
  297. var triangles = new int[indexCount];
  298. for (int iTri = 0; iTri < renderModel.unTriangleCount; iTri++)
  299. {
  300. triangles[iTri * 3 + 0] = (int)indices[iTri * 3 + 2];
  301. triangles[iTri * 3 + 1] = (int)indices[iTri * 3 + 1];
  302. triangles[iTri * 3 + 2] = (int)indices[iTri * 3 + 0];
  303. }
  304. var mesh = new Mesh();
  305. mesh.vertices = vertices;
  306. mesh.normals = normals;
  307. mesh.uv = uv;
  308. mesh.triangles = triangles;
  309. #if (UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
  310. mesh.Optimize();
  311. #endif
  312. //mesh.hideFlags = HideFlags.DontUnloadUnusedAsset;
  313. // Check cache before loading texture.
  314. var material = materials[renderModel.diffuseTextureId] as Material;
  315. if (material == null || material.mainTexture == null)
  316. {
  317. var pDiffuseTexture = System.IntPtr.Zero;
  318. while (true)
  319. {
  320. error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
  321. if (error != EVRRenderModelError.Loading)
  322. break;
  323. Sleep();
  324. }
  325. if (error == EVRRenderModelError.None)
  326. {
  327. var diffuseTexture = MarshalRenderModel_TextureMap(pDiffuseTexture);
  328. var texture = new Texture2D(diffuseTexture.unWidth, diffuseTexture.unHeight, TextureFormat.RGBA32, false);
  329. if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11)
  330. {
  331. texture.Apply();
  332. while (true)
  333. {
  334. error = renderModels.LoadIntoTextureD3D11_Async(renderModel.diffuseTextureId, texture.GetNativeTexturePtr());
  335. if (error != EVRRenderModelError.Loading)
  336. break;
  337. Sleep();
  338. }
  339. }
  340. else
  341. {
  342. var textureMapData = new byte[diffuseTexture.unWidth * diffuseTexture.unHeight * 4]; // RGBA
  343. Marshal.Copy(diffuseTexture.rubTextureMapData, textureMapData, 0, textureMapData.Length);
  344. var colors = new Color32[diffuseTexture.unWidth * diffuseTexture.unHeight];
  345. int iColor = 0;
  346. for (int iHeight = 0; iHeight < diffuseTexture.unHeight; iHeight++)
  347. {
  348. for (int iWidth = 0; iWidth < diffuseTexture.unWidth; iWidth++)
  349. {
  350. var r = textureMapData[iColor++];
  351. var g = textureMapData[iColor++];
  352. var b = textureMapData[iColor++];
  353. var a = textureMapData[iColor++];
  354. colors[iHeight * diffuseTexture.unWidth + iWidth] = new Color32(r, g, b, a);
  355. }
  356. }
  357. texture.SetPixels32(colors);
  358. texture.Apply();
  359. }
  360. material = new Material(shader != null ? shader : Shader.Find("Standard"));
  361. material.mainTexture = texture;
  362. //material.hideFlags = HideFlags.DontUnloadUnusedAsset;
  363. materials[renderModel.diffuseTextureId] = material;
  364. renderModels.FreeTexture(pDiffuseTexture);
  365. }
  366. else
  367. {
  368. Debug.Log("Failed to load render model texture for render model " + renderModelName);
  369. }
  370. }
  371. // Delay freeing when we can since we'll often get multiple requests for the same model right
  372. // after another (e.g. two controllers or two basestations).
  373. #if UNITY_EDITOR
  374. if (!Application.isPlaying)
  375. renderModels.FreeRenderModel(pRenderModel);
  376. else
  377. #endif
  378. StartCoroutine(FreeRenderModel(pRenderModel));
  379. return new RenderModel(mesh, material);
  380. }
  381. IEnumerator FreeRenderModel(System.IntPtr pRenderModel)
  382. {
  383. yield return new WaitForSeconds(1.0f);
  384. using (var holder = new RenderModelInterfaceHolder())
  385. {
  386. var renderModels = holder.instance;
  387. renderModels.FreeRenderModel(pRenderModel);
  388. }
  389. }
  390. public Transform FindComponent(string componentName)
  391. {
  392. var t = transform;
  393. for (int i = 0; i < t.childCount; i++)
  394. {
  395. var child = t.GetChild(i);
  396. if (child.name == componentName)
  397. return child;
  398. }
  399. return null;
  400. }
  401. private void StripMesh(GameObject go)
  402. {
  403. var meshRenderer = go.GetComponent<MeshRenderer>();
  404. if (meshRenderer != null)
  405. DestroyImmediate(meshRenderer);
  406. var meshFilter = go.GetComponent<MeshFilter>();
  407. if (meshFilter != null)
  408. DestroyImmediate(meshFilter);
  409. }
  410. private bool LoadComponents(RenderModelInterfaceHolder holder, string renderModelName)
  411. {
  412. // Disable existing components (we will re-enable them if referenced by this new model).
  413. // Also strip mesh filter and renderer since these will get re-added if the new component needs them.
  414. var t = transform;
  415. for (int i = 0; i < t.childCount; i++)
  416. {
  417. var child = t.GetChild(i);
  418. child.gameObject.SetActive(false);
  419. StripMesh(child.gameObject);
  420. }
  421. // If no model specified, we're done; return success.
  422. if (string.IsNullOrEmpty(renderModelName))
  423. return true;
  424. var renderModels = holder.instance;
  425. if (renderModels == null)
  426. return false;
  427. var count = renderModels.GetComponentCount(renderModelName);
  428. if (count == 0)
  429. return false;
  430. for (int i = 0; i < count; i++)
  431. {
  432. var capacity = renderModels.GetComponentName(renderModelName, (uint)i, null, 0);
  433. if (capacity == 0)
  434. continue;
  435. var componentName = new System.Text.StringBuilder((int)capacity);
  436. if (renderModels.GetComponentName(renderModelName, (uint)i, componentName, capacity) == 0)
  437. continue;
  438. // Create (or reuse) a child object for this component (some components are dynamic and don't have meshes).
  439. t = FindComponent(componentName.ToString());
  440. if (t != null)
  441. {
  442. t.gameObject.SetActive(true);
  443. }
  444. else
  445. {
  446. t = new GameObject(componentName.ToString()).transform;
  447. t.parent = transform;
  448. t.gameObject.layer = gameObject.layer;
  449. // Also create a child 'attach' object for attaching things.
  450. var attach = new GameObject(k_localTransformName).transform;
  451. attach.parent = t;
  452. attach.localPosition = Vector3.zero;
  453. attach.localRotation = Quaternion.identity;
  454. attach.localScale = Vector3.one;
  455. attach.gameObject.layer = gameObject.layer;
  456. }
  457. // Reset transform.
  458. t.localPosition = Vector3.zero;
  459. t.localRotation = Quaternion.identity;
  460. t.localScale = Vector3.one;
  461. capacity = renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), null, 0);
  462. if (capacity == 0)
  463. continue;
  464. var componentRenderModelName = new System.Text.StringBuilder((int)capacity);
  465. if (renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), componentRenderModelName, capacity) == 0)
  466. continue;
  467. // Check the cache or load into memory.
  468. var model = models[componentRenderModelName] as RenderModel;
  469. if (model == null || model.mesh == null)
  470. {
  471. if (verbose)
  472. Debug.Log("Loading render model " + componentRenderModelName);
  473. model = LoadRenderModel(renderModels, componentRenderModelName.ToString(), renderModelName);
  474. if (model == null)
  475. continue;
  476. models[componentRenderModelName] = model;
  477. }
  478. t.gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
  479. t.gameObject.AddComponent<MeshRenderer>().sharedMaterial = model.material;
  480. }
  481. return true;
  482. }
  483. SteamVR_Events.Action deviceConnectedAction, hideRenderModelsAction, modelSkinSettingsHaveChangedAction;
  484. SteamVR_RenderModel()
  485. {
  486. deviceConnectedAction = SteamVR_Events.DeviceConnectedAction(OnDeviceConnected);
  487. hideRenderModelsAction = SteamVR_Events.HideRenderModelsAction(OnHideRenderModels);
  488. modelSkinSettingsHaveChangedAction = SteamVR_Events.SystemAction(EVREventType.VREvent_ModelSkinSettingsHaveChanged, OnModelSkinSettingsHaveChanged);
  489. }
  490. void OnEnable()
  491. {
  492. #if UNITY_EDITOR
  493. if (!Application.isPlaying)
  494. return;
  495. #endif
  496. if (!string.IsNullOrEmpty(modelOverride))
  497. {
  498. Debug.Log(modelOverrideWarning);
  499. enabled = false;
  500. return;
  501. }
  502. var system = OpenVR.System;
  503. if (system != null && system.IsTrackedDeviceConnected((uint)index))
  504. {
  505. UpdateModel();
  506. }
  507. deviceConnectedAction.enabled = true;
  508. hideRenderModelsAction.enabled = true;
  509. modelSkinSettingsHaveChangedAction.enabled = true;
  510. }
  511. void OnDisable()
  512. {
  513. #if UNITY_EDITOR
  514. if (!Application.isPlaying)
  515. return;
  516. #endif
  517. deviceConnectedAction.enabled = false;
  518. hideRenderModelsAction.enabled = false;
  519. modelSkinSettingsHaveChangedAction.enabled = false;
  520. }
  521. #if UNITY_EDITOR
  522. Hashtable values;
  523. #endif
  524. void Update()
  525. {
  526. #if UNITY_EDITOR
  527. if (!Application.isPlaying)
  528. {
  529. // See if anything has changed since this gets called whenever anything gets touched.
  530. var fields = GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
  531. bool modified = false;
  532. if (values == null)
  533. {
  534. modified = true;
  535. }
  536. else
  537. {
  538. foreach (var f in fields)
  539. {
  540. if (!values.Contains(f))
  541. {
  542. modified = true;
  543. break;
  544. }
  545. var v0 = values[f];
  546. var v1 = f.GetValue(this);
  547. if (v1 != null)
  548. {
  549. if (!v1.Equals(v0))
  550. {
  551. modified = true;
  552. break;
  553. }
  554. }
  555. else if (v0 != null)
  556. {
  557. modified = true;
  558. break;
  559. }
  560. }
  561. }
  562. if (modified)
  563. {
  564. if (renderModelName != modelOverride)
  565. {
  566. renderModelName = modelOverride;
  567. SetModel(modelOverride);
  568. }
  569. values = new Hashtable();
  570. foreach (var f in fields)
  571. values[f] = f.GetValue(this);
  572. }
  573. return; // Do not update transforms (below) when not playing in Editor (to avoid keeping OpenVR running all the time).
  574. }
  575. #endif
  576. // Update component transforms dynamically.
  577. if (updateDynamically)
  578. UpdateComponents(OpenVR.RenderModels);
  579. }
  580. Dictionary<int, string> nameCache;
  581. public void UpdateComponents(CVRRenderModels renderModels)
  582. {
  583. if (renderModels == null)
  584. return;
  585. var t = transform;
  586. if (t.childCount == 0)
  587. return;
  588. var controllerState = (index != SteamVR_TrackedObject.EIndex.None) ?
  589. SteamVR_Controller.Input((int)index).GetState() : new VRControllerState_t();
  590. if (nameCache == null)
  591. nameCache = new Dictionary<int, string>();
  592. for (int i = 0; i < t.childCount; i++)
  593. {
  594. var child = t.GetChild(i);
  595. // Cache names since accessing an object's name allocate memory.
  596. string name;
  597. if (!nameCache.TryGetValue(child.GetInstanceID(), out name))
  598. {
  599. name = child.name;
  600. nameCache.Add(child.GetInstanceID(), name);
  601. }
  602. var componentState = new RenderModel_ComponentState_t();
  603. if (!renderModels.GetComponentState(renderModelName, name, ref controllerState, ref controllerModeState, ref componentState))
  604. continue;
  605. var componentTransform = new SteamVR_Utils.RigidTransform(componentState.mTrackingToComponentRenderModel);
  606. child.localPosition = componentTransform.pos;
  607. child.localRotation = componentTransform.rot;
  608. var attach = child.Find(k_localTransformName);
  609. if (attach != null)
  610. {
  611. var attachTransform = new SteamVR_Utils.RigidTransform(componentState.mTrackingToComponentLocal);
  612. attach.position = t.TransformPoint(attachTransform.pos);
  613. attach.rotation = t.rotation * attachTransform.rot;
  614. }
  615. bool visible = (componentState.uProperties & (uint)EVRComponentProperty.IsVisible) != 0;
  616. if (visible != child.gameObject.activeSelf)
  617. {
  618. child.gameObject.SetActive(visible);
  619. }
  620. }
  621. }
  622. public void SetDeviceIndex(int index)
  623. {
  624. this.index = (SteamVR_TrackedObject.EIndex)index;
  625. modelOverride = "";
  626. if (enabled)
  627. {
  628. UpdateModel();
  629. }
  630. }
  631. private static void Sleep()
  632. {
  633. #if !UNITY_METRO
  634. System.Threading.Thread.Sleep(1);
  635. #endif
  636. }
  637. /// <summary>
  638. /// Helper function to handle the inconvenient fact that the packing for RenderModel_t is
  639. /// different on Linux/OSX (4) than it is on Windows (8)
  640. /// </summary>
  641. /// <param name="pRenderModel">native pointer to the RenderModel_t</param>
  642. /// <returns></returns>
  643. private RenderModel_t MarshalRenderModel(System.IntPtr pRenderModel)
  644. {
  645. if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
  646. (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
  647. {
  648. var packedModel = (RenderModel_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t_Packed));
  649. RenderModel_t model = new RenderModel_t();
  650. packedModel.Unpack(ref model);
  651. return model;
  652. }
  653. else
  654. {
  655. return (RenderModel_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t));
  656. }
  657. }
  658. /// <summary>
  659. /// Helper function to handle the inconvenient fact that the packing for RenderModel_TextureMap_t is
  660. /// different on Linux/OSX (4) than it is on Windows (8)
  661. /// </summary>
  662. /// <param name="pRenderModel">native pointer to the RenderModel_TextureMap_t</param>
  663. /// <returns></returns>
  664. private RenderModel_TextureMap_t MarshalRenderModel_TextureMap(System.IntPtr pRenderModel)
  665. {
  666. if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
  667. (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
  668. {
  669. var packedModel = (RenderModel_TextureMap_t_Packed)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t_Packed));
  670. RenderModel_TextureMap_t model = new RenderModel_TextureMap_t();
  671. packedModel.Unpack(ref model);
  672. return model;
  673. }
  674. else
  675. {
  676. return (RenderModel_TextureMap_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t));
  677. }
  678. }
  679. }