5using System.Collections;
6using System.Collections.Generic;
7using System.Runtime.InteropServices;
9using UnityEngine.Events;
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.";
28 [Tooltip(
"Shader to apply to model.")]
31 [Tooltip(
"Enable to print out when render models are loaded.")]
34 [Tooltip(
"If available, break down into separate components instead of loading as a single mesh.")]
37 [Tooltip(
"Update transforms of components at runtime to reflect user action.")]
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.")]
54 private Dictionary<string, Transform> componentAttachPoints =
new Dictionary<string, Transform>();
56 private List<MeshRenderer> meshRenderers =
new List<MeshRenderer>();
74 public Mesh
mesh {
get;
private set; }
78 public static Hashtable
models =
new Hashtable();
79 public static Hashtable
materials =
new Hashtable();
84 private bool needsShutdown, failedLoadInterface;
85 private CVRRenderModels _instance;
90 if (_instance ==
null && !failedLoadInterface)
92 if (Application.isEditor && Application.isPlaying ==
false)
95 _instance = OpenVR.RenderModels;
96 if (_instance ==
null)
98 Debug.LogError(
"<b>[OVRT]</b> Failed to load IVRRenderModels interface version " + OpenVR.IVRRenderModels_Version);
99 failedLoadInterface =
true;
112 private void OnModelSkinSettingsHaveChanged()
123 for (
int rendererIndex = 0; rendererIndex < meshRenderers.Count; rendererIndex++)
125 MeshRenderer renderer = meshRenderers[rendererIndex];
127 if (renderer !=
null)
128 renderer.enabled = state;
132 private void OnHideRenderModels(
bool hidden)
137 private void OnDeviceConnected(
int i,
bool connected)
148 private void OnTrackedDeviceIndexChanged(
int i)
155 var system = OpenVR.System;
159 var error = ETrackedPropertyError.TrackedProp_Success;
160 var capacity = system.GetStringTrackedDeviceProperty((uint)
index, ETrackedDeviceProperty.Prop_RenderModelName_String,
null, 0, ref error);
163 Debug.LogError(
"<b>[OVRT]</b> Failed to get render model name for tracked object " +
index);
167 var buffer =
new System.Text.StringBuilder((
int)capacity);
168 system.GetStringTrackedDeviceProperty((uint)
index, ETrackedDeviceProperty.Prop_RenderModelName_String, buffer, capacity, ref error);
170 var s = buffer.ToString();
173 StartCoroutine(SetModelAsync(s));
177 IEnumerator SetModelAsync(
string newRenderModelName)
179 meshRenderers.Clear();
181 if (
string.IsNullOrEmpty(newRenderModelName))
185 using (RenderModelInterfaceHolder holder =
new RenderModelInterfaceHolder())
187 CVRRenderModels renderModels = holder.instance;
188 if (renderModels ==
null)
192 string[] renderModelNames;
194 uint count = renderModels.GetComponentCount(newRenderModelName);
197 renderModelNames =
new string[count];
199 for (
int componentIndex = 0; componentIndex < count; componentIndex++)
201 uint capacity = renderModels.GetComponentName(newRenderModelName, (uint)componentIndex,
null, 0);
205 var componentNameStringBuilder =
new System.Text.StringBuilder((
int)capacity);
206 if (renderModels.GetComponentName(newRenderModelName, (uint)componentIndex, componentNameStringBuilder, capacity) == 0)
209 string componentName = componentNameStringBuilder.ToString();
211 capacity = renderModels.GetComponentRenderModelName(newRenderModelName, componentName,
null, 0);
215 var nameStringBuilder =
new System.Text.StringBuilder((
int)capacity);
216 if (renderModels.GetComponentRenderModelName(newRenderModelName, componentName, nameStringBuilder, capacity) == 0)
219 var s = nameStringBuilder.ToString();
222 RenderModel model =
models[s] as RenderModel;
223 if (model ==
null || model.mesh ==
null)
225 renderModelNames[componentIndex] = s;
232 RenderModel model =
models[newRenderModelName] as RenderModel;
233 if (model ==
null || model.mesh ==
null)
235 renderModelNames =
new string[] { newRenderModelName };
239 renderModelNames =
new string[0];
247 for (
int renderModelNameIndex = 0; renderModelNameIndex < renderModelNames.Length; renderModelNameIndex++)
249 if (
string.IsNullOrEmpty(renderModelNames[renderModelNameIndex]))
252 var pRenderModel = System.IntPtr.Zero;
254 var error = renderModels.LoadRenderModel_Async(renderModelNames[renderModelNameIndex], ref pRenderModel);
257 if (error == EVRRenderModelError.Loading)
261 else if (error == EVRRenderModelError.None)
264 var renderModel = MarshalRenderModel(pRenderModel);
267 var material =
materials[renderModel.diffuseTextureId] as Material;
268 if (material ==
null || material.mainTexture ==
null)
270 var pDiffuseTexture = System.IntPtr.Zero;
272 error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
275 if (error == EVRRenderModelError.Loading)
285 yield
return new WaitForSecondsRealtime(0.1f);
294 bool success = SetModel(newRenderModelName);
295 this.renderModelName = newRenderModelName;
296 OVRT_Events.RenderModelLoaded.Invoke(
this, success);
301 StripMesh(gameObject);
303 using (var holder =
new RenderModelInterfaceHolder())
307 componentAttachPoints.Clear();
315 Debug.Log(
"<b>[OVRT]</b> [" + gameObject.name +
"] Render model does not support components, falling back to single mesh.");
321 if (model ==
null || model.mesh ==
null)
323 var renderModels = holder.instance;
324 if (renderModels ==
null)
337 gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
338 MeshRenderer newRenderer = gameObject.AddComponent<MeshRenderer>();
339 newRenderer.sharedMaterial = model.material;
340 meshRenderers.Add(newRenderer);
348 RenderModel LoadRenderModel(CVRRenderModels renderModels,
string renderModelName,
string baseName)
350 var pRenderModel = System.IntPtr.Zero;
352 EVRRenderModelError error;
355 error = renderModels.LoadRenderModel_Async(
renderModelName, ref pRenderModel);
356 if (error != EVRRenderModelError.Loading)
362 if (error != EVRRenderModelError.None)
364 Debug.LogError(
string.Format(
"<b>[OVRT]</b> Failed to load render model {0} - {1}",
renderModelName, error.ToString()));
368 var renderModel = MarshalRenderModel(pRenderModel);
370 var vertices =
new Vector3[renderModel.unVertexCount];
371 var normals =
new Vector3[renderModel.unVertexCount];
372 var uv =
new Vector2[renderModel.unVertexCount];
374 var type = typeof(RenderModel_Vertex_t);
375 for (
int iVert = 0; iVert < renderModel.unVertexCount; iVert++)
377 var ptr =
new System.IntPtr(renderModel.rVertexData.ToInt64() + iVert * Marshal.SizeOf(type));
378 var vert = (RenderModel_Vertex_t)Marshal.PtrToStructure(ptr, type);
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);
385 int indexCount = (int)renderModel.unTriangleCount * 3;
386 var indices =
new short[indexCount];
387 Marshal.Copy(renderModel.rIndexData, indices, 0, indices.Length);
389 var triangles =
new int[indexCount];
390 for (
int iTri = 0; iTri < renderModel.unTriangleCount; iTri++)
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];
397 var mesh =
new Mesh();
398 mesh.vertices = vertices;
399 mesh.normals = normals;
401 mesh.triangles = triangles;
403#if (UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
409 var material =
materials[renderModel.diffuseTextureId] as Material;
410 if (material ==
null || material.mainTexture ==
null)
412 var pDiffuseTexture = System.IntPtr.Zero;
416 error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
417 if (error != EVRRenderModelError.Loading)
423 if (error == EVRRenderModelError.None)
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)
430 System.IntPtr texturePointer = texture.GetNativeTexturePtr();
433 error = renderModels.LoadIntoTextureD3D11_Async(renderModel.diffuseTextureId, texturePointer);
434 if (error != EVRRenderModelError.Loading)
442 var textureMapData =
new byte[diffuseTexture.unWidth * diffuseTexture.unHeight * 4];
443 Marshal.Copy(diffuseTexture.rubTextureMapData, textureMapData, 0, textureMapData.Length);
445 var colors =
new Color32[diffuseTexture.unWidth * diffuseTexture.unHeight];
447 for (
int iHeight = 0; iHeight < diffuseTexture.unHeight; iHeight++)
449 for (
int iWidth = 0; iWidth < diffuseTexture.unWidth; iWidth++)
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);
459 texture.SetPixels32(colors);
464 material =
new Material(
shader !=
null ?
shader : Shader.Find(
"Universal Render Pipeline/Lit"));
466 material =
new Material(
shader !=
null ?
shader : Shader.Find(
"Standard"));
469 material.mainTexture = texture;
472 materials[renderModel.diffuseTextureId] = material;
474 renderModels.FreeTexture(pDiffuseTexture);
478 Debug.Log(
"<b>[OVRT]</b> Failed to load render model texture for render model " +
renderModelName +
". Error: " + error.ToString());
485 if (!Application.isPlaying)
486 renderModels.FreeRenderModel(pRenderModel);
489 StartCoroutine(FreeRenderModel(pRenderModel));
491 return new RenderModel(mesh, material);
494 IEnumerator FreeRenderModel(System.IntPtr pRenderModel)
496 yield
return new WaitForSeconds(1.0f);
498 using (var holder =
new RenderModelInterfaceHolder())
500 var renderModels = holder.instance;
501 renderModels.FreeRenderModel(pRenderModel);
507 if (inTransform ==
null)
508 inTransform = this.transform;
510 for (
int childIndex = 0; childIndex < inTransform.childCount; childIndex++)
512 Transform child = inTransform.GetChild(childIndex);
513 if (child.name == componentName)
522 if (componentName ==
null)
523 return this.transform;
525 if (componentAttachPoints.ContainsKey(componentName))
526 return componentAttachPoints[componentName];
531 private void StripMesh(GameObject go)
533 var meshRenderer = go.GetComponent<MeshRenderer>();
534 if (meshRenderer !=
null)
535 DestroyImmediate(meshRenderer);
537 var meshFilter = go.GetComponent<MeshFilter>();
538 if (meshFilter !=
null)
539 DestroyImmediate(meshFilter);
542 private bool LoadComponents(RenderModelInterfaceHolder holder,
string renderModelName)
547 for (
int childIndex = 0; childIndex < t.childCount; childIndex++)
549 var child = t.GetChild(childIndex);
550 child.gameObject.SetActive(
false);
551 StripMesh(child.gameObject);
558 var renderModels = holder.instance;
559 if (renderModels ==
null)
566 for (
int i = 0; i < count; i++)
568 var capacity = renderModels.GetComponentName(
renderModelName, (uint)i,
null, 0);
572 System.Text.StringBuilder componentNameStringBuilder =
new System.Text.StringBuilder((
int)capacity);
573 if (renderModels.GetComponentName(
renderModelName, (uint)i, componentNameStringBuilder, capacity) == 0)
576 string componentName = componentNameStringBuilder.ToString();
582 t.gameObject.SetActive(
true);
587 t =
new GameObject(componentName).transform;
588 t.parent = transform;
589 t.gameObject.layer = gameObject.layer;
594 attach.localPosition = Vector3.zero;
595 attach.localRotation = Quaternion.identity;
596 attach.localScale = Vector3.one;
597 attach.gameObject.layer = gameObject.layer;
599 componentAttachPoints[componentName] = attach;
603 t.localPosition = Vector3.zero;
604 t.localRotation = Quaternion.identity;
605 t.localScale = Vector3.one;
610 if (
renderModelName ==
"{htc}vr_tracker_vive_1_0" && componentName ==
"body")
612 t.Translate(
new Vector3(0, 0, 0.0073f), Space.Self);
614 if (
renderModelName ==
"{htc}vr_tracker_vive_3_0" && componentName ==
"body")
616 t.Translate(
new Vector3(0, 0, 0.008f), Space.Self);
620 capacity = renderModels.GetComponentRenderModelName(
renderModelName, componentName,
null, 0);
624 var componentRenderModelNameStringBuilder =
new System.Text.StringBuilder((
int)capacity);
625 if (renderModels.GetComponentRenderModelName(
renderModelName, componentName, componentRenderModelNameStringBuilder, capacity) == 0)
628 string componentRenderModelName = componentRenderModelNameStringBuilder.ToString();
631 var model =
models[componentRenderModelName] as RenderModel;
632 if (model ==
null || model.mesh ==
null)
635 Debug.Log(
"<b>[OVRT]</b> Loading render model " + componentRenderModelName);
637 model = LoadRenderModel(renderModels, componentRenderModelName,
renderModelName);
641 models[componentRenderModelName] = model;
644 t.gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
645 MeshRenderer newRenderer = t.gameObject.AddComponent<MeshRenderer>();
646 newRenderer.sharedMaterial = model.material;
647 meshRenderers.Add(newRenderer);
653 private UnityAction<int, bool> _onDeviceConnectedAction;
654 private UnityAction<bool> _onHideRenderModelsAction;
655 private UnityAction _onModelSkinSettingsHaveChanged;
660 _onDeviceConnectedAction += OnDeviceConnected;
661 _onHideRenderModelsAction += OnHideRenderModels;
662 _onModelSkinSettingsHaveChanged += OnModelSkinSettingsHaveChanged;
667 var system = OpenVR.System;
668 if (system !=
null && system.IsTrackedDeviceConnected((uint)
index))
677 if (!Application.isPlaying)
689 trackedDevice = this.gameObject.GetComponent<OVRT_TrackedDevice>();
698 OVRT_Events.TrackedDeviceConnected.AddListener(_onDeviceConnectedAction);
699 OVRT_Events.HideRenderModelsChanged.AddListener(_onHideRenderModelsAction);
700 OVRT_Events.ModelSkinSettingsHaveChanged.AddListener(_onModelSkinSettingsHaveChanged);
706 if (!Application.isPlaying)
715 OVRT_Events.TrackedDeviceConnected.RemoveListener(_onDeviceConnectedAction);
716 OVRT_Events.HideRenderModelsChanged.RemoveListener(_onHideRenderModelsAction);
717 OVRT_Events.ModelSkinSettingsHaveChanged.RemoveListener(_onModelSkinSettingsHaveChanged);
726 if (!Application.isPlaying)
729 var fields = GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
731 bool modified =
false;
739 foreach (var f
in fields)
741 if (!values.Contains(f))
748 var v1 = f.GetValue(
this);
773 values =
new Hashtable();
774 foreach (var f
in fields)
775 values[f] = f.GetValue(
this);
786 Dictionary<int, string> nameCache;
790 if (renderModels ==
null)
793 if (transform.childCount == 0)
796 if (nameCache ==
null)
797 nameCache =
new Dictionary<int, string>();
799 var system = OpenVR.System;
803 for (
int childIndex = 0; childIndex < transform.childCount; childIndex++)
805 Transform child = transform.GetChild(childIndex);
808 string componentName;
809 if (!nameCache.TryGetValue(child.GetInstanceID(), out componentName))
811 componentName = child.name;
812 nameCache.Add(child.GetInstanceID(), componentName);
815 var controllerState =
new VRControllerState_t();
816 system.GetControllerState((uint)
index, ref controllerState, (uint)Marshal.SizeOf(typeof(VRControllerState_t)));
818 var componentState =
new RenderModel_ComponentState_t();
820 if (!renderModels.GetComponentState(componentName, componentName, ref controllerState, ref
controllerModeState, ref componentState))
826 child.localPosition = componentState.mTrackingToComponentRenderModel.GetPosition();
827 child.localRotation = componentState.mTrackingToComponentRenderModel.GetRotation();
829 Transform attach =
null;
830 for (
int childChildIndex = 0; childChildIndex < child.childCount; childChildIndex++)
832 Transform childChild = child.GetChild(childChildIndex);
833 int childInstanceID = childChild.GetInstanceID();
835 if (!nameCache.TryGetValue(childInstanceID, out childName))
837 childName = childChild.name;
838 nameCache.Add(childInstanceID, componentName);
847 attach.position = transform.TransformPoint(componentState.mTrackingToComponentLocal.GetPosition());
848 attach.rotation = transform.rotation * componentState.mTrackingToComponentLocal.GetRotation();
853 bool visible = (componentState.uProperties & (uint)EVRComponentProperty.IsVisible) != 0;
854 if (visible != child.gameObject.activeSelf)
856 child.gameObject.SetActive(visible);
878 private static void Sleep()
882 System.Threading.Thread.Sleep(1);
892 private RenderModel_t MarshalRenderModel(System.IntPtr pRenderModel)
894 if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
895 (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
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);
904 return (RenderModel_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_t));
914 private RenderModel_TextureMap_t MarshalRenderModel_TextureMap(System.IntPtr pRenderModel)
916 if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
917 (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
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);
926 return (RenderModel_TextureMap_t)Marshal.PtrToStructure(pRenderModel, typeof(RenderModel_TextureMap_t));
RenderModel(Mesh mesh, Material material)
void SetDeviceIndex(int newIndex)
OVRT_TrackedDevice trackedDevice
OVRT_TrackedObject.EIndex index
void UpdateComponents(CVRRenderModels renderModels)
void SetMeshRendererState(bool state)
const string modelOverrideWarning
bool initializedAttachPoints
RenderModel_ControllerMode_State_t controllerModeState
Transform GetComponentTransform(string componentName)
Transform FindTransformByName(string componentName, Transform inTransform=null)
static Hashtable materials
bool fixTrackerModelCenter
const string k_localTransformName
UnityEvent< int > onDeviceIndexChanged
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...
static bool InitializeTemporarySession()
static void ExitTemporarySession()