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