You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
891 lines
39 KiB
891 lines
39 KiB
//========= Copyright 2016-2020, HTC Corporation. All rights reserved. ===========
|
|
|
|
#pragma warning disable 0649
|
|
using HTC.UnityPlugin.Utility;
|
|
using HTC.UnityPlugin.VRModuleManagement;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Runtime.InteropServices;
|
|
using UnityEngine;
|
|
#if VIU_OCULUSVR_AVATAR
|
|
using Oculus.Avatar;
|
|
#endif
|
|
|
|
namespace HTC.UnityPlugin.Vive.OculusVRExtension
|
|
{
|
|
// Only works in playing mode
|
|
public class VIUOculusVRRenderModel : MonoBehaviour
|
|
{
|
|
private struct ChildTransforms
|
|
{
|
|
public Transform root;
|
|
public Transform attach;
|
|
}
|
|
|
|
// Name of the sub-object which represents the "local" coordinate space for each component.
|
|
public const string LOCAL_TRANSFORM_NAME = "attach";
|
|
|
|
public const string MODEL_OVERRIDE_WARNNING = "Model override is really only meant to be used in " +
|
|
"the scene view for lining things up. Use tracked device " +
|
|
"index instead to ensure the correct model is displayed for all users.";
|
|
|
|
private const uint LEFT_INDEX = 1;
|
|
private const uint RIGHT_INDEX = 2;
|
|
|
|
[Tooltip(MODEL_OVERRIDE_WARNNING)]
|
|
[SerializeField]
|
|
private string m_modelOverride;
|
|
|
|
[Tooltip("Shader to apply to model.")]
|
|
[SerializeField]
|
|
private Shader m_shaderOverride;
|
|
|
|
[Tooltip("Update transforms of components at runtime to reflect user action.")]
|
|
[SerializeField]
|
|
private bool m_updateDynamically = true;
|
|
|
|
private uint m_deviceIndex = VRModule.INVALID_DEVICE_INDEX;
|
|
private MeshFilter m_meshFilter;
|
|
private MeshRenderer m_meshRenderer;
|
|
private IndexedTable<string, ChildTransforms> m_chilTransforms = new IndexedTable<string, ChildTransforms>();
|
|
private IndexedTable<int, Material> m_materials = new IndexedTable<int, Material>();
|
|
private HashSet<string> m_loadingRenderModels = new HashSet<string>();
|
|
private bool m_isAppQuit;
|
|
|
|
#if (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER || VIU_OCULUSVR_1_37_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
private IntPtr sdkAvatar = IntPtr.Zero;
|
|
private HashSet<UInt64> assetLoadingIds = new HashSet<UInt64>();
|
|
private Dictionary<string, OvrAvatarComponent> trackedComponents =
|
|
new Dictionary<string, OvrAvatarComponent>();
|
|
private OvrAvatarTouchController ovrController;
|
|
private int renderPartCount = 0;
|
|
private Shader SurfaceShader;
|
|
private Shader SurfaceShaderSelfOccluding;
|
|
private List<OvrAvatarRenderComponent> RenderParts = new List<OvrAvatarRenderComponent>();
|
|
|
|
private ovrAvatarHandInputState inputStateLeft;
|
|
private ovrAvatarHandInputState inputStateRight;
|
|
private bool firstSkinnedUpdate = true;
|
|
private bool assetsFinishedLoading = false;
|
|
private bool isMaterialInitilized = false;
|
|
private bool isMeshInitilized = false;
|
|
private ovrAvatarControllerType m_controllerType = ovrAvatarControllerType.Quest;
|
|
#endif
|
|
|
|
private string preferedModelName
|
|
{
|
|
get
|
|
{
|
|
if (!string.IsNullOrEmpty(m_modelOverride)) { return m_modelOverride; }
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
return VRModule.GetCurrentDeviceState(m_deviceIndex).renderModelName;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Shader preferedShader { get { return m_shaderOverride == null ? Shader.Find("Standard") : m_shaderOverride; } }
|
|
|
|
public bool updateDynamically { get { return m_updateDynamically; } set { m_updateDynamically = value; } }
|
|
public bool isLoadingModel { get { return m_loadingRenderModels.Count > 0; } }
|
|
public string loadedModelName { get; private set; }
|
|
public bool isModelLoaded { get { return !string.IsNullOrEmpty(loadedModelName); } }
|
|
public Shader loadedShader { get; private set; }
|
|
|
|
public string modelOverride
|
|
{
|
|
get
|
|
{
|
|
return m_modelOverride;
|
|
}
|
|
set
|
|
{
|
|
m_modelOverride = value;
|
|
LoadPreferedModel();
|
|
}
|
|
}
|
|
|
|
public Shader shaderOverride
|
|
{
|
|
get
|
|
{
|
|
return m_shaderOverride;
|
|
}
|
|
set
|
|
{
|
|
m_shaderOverride = value;
|
|
SetPreferedShader();
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
private void OnValidate()
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
UnityEditor.EditorApplication.delayCall += () =>
|
|
{
|
|
if (!m_isAppQuit && this != null && isActiveAndEnabled)
|
|
{
|
|
LoadPreferedModel();
|
|
SetPreferedShader();
|
|
}
|
|
};
|
|
}
|
|
}
|
|
#endif
|
|
|
|
private void Update()
|
|
{
|
|
if (m_updateDynamically)
|
|
{
|
|
#if (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER || VIU_OCULUSVR_1_37_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
if (sdkAvatar == IntPtr.Zero)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (m_deviceIndex == LEFT_INDEX)
|
|
{
|
|
inputStateLeft.transform.position = transform.position;
|
|
inputStateLeft.transform.orientation = transform.rotation;
|
|
inputStateLeft.transform.scale = transform.localScale;
|
|
|
|
inputStateLeft.buttonMask = 0;
|
|
inputStateLeft.touchMask = ovrAvatarTouch.Pointing | ovrAvatarTouch.ThumbUp;
|
|
|
|
if (ViveInput.GetPress(HandRole.LeftHand, ControllerButton.AKey))
|
|
{
|
|
inputStateLeft.buttonMask |= ovrAvatarButton.One;
|
|
}
|
|
|
|
if (ViveInput.GetPress(HandRole.LeftHand, ControllerButton.BKey))
|
|
{
|
|
inputStateLeft.buttonMask |= ovrAvatarButton.Two;
|
|
}
|
|
|
|
if (ViveInput.GetPress(HandRole.LeftHand, ControllerButton.System))
|
|
{
|
|
inputStateLeft.buttonMask |= ovrAvatarButton.Three;
|
|
}
|
|
|
|
if (ViveInput.GetPress(HandRole.LeftHand, ControllerButton.Pad))
|
|
{
|
|
inputStateLeft.buttonMask |= ovrAvatarButton.Joystick;
|
|
}
|
|
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.AKeyTouch))
|
|
{
|
|
inputStateLeft.touchMask &= ~ovrAvatarTouch.ThumbUp;
|
|
inputStateLeft.touchMask |= ovrAvatarTouch.One;
|
|
}
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.BkeyTouch))
|
|
{
|
|
inputStateLeft.touchMask &= ~ovrAvatarTouch.ThumbUp;
|
|
inputStateLeft.touchMask |= ovrAvatarTouch.Two;
|
|
}
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.PadTouch))
|
|
{
|
|
inputStateLeft.touchMask &= ~ovrAvatarTouch.ThumbUp;
|
|
inputStateLeft.touchMask |= ovrAvatarTouch.Joystick;
|
|
}
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.TriggerTouch))
|
|
{
|
|
inputStateLeft.touchMask &= ~ovrAvatarTouch.Pointing;
|
|
inputStateLeft.touchMask |= ovrAvatarTouch.Index;
|
|
}
|
|
|
|
inputStateLeft.joystickX = ViveInput.GetAxis(HandRole.LeftHand, ControllerAxis.JoystickX);
|
|
inputStateLeft.joystickY = ViveInput.GetAxis(HandRole.LeftHand, ControllerAxis.JoystickY);
|
|
inputStateLeft.indexTrigger = ViveInput.GetAxis(HandRole.LeftHand, ControllerAxis.Trigger);
|
|
inputStateLeft.handTrigger = ViveInput.GetAxis(HandRole.LeftHand, ControllerAxis.CapSenseGrip);
|
|
inputStateLeft.isActive = true;
|
|
}
|
|
else if (m_deviceIndex == RIGHT_INDEX)
|
|
{
|
|
inputStateRight.transform.position = transform.position;
|
|
inputStateRight.transform.orientation = transform.rotation;
|
|
inputStateRight.transform.scale = transform.localScale;
|
|
|
|
inputStateRight.buttonMask = 0;
|
|
inputStateRight.touchMask = ovrAvatarTouch.Pointing | ovrAvatarTouch.ThumbUp;
|
|
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.AKey))
|
|
{
|
|
inputStateRight.buttonMask |= ovrAvatarButton.One;
|
|
}
|
|
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.BKey))
|
|
{
|
|
inputStateRight.buttonMask |= ovrAvatarButton.Two;
|
|
}
|
|
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.Pad))
|
|
{
|
|
inputStateRight.buttonMask |= ovrAvatarButton.Joystick;
|
|
}
|
|
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.AKeyTouch))
|
|
{
|
|
inputStateRight.touchMask &= ~ovrAvatarTouch.ThumbUp;
|
|
inputStateRight.touchMask |= ovrAvatarTouch.One;
|
|
}
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.BkeyTouch))
|
|
{
|
|
inputStateRight.touchMask &= ~ovrAvatarTouch.ThumbUp;
|
|
inputStateRight.touchMask |= ovrAvatarTouch.Two;
|
|
}
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.PadTouch))
|
|
{
|
|
inputStateRight.touchMask &= ~ovrAvatarTouch.ThumbUp;
|
|
inputStateRight.touchMask |= ovrAvatarTouch.Joystick;
|
|
}
|
|
if (ViveInput.GetPress(HandRole.RightHand, ControllerButton.TriggerTouch))
|
|
{
|
|
inputStateRight.touchMask &= ~ovrAvatarTouch.Pointing;
|
|
inputStateRight.touchMask |= ovrAvatarTouch.Index;
|
|
}
|
|
|
|
inputStateRight.joystickX = ViveInput.GetAxis(HandRole.RightHand, ControllerAxis.JoystickX);
|
|
inputStateRight.joystickY = ViveInput.GetAxis(HandRole.RightHand, ControllerAxis.JoystickY);
|
|
inputStateRight.indexTrigger = ViveInput.GetAxis(HandRole.RightHand, ControllerAxis.Trigger);
|
|
inputStateRight.handTrigger = ViveInput.GetAxis(HandRole.RightHand, ControllerAxis.CapSenseGrip);
|
|
inputStateRight.isActive = true;
|
|
}
|
|
|
|
CAPI.ovrAvatarPose_UpdateHandsWithType(sdkAvatar, inputStateLeft, inputStateRight, m_controllerType);
|
|
CAPI.ovrAvatarPose_Finalize(sdkAvatar, Time.deltaTime);
|
|
#endif
|
|
|
|
UpdateComponents();
|
|
|
|
#if VIU_OCULUSVR_1_37_0_OR_NEWER && VIU_OCULUSVR_AVATAR
|
|
if (m_deviceIndex == LEFT_INDEX)
|
|
{
|
|
ovrAvatarControllerComponent component = new ovrAvatarControllerComponent();
|
|
if (CAPI.ovrAvatarPose_GetLeftControllerComponent(sdkAvatar, ref component))
|
|
{
|
|
UpdateAvatarComponent(component.renderComponent);
|
|
}
|
|
}
|
|
else if (m_deviceIndex == RIGHT_INDEX)
|
|
{
|
|
ovrAvatarControllerComponent component = new ovrAvatarControllerComponent();
|
|
if (CAPI.ovrAvatarPose_GetRightControllerComponent(sdkAvatar, ref component))
|
|
{
|
|
UpdateAvatarComponent(component.renderComponent);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
LoadPreferedModel();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
ClearModel();
|
|
}
|
|
|
|
private void OnApplicationQuit()
|
|
{
|
|
m_isAppQuit = true;
|
|
}
|
|
|
|
public void ClearModel()
|
|
{
|
|
if (!isModelLoaded) { return; }
|
|
|
|
if (m_meshRenderer != null) { Destroy(m_meshRenderer); }
|
|
if (m_meshFilter != null) { Destroy(m_meshFilter); }
|
|
|
|
for (int i = 0, imax = m_chilTransforms.Count; i < imax; ++i)
|
|
{
|
|
var c = m_chilTransforms.GetValueByIndex(i);
|
|
if (c.root == null) { continue; }
|
|
Destroy(c.root.gameObject);
|
|
}
|
|
|
|
m_chilTransforms.Clear();
|
|
m_materials.Clear();
|
|
loadedModelName = string.Empty;
|
|
loadedShader = null;
|
|
}
|
|
|
|
private void SetPreferedShader()
|
|
{
|
|
SetShader(preferedShader);
|
|
}
|
|
|
|
private void SetShader(Shader newShader)
|
|
{
|
|
if (loadedShader == newShader) { return; }
|
|
|
|
loadedShader = newShader;
|
|
|
|
if (m_materials == null) { return; }
|
|
|
|
for (int i = 0, imax = m_materials.Count; i < imax; ++i)
|
|
{
|
|
var mat = m_materials.GetValueByIndex(i);
|
|
if (mat != null)
|
|
{
|
|
mat.shader = newShader;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void LoadPreferedModel()
|
|
{
|
|
LoadModel(preferedModelName);
|
|
}
|
|
|
|
private void LoadModel(string renderModelName)
|
|
{
|
|
//Debug.Log(transform.parent.parent.name + " Try LoadModel " + renderModelName);
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
Debug.LogWarning("LoadModel failed! This function only works in playing mode");
|
|
return;
|
|
}
|
|
#endif
|
|
if (string.IsNullOrEmpty(loadedModelName) && string.IsNullOrEmpty(renderModelName)) { return; }
|
|
|
|
if (loadedModelName == renderModelName) { return; }
|
|
|
|
if (m_loadingRenderModels.Contains(renderModelName)) { return; }
|
|
|
|
ClearModel();
|
|
|
|
if (!m_isAppQuit && !string.IsNullOrEmpty(renderModelName))
|
|
{
|
|
//Debug.Log(transform.parent.parent.name + " LoadModel " + renderModelName);
|
|
m_loadingRenderModels.Add(renderModelName);
|
|
#if VIU_OCULUSVR_1_37_0_OR_NEWER && VIU_OCULUSVR_AVATAR
|
|
OvrAvatarSDKManager.AvatarSpecRequestParams avatarSpecRequest = new OvrAvatarSDKManager.AvatarSpecRequestParams(
|
|
0,
|
|
this.AvatarSpecificationCallback,
|
|
false,
|
|
ovrAvatarAssetLevelOfDetail.Highest,
|
|
false,
|
|
ovrAvatarLookAndFeelVersion.Two,
|
|
ovrAvatarLookAndFeelVersion.One,
|
|
false);
|
|
|
|
OvrAvatarSDKManager.Instance.RequestAvatarSpecification(avatarSpecRequest);
|
|
#elif VIU_OCULUSVR_1_36_0_OR_NEWER && VIU_OCULUSVR_AVATAR
|
|
OvrAvatarSDKManager.Instance.RequestAvatarSpecification(
|
|
0,
|
|
this.AvatarSpecificationCallback,
|
|
false,
|
|
ovrAvatarAssetLevelOfDetail.Highest,
|
|
false,
|
|
ovrAvatarLookAndFeelVersion.Two,
|
|
ovrAvatarLookAndFeelVersion.One,
|
|
false);
|
|
#elif VIU_OCULUSVR_1_32_0_OR_NEWER && VIU_OCULUSVR_AVATAR
|
|
OvrAvatarSDKManager.Instance.RequestAvatarSpecification(
|
|
0,
|
|
this.AvatarSpecificationCallback,
|
|
false,
|
|
ovrAvatarAssetLevelOfDetail.Highest,
|
|
false);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
private void AvatarSpecificationCallback(IntPtr avatarSpecification)
|
|
{
|
|
#if (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER || VIU_OCULUSVR_1_37_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
sdkAvatar = CAPI.ovrAvatar_Create(avatarSpecification, ovrAvatarCapabilities.All);
|
|
CAPI.ovrAvatar_SetLeftControllerVisibility(sdkAvatar, true);
|
|
CAPI.ovrAvatar_SetRightControllerVisibility(sdkAvatar, true);
|
|
|
|
//Fetch all the assets that this avatar uses.
|
|
UInt32 assetCount = CAPI.ovrAvatar_GetReferencedAssetCount(sdkAvatar);
|
|
for (UInt32 i = 0; i < assetCount; ++i)
|
|
{
|
|
UInt64 id = CAPI.ovrAvatar_GetReferencedAsset(sdkAvatar, i);
|
|
if (OvrAvatarSDKManager.Instance.GetAsset(id) == null)
|
|
{
|
|
OvrAvatarSDKManager.Instance.BeginLoadingAsset(
|
|
id,
|
|
ovrAvatarAssetLevelOfDetail.Highest,
|
|
AssetLoadedCallback);
|
|
|
|
assetLoadingIds.Add(id);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER || VIU_OCULUSVR_1_37_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
private void AssetLoadedCallback(OvrAvatarAsset asset)
|
|
{
|
|
assetLoadingIds.Remove(asset.assetID);
|
|
}
|
|
#endif
|
|
|
|
private void OnLoadModelComplete(string renderModelName)
|
|
{
|
|
m_loadingRenderModels.Remove(renderModelName);
|
|
|
|
if (loadedModelName == renderModelName) { return; }
|
|
if (preferedModelName != renderModelName) { return; }
|
|
if (!isActiveAndEnabled) { return; }
|
|
//Debug.Log(transform.parent.parent.name + " OnLoadModelComplete " + renderModelName);
|
|
ClearModel();
|
|
|
|
loadedModelName = renderModelName;
|
|
}
|
|
|
|
private void UpdateComponents()
|
|
{
|
|
#if (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER || VIU_OCULUSVR_1_37_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
if (assetLoadingIds.Count == 0)
|
|
{
|
|
if (!assetsFinishedLoading)
|
|
{
|
|
UpdateSDKAvatarUnityState();
|
|
assetsFinishedLoading = true;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER || VIU_OCULUSVR_1_37_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
private void UpdateSDKAvatarUnityState()
|
|
{
|
|
#if VIU_OCULUSVR_1_37_0_OR_NEWER && VIU_OCULUSVR_AVATAR
|
|
ovrAvatarControllerComponent controllerComponent = new ovrAvatarControllerComponent();
|
|
ovrAvatarComponent dummyComponent = new ovrAvatarComponent();
|
|
OvrAvatarTouchController controller = null;
|
|
|
|
if (m_deviceIndex == LEFT_INDEX)
|
|
{
|
|
if (CAPI.ovrAvatarPose_GetLeftControllerComponent(sdkAvatar, ref controllerComponent))
|
|
{
|
|
CAPI.ovrAvatarComponent_Get(controllerComponent.renderComponent, true, ref dummyComponent);
|
|
AddAvatarComponent(ref controller, dummyComponent);
|
|
controller.isLeftHand = true;
|
|
}
|
|
}
|
|
else if (m_deviceIndex == RIGHT_INDEX)
|
|
{
|
|
if (CAPI.ovrAvatarPose_GetRightControllerComponent(sdkAvatar, ref controllerComponent))
|
|
{
|
|
CAPI.ovrAvatarComponent_Get(controllerComponent.renderComponent, true, ref dummyComponent);
|
|
AddAvatarComponent(ref controller, dummyComponent);
|
|
controller.isLeftHand = false;
|
|
}
|
|
}
|
|
#elif (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
//Iterate through all the render components
|
|
UInt32 componentCount = CAPI.ovrAvatarComponent_Count(sdkAvatar);
|
|
|
|
for (UInt32 i = 0; i < componentCount; i++)
|
|
{
|
|
IntPtr ptr = CAPI.ovrAvatarComponent_Get_Native(sdkAvatar, i);
|
|
|
|
ovrAvatarComponent component = (ovrAvatarComponent)Marshal.PtrToStructure(ptr, typeof(ovrAvatarComponent));
|
|
|
|
if (!trackedComponents.ContainsKey(component.name))
|
|
{
|
|
GameObject componentObject = null;
|
|
Type specificType = null;
|
|
|
|
|
|
if (specificType == null && (ovrAvatarCapabilities.All & ovrAvatarCapabilities.Hands) != 0)
|
|
{
|
|
if (m_deviceIndex == LEFT_INDEX)
|
|
{
|
|
ovrAvatarControllerComponent? controllerComponent = CAPI.ovrAvatarPose_GetLeftControllerComponent(sdkAvatar);
|
|
if (specificType == null && controllerComponent.HasValue && ptr == controllerComponent.Value.renderComponent)
|
|
{
|
|
specificType = typeof(OvrAvatarTouchController);
|
|
if (ovrController != null)
|
|
{
|
|
componentObject = ovrController.gameObject;
|
|
}
|
|
}
|
|
}
|
|
else if (m_deviceIndex == RIGHT_INDEX)
|
|
{
|
|
ovrAvatarControllerComponent? controllerComponent = CAPI.ovrAvatarPose_GetRightControllerComponent(sdkAvatar);
|
|
if (specificType == null && controllerComponent.HasValue && ptr == controllerComponent.Value.renderComponent)
|
|
{
|
|
specificType = typeof(OvrAvatarTouchController);
|
|
if (ovrController != null)
|
|
{
|
|
componentObject = ovrController.gameObject;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (componentObject != null)
|
|
{
|
|
AddAvatarComponent(componentObject, component);
|
|
}
|
|
}
|
|
|
|
UpdateAvatarComponent(component);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if VIU_OCULUSVR_1_37_0_OR_NEWER && VIU_OCULUSVR_AVATAR
|
|
private void AddAvatarComponent<T>(ref T root, ovrAvatarComponent nativeComponent) where T : OvrAvatarComponent
|
|
{
|
|
GameObject componentObject = new GameObject();
|
|
componentObject.name = nativeComponent.name;
|
|
componentObject.transform.SetParent(transform);
|
|
root = componentObject.AddComponent<T>();
|
|
AddRenderParts(root, nativeComponent, componentObject.transform);
|
|
}
|
|
#elif VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER
|
|
private void AddAvatarComponent(GameObject componentObject, ovrAvatarComponent component)
|
|
{
|
|
OvrAvatarComponent ovrComponent = componentObject.AddComponent<OvrAvatarComponent>();
|
|
trackedComponents.Add(component.name, ovrComponent);
|
|
|
|
AddRenderParts(ovrComponent, component, componentObject.transform);
|
|
}
|
|
#endif
|
|
|
|
private void AddRenderParts(
|
|
OvrAvatarComponent ovrComponent,
|
|
ovrAvatarComponent component,
|
|
Transform parent)
|
|
{
|
|
for (UInt32 renderPartIndex = 0; renderPartIndex < component.renderPartCount; renderPartIndex++)
|
|
{
|
|
GameObject renderPartObject = new GameObject();
|
|
renderPartObject.name = GetRenderPartName(component, renderPartIndex);
|
|
|
|
renderPartObject.transform.SetParent(parent);
|
|
renderPartObject.transform.localPosition = Vector2.zero;
|
|
renderPartObject.transform.localRotation = Quaternion.identity;
|
|
|
|
IntPtr renderPart = GetRenderPart(component, renderPartIndex);
|
|
ovrAvatarRenderPartType type = CAPI.ovrAvatarRenderPart_GetType(renderPart);
|
|
OvrAvatarRenderComponent ovrRenderPart = null;
|
|
switch (type)
|
|
{
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS:
|
|
ovrRenderPart = AddSkinnedMeshRenderPBSComponent(renderPartObject, CAPI.ovrAvatarRenderPart_GetSkinnedMeshRenderPBS(renderPart));
|
|
break;
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2:
|
|
ovrRenderPart = AddSkinnedMeshRenderPBSV2Component(renderPartObject, CAPI.ovrAvatarRenderPart_GetSkinnedMeshRenderPBSV2(renderPart));
|
|
break;
|
|
default:
|
|
break;// throw new NotImplementedException(string.Format("Unsupported render part type: {0}", type.ToString()));
|
|
}
|
|
|
|
if (ovrRenderPart != null)
|
|
{
|
|
ovrComponent.RenderParts.Add(ovrRenderPart);
|
|
RenderParts.Add(ovrRenderPart);
|
|
}
|
|
}
|
|
}
|
|
|
|
private OvrAvatarSkinnedMeshRenderPBSComponent AddSkinnedMeshRenderPBSComponent(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRenderPBS skinnedMeshRenderPBS)
|
|
{
|
|
OvrAvatarSkinnedMeshRenderPBSComponent skinnedMeshRenderer = gameObject.AddComponent<OvrAvatarSkinnedMeshRenderPBSComponent>();
|
|
OvrAvatarAssetMesh meshAsset = (OvrAvatarAssetMesh)OvrAvatarSDKManager.Instance.GetAsset(skinnedMeshRenderPBS.meshAssetID);
|
|
SkinnedMeshRenderer renderer = meshAsset.CreateSkinnedMeshRendererOnObject(gameObject);
|
|
|
|
#if UNITY_ANDROID
|
|
renderer.quality = SkinQuality.Bone2;
|
|
#else
|
|
renderer.quality = SkinQuality.Bone4;
|
|
#endif
|
|
renderer.updateWhenOffscreen = true;
|
|
skinnedMeshRenderer.mesh = renderer;
|
|
transform.GetChild(0).localPosition = Vector2.zero;
|
|
transform.GetChild(0).localRotation = Quaternion.identity;
|
|
transform.GetChild(0).GetComponentInChildren<OvrAvatarSkinnedMeshRenderPBSComponent>().gameObject.SetActive(false);
|
|
var shader = Shader.Find("OvrAvatar/AvatarSurfaceShaderPBS");
|
|
renderer.sharedMaterial = CreateAvatarMaterial(gameObject.name + "_material", shader);
|
|
SetMaterialOpaque(renderer.sharedMaterial);
|
|
skinnedMeshRenderer.bones = renderer.bones;
|
|
|
|
return skinnedMeshRenderer;
|
|
}
|
|
|
|
private OvrAvatarSkinnedMeshPBSV2RenderComponent AddSkinnedMeshRenderPBSV2Component(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRenderPBS_V2 skinnedMeshRenderPBSV2)
|
|
{
|
|
OvrAvatarSkinnedMeshPBSV2RenderComponent skinnedMeshRenderer = gameObject.AddComponent<OvrAvatarSkinnedMeshPBSV2RenderComponent>();
|
|
OvrAvatarAssetMesh meshAsset = (OvrAvatarAssetMesh)OvrAvatarSDKManager.Instance.GetAsset(skinnedMeshRenderPBSV2.meshAssetID);
|
|
SkinnedMeshRenderer renderer = meshAsset.CreateSkinnedMeshRendererOnObject(gameObject);
|
|
|
|
#if UNITY_ANDROID
|
|
renderer.quality = SkinQuality.Bone2;
|
|
#else
|
|
renderer.quality = SkinQuality.Bone4;
|
|
#endif
|
|
renderer.updateWhenOffscreen = true;
|
|
skinnedMeshRenderer.mesh = renderer;
|
|
transform.GetChild(0).localPosition = Vector2.zero;
|
|
transform.GetChild(0).localRotation = Quaternion.identity;
|
|
transform.GetChild(0).GetComponentInChildren<OvrAvatarSkinnedMeshPBSV2RenderComponent>().gameObject.SetActive(false);
|
|
var shader = Shader.Find("OvrAvatar/AvatarPBRV2Simple");
|
|
renderer.sharedMaterial = CreateAvatarMaterial(gameObject.name + "_material", shader);
|
|
SetMaterialOpaque(renderer.sharedMaterial);
|
|
skinnedMeshRenderer.bones = renderer.bones;
|
|
|
|
return skinnedMeshRenderer;
|
|
}
|
|
|
|
private Material CreateAvatarMaterial(string name, Shader shader)
|
|
{
|
|
if (shader == null)
|
|
{
|
|
throw new Exception("No shader provided for avatar material.");
|
|
}
|
|
Material mat = new Material(shader);
|
|
mat.name = name;
|
|
return mat;
|
|
}
|
|
|
|
private void SetMaterialOpaque(Material mat)
|
|
{
|
|
// Initialize shader to use geometry render queue with no blending
|
|
mat.SetOverrideTag("Queue", "Geometry");
|
|
mat.SetOverrideTag("RenderType", "Opaque");
|
|
mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
|
|
mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
|
|
mat.DisableKeyword("_ALPHATEST_ON");
|
|
mat.DisableKeyword("_ALPHABLEND_ON");
|
|
mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
|
|
mat.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
|
|
}
|
|
|
|
private static string GetRenderPartName(ovrAvatarComponent component, uint renderPartIndex)
|
|
{
|
|
return component.name + "_renderPart_" + (int)renderPartIndex;
|
|
}
|
|
|
|
static public IntPtr GetRenderPart(ovrAvatarComponent component, UInt32 renderPartIndex)
|
|
{
|
|
long offset = Marshal.SizeOf(typeof(IntPtr)) * renderPartIndex;
|
|
IntPtr marshalPtr = new IntPtr(component.renderParts.ToInt64() + offset);
|
|
return (IntPtr)Marshal.PtrToStructure(marshalPtr, typeof(IntPtr));
|
|
}
|
|
|
|
#if VIU_OCULUSVR_1_37_0_OR_NEWER
|
|
private void UpdateAvatarComponent(IntPtr nativeComponent)
|
|
{
|
|
ovrAvatarComponent nativeAvatarComponent = new ovrAvatarComponent();
|
|
CAPI.ovrAvatarComponent_Get(nativeComponent, false, ref nativeAvatarComponent);
|
|
ConvertTransform(nativeAvatarComponent.transform, transform);
|
|
for (UInt32 renderPartIndex = 0; renderPartIndex < nativeAvatarComponent.renderPartCount; renderPartIndex++)
|
|
{
|
|
if (RenderParts.Count <= renderPartIndex)
|
|
{
|
|
break;
|
|
}
|
|
|
|
OvrAvatarRenderComponent renderComponent = RenderParts[(int)renderPartIndex];
|
|
IntPtr renderPart = OvrAvatar.GetRenderPart(nativeAvatarComponent, renderPartIndex);
|
|
ovrAvatarRenderPartType type = CAPI.ovrAvatarRenderPart_GetType(renderPart);
|
|
ovrAvatarTransform localTransform;
|
|
ovrAvatarVisibilityFlags visibilityMask;
|
|
var mesh = renderComponent.mesh;
|
|
var bones = renderComponent.bones;
|
|
switch (type)
|
|
{
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS:
|
|
visibilityMask = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetVisibilityMask(renderPart);
|
|
localTransform = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetTransform(renderPart);
|
|
if ((visibilityMask & ovrAvatarVisibilityFlags.FirstPerson) != 0)
|
|
{
|
|
renderComponent.gameObject.SetActive(true);
|
|
mesh.enabled = true;
|
|
}
|
|
|
|
UpdateSkinnedMesh(localTransform, renderPart, bones);
|
|
|
|
UInt64 albedoTextureID = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetAlbedoTextureAssetID(renderPart);
|
|
UInt64 surfaceTextureID = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetSurfaceTextureAssetID(renderPart);
|
|
mesh.sharedMaterial.SetTexture("_Albedo", OvrAvatarComponent.GetLoadedTexture(albedoTextureID));
|
|
mesh.sharedMaterial.SetTexture("_Surface", OvrAvatarComponent.GetLoadedTexture(surfaceTextureID));
|
|
break;
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2:
|
|
visibilityMask = CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetVisibilityMask(renderPart);
|
|
localTransform = CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetTransform(renderPart);
|
|
if ((visibilityMask & ovrAvatarVisibilityFlags.FirstPerson) != 0)
|
|
{
|
|
renderComponent.gameObject.SetActive(true);
|
|
mesh.enabled = true;
|
|
}
|
|
|
|
UpdateSkinnedMesh(localTransform, renderPart, bones);
|
|
|
|
ovrAvatarPBSMaterialState materialState =
|
|
CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetPBSMaterialState(renderPart);
|
|
Texture2D diffuseTexture = OvrAvatarComponent.GetLoadedTexture(materialState.albedoTextureID);
|
|
Texture2D normalTexture = OvrAvatarComponent.GetLoadedTexture(materialState.normalTextureID);
|
|
Texture2D metallicTexture = OvrAvatarComponent.GetLoadedTexture(materialState.metallicnessTextureID);
|
|
mesh.materials[0].SetTexture("_MainTex", diffuseTexture);
|
|
mesh.materials[0].SetTexture("_NormalMap", normalTexture);
|
|
mesh.materials[0].SetTexture("_RoughnessMap", metallicTexture);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#elif VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER
|
|
private void UpdateAvatarComponent(ovrAvatarComponent component)
|
|
{
|
|
for (UInt32 renderPartIndex = 0; renderPartIndex < component.renderPartCount; renderPartIndex++)
|
|
{
|
|
if (RenderParts.Count <= renderPartIndex)
|
|
{
|
|
break;
|
|
}
|
|
|
|
OvrAvatarRenderComponent renderComponent = RenderParts[(int)renderPartIndex];
|
|
IntPtr renderPart = OvrAvatar.GetRenderPart(component, renderPartIndex);
|
|
ovrAvatarRenderPartType type = CAPI.ovrAvatarRenderPart_GetType(renderPart);
|
|
switch (type)
|
|
{
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS:
|
|
var mat = renderComponent.mesh.sharedMaterial;
|
|
var bones = renderComponent.bones;
|
|
ovrAvatarVisibilityFlags visibilityMask = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetVisibilityMask(renderPart);
|
|
ovrAvatarTransform localTransform = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetTransform(renderPart);
|
|
UpdateSkinnedMesh(localTransform, renderPart, bones);
|
|
|
|
UInt64 albedoTextureID = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetAlbedoTextureAssetID(renderPart);
|
|
UInt64 surfaceTextureID = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetSurfaceTextureAssetID(renderPart);
|
|
mat.SetTexture("_Albedo", OvrAvatarComponent.GetLoadedTexture(albedoTextureID));
|
|
mat.SetTexture("_Surface", OvrAvatarComponent.GetLoadedTexture(surfaceTextureID));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
private void UpdateSkinnedMesh(ovrAvatarTransform localTransform, IntPtr renderPart, Transform[] bones)
|
|
{
|
|
ConvertTransform(localTransform, transform);
|
|
ovrAvatarRenderPartType type = CAPI.ovrAvatarRenderPart_GetType(renderPart);
|
|
UInt64 dirtyJoints;
|
|
switch (type)
|
|
{
|
|
case ovrAvatarRenderPartType.SkinnedMeshRender:
|
|
dirtyJoints = CAPI.ovrAvatarSkinnedMeshRender_GetDirtyJoints(renderPart);
|
|
break;
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS:
|
|
dirtyJoints = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetDirtyJoints(renderPart);
|
|
break;
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2:
|
|
dirtyJoints = CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetDirtyJoints(renderPart);
|
|
break;
|
|
default:
|
|
throw new Exception("Unhandled render part type: " + type);
|
|
}
|
|
|
|
for (UInt32 i = 0; i < 64; i++)
|
|
{
|
|
UInt64 dirtyMask = (ulong)1 << (int)i;
|
|
// We need to make sure that we fully update the initial position of
|
|
// Skinned mesh renderers, then, thereafter, we can only update dirty joints
|
|
if ((firstSkinnedUpdate && i < bones.Length) ||
|
|
(dirtyMask & dirtyJoints) != 0)
|
|
{
|
|
//This joint is dirty and needs to be updated
|
|
Transform targetBone = bones[i];
|
|
ovrAvatarTransform transform;
|
|
switch (type)
|
|
{
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS:
|
|
transform = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetJointTransform(renderPart, i);
|
|
break;
|
|
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2:
|
|
transform = CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetJointTransform(renderPart, i);
|
|
break;
|
|
default:
|
|
throw new Exception("Unhandled render part type: " + type);
|
|
}
|
|
|
|
ConvertTransform(transform, targetBone);
|
|
}
|
|
}
|
|
firstSkinnedUpdate = false;
|
|
}
|
|
|
|
private void ConvertTransform(ovrAvatarTransform transform, Transform target)
|
|
{
|
|
Vector3 position = transform.position;
|
|
position.z = -position.z;
|
|
Quaternion orientation = transform.orientation;
|
|
orientation.x = -orientation.x;
|
|
orientation.y = -orientation.y;
|
|
target.localPosition = position;
|
|
target.localRotation = orientation;
|
|
target.localScale = transform.scale;
|
|
}
|
|
#endif
|
|
|
|
public void SetDeviceIndex(uint index)
|
|
{
|
|
//Debug.Log(transform.parent.parent.name + " SetDeviceIndex " + index);
|
|
m_deviceIndex = index;
|
|
#if (VIU_OCULUSVR_1_32_0_OR_NEWER || VIU_OCULUSVR_1_36_0_OR_NEWER) && VIU_OCULUSVR_AVATAR
|
|
ovrController = this.GetComponent<OvrAvatarTouchController>();
|
|
#endif
|
|
#if VIU_OCULUSVR && VIU_OCULUSVR_AVATAR
|
|
var headsetType = OVRPlugin.GetSystemHeadsetType();
|
|
switch (headsetType)
|
|
{
|
|
#if !VIU_OCULUSVR_19_0_OR_NEWER
|
|
case OVRPlugin.SystemHeadset.GearVR_R320:
|
|
case OVRPlugin.SystemHeadset.GearVR_R321:
|
|
case OVRPlugin.SystemHeadset.GearVR_R322:
|
|
case OVRPlugin.SystemHeadset.GearVR_R323:
|
|
case OVRPlugin.SystemHeadset.GearVR_R324:
|
|
case OVRPlugin.SystemHeadset.GearVR_R325:
|
|
m_controllerType = ovrAvatarControllerType.Malibu;
|
|
break;
|
|
case OVRPlugin.SystemHeadset.Oculus_Go:
|
|
m_controllerType = ovrAvatarControllerType.Go;
|
|
break;
|
|
#endif
|
|
#if VIU_OCULUSVR_16_0_OR_NEWER
|
|
case OVRPlugin.SystemHeadset.Oculus_Link_Quest:
|
|
#endif
|
|
case OVRPlugin.SystemHeadset.Oculus_Quest:
|
|
#if VIU_OCULUSVR_1_37_0_OR_NEWER
|
|
case OVRPlugin.SystemHeadset.Rift_S:
|
|
m_controllerType = ovrAvatarControllerType.Quest;
|
|
break;
|
|
#endif
|
|
case OVRPlugin.SystemHeadset.Rift_DK1:
|
|
case OVRPlugin.SystemHeadset.Rift_DK2:
|
|
case OVRPlugin.SystemHeadset.Rift_CV1:
|
|
default:
|
|
m_controllerType = ovrAvatarControllerType.Touch;
|
|
break;
|
|
}
|
|
#endif
|
|
LoadPreferedModel();
|
|
}
|
|
}
|
|
}
|