SteamVR_RenderModel.cs 34 KB

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