8 using System.Collections;
9 using System.Collections.Generic;
10 using System.Runtime.InteropServices;
16 public SteamVR_TrackedObject.EIndex index = SteamVR_TrackedObject.EIndex.None;
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.";
22 [Tooltip(modelOverrideWarning)]
23 public string modelOverride;
25 [Tooltip(
"Shader to apply to model.")]
28 [Tooltip(
"Enable to print out when render models are loaded.")]
29 public bool verbose =
false;
31 [Tooltip(
"If available, break down into separate components instead of loading as a single mesh.")]
32 public bool createComponents =
true;
34 [Tooltip(
"Update transforms of components at runtime to reflect user action.")]
35 public bool updateDynamically =
true;
41 public const string k_localTransformName =
"attach";
44 public string renderModelName {
get;
private set; }
60 this.material = material;
62 public Mesh mesh {
get;
private set; }
63 public Material material {
get;
private set; }
66 public static Hashtable models =
new Hashtable();
67 public static Hashtable materials =
new Hashtable();
72 private bool needsShutdown, failedLoadInterface;
78 if (_instance == null && !failedLoadInterface)
82 var error = EVRInitError.None;
83 OpenVR.Init(ref error, EVRApplicationType.VRApplication_Utility);
87 _instance = OpenVR.RenderModels;
88 if (_instance == null)
90 Debug.LogError(
"Failed to load IVRRenderModels interface version " + OpenVR.IVRRenderModels_Version);
91 failedLoadInterface =
true;
104 private void OnModelSkinSettingsHaveChanged(
VREvent_t vrEvent)
106 if (!
string.IsNullOrEmpty(renderModelName))
108 renderModelName =
"";
113 private void OnHideRenderModels(
bool hidden)
115 var meshRenderer = GetComponent<MeshRenderer>();
116 if (meshRenderer != null)
117 meshRenderer.enabled = !hidden;
118 foreach (var child
in transform.GetComponentsInChildren<MeshRenderer>())
119 child.enabled = !hidden;
122 private void OnDeviceConnected(
int i,
bool connected)
133 public void UpdateModel()
135 var system = OpenVR.System;
139 var error = ETrackedPropertyError.TrackedProp_Success;
140 var capacity = system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, null, 0, ref error);
143 Debug.LogError(
"Failed to get render model name for tracked object " + index);
147 var buffer =
new System.Text.StringBuilder((int)capacity);
148 system.GetStringTrackedDeviceProperty((uint)index, ETrackedDeviceProperty.Prop_RenderModelName_String, buffer, capacity, ref error);
150 var s = buffer.ToString();
151 if (renderModelName != s)
154 StartCoroutine(SetModelAsync(s));
158 IEnumerator SetModelAsync(
string renderModelName)
160 if (
string.IsNullOrEmpty(renderModelName))
164 using (var holder =
new RenderModelInterfaceHolder())
166 var renderModels = holder.instance;
167 if (renderModels == null)
171 string[] renderModelNames;
173 var count = renderModels.GetComponentCount(renderModelName);
176 renderModelNames =
new string[count];
178 for (
int i = 0; i < count; i++)
180 var capacity = renderModels.GetComponentName(renderModelName, (uint)i, null, 0);
184 var componentName =
new System.Text.StringBuilder((int)capacity);
185 if (renderModels.GetComponentName(renderModelName, (uint)i, componentName, capacity) == 0)
188 capacity = renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), null, 0);
192 var name =
new System.Text.StringBuilder((int)capacity);
193 if (renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), name, capacity) == 0)
196 var s = name.ToString();
199 var model = models[s] as RenderModel;
200 if (model == null || model.mesh == null)
202 renderModelNames[i] = s;
209 var model = models[renderModelName] as RenderModel;
210 if (model == null || model.mesh == null)
212 renderModelNames =
new string[] { renderModelName };
216 renderModelNames =
new string[0];
224 foreach (var name
in renderModelNames)
226 if (
string.IsNullOrEmpty(name))
229 var pRenderModel = System.IntPtr.Zero;
231 var error = renderModels.LoadRenderModel_Async(name, ref pRenderModel);
232 if (error == EVRRenderModelError.Loading)
236 else if (error == EVRRenderModelError.None)
239 var renderModel = MarshalRenderModel(pRenderModel);
242 var material = materials[renderModel.diffuseTextureId] as Material;
243 if (material == null || material.mainTexture == null)
245 var pDiffuseTexture = System.IntPtr.Zero;
247 error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
248 if (error == EVRRenderModelError.Loading)
258 yield
return new WaitForSecondsRealtime(0.1f);
267 bool success = SetModel(renderModelName);
268 SteamVR_Events.RenderModelLoaded.Send(
this, success);
271 private bool SetModel(
string renderModelName)
273 StripMesh(gameObject);
275 using (var holder =
new RenderModelInterfaceHolder())
277 if (createComponents)
279 if (LoadComponents(holder, renderModelName))
281 UpdateComponents(holder.instance);
285 Debug.Log(
"[" + gameObject.name +
"] Render model does not support components, falling back to single mesh.");
288 if (!
string.IsNullOrEmpty(renderModelName))
290 var model = models[renderModelName] as RenderModel;
291 if (model == null || model.mesh == null)
293 var renderModels = holder.instance;
294 if (renderModels == null)
298 Debug.Log(
"Loading render model " + renderModelName);
300 model = LoadRenderModel(renderModels, renderModelName, renderModelName);
304 models[renderModelName] = model;
307 gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
308 gameObject.AddComponent<MeshRenderer>().sharedMaterial = model.material;
316 RenderModel LoadRenderModel(
CVRRenderModels renderModels,
string renderModelName,
string baseName)
318 var pRenderModel = System.IntPtr.Zero;
320 EVRRenderModelError error;
323 error = renderModels.LoadRenderModel_Async(renderModelName, ref pRenderModel);
324 if (error != EVRRenderModelError.Loading)
330 if (error != EVRRenderModelError.None)
332 Debug.LogError(string.Format(
"Failed to load render model {0} - {1}", renderModelName, error.ToString()));
336 var renderModel = MarshalRenderModel(pRenderModel);
338 var vertices =
new Vector3[renderModel.unVertexCount];
339 var normals =
new Vector3[renderModel.unVertexCount];
340 var uv =
new Vector2[renderModel.unVertexCount];
343 for (
int iVert = 0; iVert < renderModel.unVertexCount; iVert++)
345 var ptr =
new System.IntPtr(renderModel.rVertexData.ToInt64() + iVert * Marshal.SizeOf(type));
348 vertices[iVert] =
new Vector3(vert.vPosition.v0, vert.vPosition.v1, -vert.vPosition.v2);
349 normals[iVert] =
new Vector3(vert.vNormal.v0, vert.vNormal.v1, -vert.vNormal.v2);
350 uv[iVert] =
new Vector2(vert.rfTextureCoord0, vert.rfTextureCoord1);
353 int indexCount = (int)renderModel.unTriangleCount * 3;
354 var indices =
new short[indexCount];
355 Marshal.Copy(renderModel.rIndexData, indices, 0, indices.Length);
357 var triangles =
new int[indexCount];
358 for (
int iTri = 0; iTri < renderModel.unTriangleCount; iTri++)
360 triangles[iTri * 3 + 0] = (int)indices[iTri * 3 + 2];
361 triangles[iTri * 3 + 1] = (int)indices[iTri * 3 + 1];
362 triangles[iTri * 3 + 2] = (int)indices[iTri * 3 + 0];
365 var mesh =
new Mesh();
366 mesh.vertices = vertices;
367 mesh.normals = normals;
369 mesh.triangles = triangles;
371 #if (UNITY_5_4 || UNITY_5_3 || UNITY_5_2 || UNITY_5_1 || UNITY_5_0)
377 var material = materials[renderModel.diffuseTextureId] as Material;
378 if (material == null || material.mainTexture == null)
380 var pDiffuseTexture = System.IntPtr.Zero;
384 error = renderModels.LoadTexture_Async(renderModel.diffuseTextureId, ref pDiffuseTexture);
385 if (error != EVRRenderModelError.Loading)
391 if (error == EVRRenderModelError.None)
393 var diffuseTexture = MarshalRenderModel_TextureMap(pDiffuseTexture);
394 var texture =
new Texture2D(diffuseTexture.unWidth, diffuseTexture.unHeight, TextureFormat.RGBA32,
false);
395 if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.Direct3D11)
401 error = renderModels.LoadIntoTextureD3D11_Async(renderModel.diffuseTextureId, texture.GetNativeTexturePtr());
402 if (error != EVRRenderModelError.Loading)
410 var textureMapData =
new byte[diffuseTexture.unWidth * diffuseTexture.unHeight * 4];
411 Marshal.Copy(diffuseTexture.rubTextureMapData, textureMapData, 0, textureMapData.Length);
413 var colors =
new Color32[diffuseTexture.unWidth * diffuseTexture.unHeight];
415 for (
int iHeight = 0; iHeight < diffuseTexture.unHeight; iHeight++)
417 for (
int iWidth = 0; iWidth < diffuseTexture.unWidth; iWidth++)
419 var r = textureMapData[iColor++];
420 var g = textureMapData[iColor++];
421 var b = textureMapData[iColor++];
422 var a = textureMapData[iColor++];
423 colors[iHeight * diffuseTexture.unWidth + iWidth] =
new Color32(r, g, b, a);
427 texture.SetPixels32(colors);
431 material =
new Material(shader != null ? shader : Shader.Find(
"Standard"));
432 material.mainTexture = texture;
435 materials[renderModel.diffuseTextureId] = material;
437 renderModels.FreeTexture(pDiffuseTexture);
441 Debug.Log(
"Failed to load render model texture for render model " + renderModelName);
448 if (!Application.isPlaying)
449 renderModels.FreeRenderModel(pRenderModel);
452 StartCoroutine(FreeRenderModel(pRenderModel));
454 return new RenderModel(mesh, material);
457 IEnumerator FreeRenderModel(System.IntPtr pRenderModel)
459 yield
return new WaitForSeconds(1.0f);
461 using (var holder =
new RenderModelInterfaceHolder())
463 var renderModels = holder.instance;
464 renderModels.FreeRenderModel(pRenderModel);
468 public Transform FindComponent(
string componentName)
471 for (
int i = 0; i < t.childCount; i++)
473 var child = t.GetChild(i);
474 if (child.name == componentName)
480 private void StripMesh(GameObject go)
482 var meshRenderer = go.GetComponent<MeshRenderer>();
483 if (meshRenderer != null)
484 DestroyImmediate(meshRenderer);
486 var meshFilter = go.GetComponent<MeshFilter>();
487 if (meshFilter != null)
488 DestroyImmediate(meshFilter);
491 private bool LoadComponents(RenderModelInterfaceHolder holder,
string renderModelName)
496 for (
int i = 0; i < t.childCount; i++)
498 var child = t.GetChild(i);
499 child.gameObject.SetActive(
false);
500 StripMesh(child.gameObject);
504 if (
string.IsNullOrEmpty(renderModelName))
507 var renderModels = holder.instance;
508 if (renderModels == null)
511 var count = renderModels.GetComponentCount(renderModelName);
515 for (
int i = 0; i < count; i++)
517 var capacity = renderModels.GetComponentName(renderModelName, (uint)i, null, 0);
521 var componentName =
new System.Text.StringBuilder((int)capacity);
522 if (renderModels.GetComponentName(renderModelName, (uint)i, componentName, capacity) == 0)
526 t = FindComponent(componentName.ToString());
529 t.gameObject.SetActive(
true);
533 t =
new GameObject(componentName.ToString()).transform;
534 t.parent = transform;
535 t.gameObject.layer = gameObject.layer;
538 var attach =
new GameObject(k_localTransformName).transform;
540 attach.localPosition = Vector3.zero;
541 attach.localRotation = Quaternion.identity;
542 attach.localScale = Vector3.one;
543 attach.gameObject.layer = gameObject.layer;
547 t.localPosition = Vector3.zero;
548 t.localRotation = Quaternion.identity;
549 t.localScale = Vector3.one;
551 capacity = renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), null, 0);
555 var componentRenderModelName =
new System.Text.StringBuilder((int)capacity);
556 if (renderModels.GetComponentRenderModelName(renderModelName, componentName.ToString(), componentRenderModelName, capacity) == 0)
560 var model = models[componentRenderModelName] as RenderModel;
561 if (model == null || model.mesh == null)
564 Debug.Log(
"Loading render model " + componentRenderModelName);
566 model = LoadRenderModel(renderModels, componentRenderModelName.ToString(), renderModelName);
570 models[componentRenderModelName] = model;
573 t.gameObject.AddComponent<MeshFilter>().mesh = model.mesh;
574 t.gameObject.AddComponent<MeshRenderer>().sharedMaterial = model.material;
580 SteamVR_Events.Action deviceConnectedAction, hideRenderModelsAction, modelSkinSettingsHaveChangedAction;
584 deviceConnectedAction = SteamVR_Events.DeviceConnectedAction(OnDeviceConnected);
585 hideRenderModelsAction = SteamVR_Events.HideRenderModelsAction(OnHideRenderModels);
586 modelSkinSettingsHaveChangedAction = SteamVR_Events.SystemAction(EVREventType.VREvent_ModelSkinSettingsHaveChanged, OnModelSkinSettingsHaveChanged);
592 if (!Application.isPlaying)
595 if (!
string.IsNullOrEmpty(modelOverride))
597 Debug.Log(modelOverrideWarning);
602 var system = OpenVR.System;
603 if (system != null && system.IsTrackedDeviceConnected((uint)index))
608 deviceConnectedAction.enabled =
true;
609 hideRenderModelsAction.enabled =
true;
610 modelSkinSettingsHaveChangedAction.enabled =
true;
616 if (!Application.isPlaying)
619 deviceConnectedAction.enabled =
false;
620 hideRenderModelsAction.enabled =
false;
621 modelSkinSettingsHaveChangedAction.enabled =
false;
630 if (!Application.isPlaying)
633 var fields = GetType().GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
635 bool modified =
false;
643 foreach (var f
in fields)
645 if (!values.Contains(f))
652 var v1 = f.GetValue(
this);
671 if (renderModelName != modelOverride)
673 renderModelName = modelOverride;
674 SetModel(modelOverride);
677 values =
new Hashtable();
678 foreach (var f
in fields)
679 values[f] = f.GetValue(
this);
686 if (updateDynamically)
687 UpdateComponents(
OpenVR.RenderModels);
690 Dictionary<int, string> nameCache;
694 if (renderModels == null)
698 if (t.childCount == 0)
701 var controllerState = (index != SteamVR_TrackedObject.EIndex.None) ?
704 if (nameCache == null)
705 nameCache =
new Dictionary<int, string>();
707 for (
int i = 0; i < t.childCount; i++)
709 var child = t.GetChild(i);
713 if (!nameCache.TryGetValue(child.GetInstanceID(), out name))
716 nameCache.Add(child.GetInstanceID(), name);
720 if (!renderModels.GetComponentState(renderModelName, name, ref controllerState, ref controllerModeState, ref componentState))
724 child.localPosition = componentTransform.pos;
725 child.localRotation = componentTransform.rot;
727 var attach = child.Find(k_localTransformName);
731 attach.position = t.TransformPoint(attachTransform.pos);
732 attach.rotation = t.rotation * attachTransform.rot;
735 bool visible = (componentState.uProperties & (uint)EVRComponentProperty.IsVisible) != 0;
736 if (visible != child.gameObject.activeSelf)
738 child.gameObject.SetActive(visible);
743 public void SetDeviceIndex(
int index)
745 this.index = (SteamVR_TrackedObject.EIndex)index;
754 private static void Sleep()
757 System.Threading.Thread.Sleep(1);
767 private RenderModel_t MarshalRenderModel(System.IntPtr pRenderModel)
769 if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
770 (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
774 packedModel.Unpack(ref model);
791 if ((System.Environment.OSVersion.Platform == System.PlatformID.MacOSX) ||
792 (System.Environment.OSVersion.Platform == System.PlatformID.Unix))
796 packedModel.Unpack(ref model);