|
|
- using UnityEngine;
- using System.Collections;
- using System;
- using Oculus.Avatar;
- using System.Runtime.InteropServices;
- using System.Collections.Generic;
- #if UNITY_EDITOR
- using UnityEditor;
- #endif
-
- #if AVATAR_INTERNAL
- using UnityEngine.Events;
- #endif
-
- [System.Serializable]
- public class AvatarLayer
- {
- public int layerIndex;
- }
-
- #if UNITY_EDITOR
- [CustomPropertyDrawer(typeof(AvatarLayer))]
- public class AvatarLayerPropertyDrawer : PropertyDrawer
- {
- public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
- {
- EditorGUI.BeginProperty(position, GUIContent.none, property);
- SerializedProperty layerIndex = property.FindPropertyRelative("layerIndex");
- position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
- layerIndex.intValue = EditorGUI.LayerField(position, layerIndex.intValue);
- EditorGUI.EndProperty();
- }
- }
- #endif
-
- [System.Serializable]
- public class PacketRecordSettings
- {
- internal bool RecordingFrames = false;
- public float UpdateRate = 1f / 30f; // 30 hz update of packets
- internal float AccumulatedTime;
- };
-
- public class OvrAvatar : MonoBehaviour
- {
- [Header("Avatar")]
- public IntPtr sdkAvatar = IntPtr.Zero;
- public string oculusUserID;
- public OvrAvatarDriver Driver;
-
- [Header("Capabilities")]
- public bool EnableBody = true;
- public bool EnableHands = true;
- public bool EnableBase = true;
- public bool EnableExpressive = false;
-
- [Header("Network")]
- public bool RecordPackets;
- public bool UseSDKPackets = true;
- public PacketRecordSettings PacketSettings = new PacketRecordSettings();
-
- [Header("Visibility")]
- public bool StartWithControllers;
- public AvatarLayer FirstPersonLayer;
- public AvatarLayer ThirdPersonLayer;
- public bool ShowFirstPerson = true;
- public bool ShowThirdPerson;
- internal ovrAvatarCapabilities Capabilities = ovrAvatarCapabilities.Body;
-
- [Header("Performance")]
- #if UNITY_ANDROID
- [Tooltip(
- "LOD mesh complexity and texture resolution. Highest LOD recommended on PC and simple mobile apps." +
- " Medium LOD recommended on mobile devices or for background characters on PC." +
- " Lowest LOD recommended for background characters on mobile.")]
- [SerializeField]
- internal ovrAvatarAssetLevelOfDetail LevelOfDetail = ovrAvatarAssetLevelOfDetail.Medium;
- #else
- [SerializeField]
- internal ovrAvatarAssetLevelOfDetail LevelOfDetail = ovrAvatarAssetLevelOfDetail.Highest;
- #endif
- #if UNITY_ANDROID && UNITY_5_5_OR_NEWER
- [Tooltip(
- "Enable to use combined meshes to reduce draw calls. Currently only available on mobile devices. " +
- "Will be forced to false on PC.")]
- private bool CombineMeshes = true;
- #else
- private bool CombineMeshes = false;
- #endif
- [Tooltip(
- "Enable to use transparent queue, disable to use geometry queue. Requires restart to take effect.")]
- public bool UseTransparentRenderQueue = true;
-
- [Header("Shaders")]
- public Shader Monochrome_SurfaceShader;
- public Shader Monochrome_SurfaceShader_SelfOccluding;
- public Shader Monochrome_SurfaceShader_PBS;
- public Shader Skinshaded_SurfaceShader_SingleComponent;
- public Shader Skinshaded_VertFrag_SingleComponent;
- public Shader Skinshaded_VertFrag_CombinedMesh;
- public Shader Skinshaded_Expressive_SurfaceShader_SingleComponent;
- public Shader Skinshaded_Expressive_VertFrag_SingleComponent;
- public Shader Skinshaded_Expressive_VertFrag_CombinedMesh;
- public Shader Loader_VertFrag_CombinedMesh;
- public Shader EyeLens;
- public Shader ControllerShader;
-
- [Header("Other")]
- public bool CanOwnMicrophone = true;
- [Tooltip(
- "Enable laughter detection and animation as part of OVRLipSync.")]
- public bool EnableLaughter = true;
- public GameObject MouthAnchor;
- public Transform LeftHandCustomPose;
- public Transform RightHandCustomPose;
-
- // Avatar asset
- private HashSet<UInt64> assetLoadingIds = new HashSet<UInt64>();
- private bool assetsFinishedLoading = false;
-
- // Material manager
- private OvrAvatarMaterialManager materialManager;
- private bool waitingForCombinedMesh = false;
-
- // Global expressive system initialization
- private static bool doneExpressiveGlobalInit = false;
-
- // Clothing offsets
- private Vector4 clothingAlphaOffset = new Vector4(0f, 0f, 0f, 1f);
- private UInt64 clothingAlphaTexture = 0;
-
- // Lipsync
- private OVRLipSyncMicInput micInput = null;
- private OVRLipSyncContext lipsyncContext = null;
- private OVRLipSync.Frame currentFrame = new OVRLipSync.Frame();
- private float[] visemes = new float[VISEME_COUNT];
- private AudioSource audioSource;
- private ONSPAudioSource spatializedSource;
- private List<float[]> voiceUpdates = new List<float[]>();
- private static ovrAvatarVisemes RuntimeVisemes;
-
- // Custom hand poses
- private Transform cachedLeftHandCustomPose;
- private Transform[] cachedCustomLeftHandJoints;
- private ovrAvatarTransform[] cachedLeftHandTransforms;
- private Transform cachedRightHandCustomPose;
- private Transform[] cachedCustomRightHandJoints;
- private ovrAvatarTransform[] cachedRightHandTransforms;
- private bool showLeftController;
- private bool showRightController;
-
- // Consts
- #if UNITY_ANDROID
- private const bool USE_MOBILE_TEXTURE_FORMAT = true;
- #else
- private const bool USE_MOBILE_TEXTURE_FORMAT = false;
- #endif
- private static readonly Vector3 MOUTH_HEAD_OFFSET = new Vector3(0, -0.085f, 0.09f);
- private const string MOUTH_HELPER_NAME = "MouthAnchor";
- // Initial 'silence' score, 14 viseme scores and 1 laughter score as last element
- private const int VISEME_COUNT = 16;
- // Lipsync animation speeds
- private const float ACTION_UNIT_ONSET_SPEED = 30f;
- private const float ACTION_UNIT_FALLOFF_SPEED = 20f;
- private const float VISEME_LEVEL_MULTIPLIER = 1.5f;
-
- // Internals
- internal UInt64 oculusUserIDInternal;
- internal OvrAvatarBase Base = null;
- internal OvrAvatarTouchController ControllerLeft = null;
- internal OvrAvatarTouchController ControllerRight = null;
- internal OvrAvatarBody Body = null;
- internal OvrAvatarHand HandLeft = null;
- internal OvrAvatarHand HandRight = null;
- internal ovrAvatarLookAndFeelVersion LookAndFeelVersion = ovrAvatarLookAndFeelVersion.Two;
- internal ovrAvatarLookAndFeelVersion FallbackLookAndFeelVersion = ovrAvatarLookAndFeelVersion.Two;
- #if AVATAR_INTERNAL
- public AvatarControllerBlend BlendController;
- public UnityEvent AssetsDoneLoading = new UnityEvent();
- #endif
-
- // Avatar packets
- public class PacketEventArgs : EventArgs
- {
- public readonly OvrAvatarPacket Packet;
- public PacketEventArgs(OvrAvatarPacket packet)
- {
- Packet = packet;
- }
- }
- private OvrAvatarPacket CurrentUnityPacket;
- public EventHandler<PacketEventArgs> PacketRecorded;
-
- public enum HandType
- {
- Right,
- Left,
-
- Max
- };
-
- public enum HandJoint
- {
- HandBase,
- IndexBase,
- IndexTip,
- ThumbBase,
- ThumbTip,
-
- Max,
- }
-
- private static string[,] HandJoints = new string[(int)HandType.Max, (int)HandJoint.Max]
- {
- {
- "hands:r_hand_world",
- "hands:r_hand_world/hands:b_r_hand/hands:b_r_index1",
- "hands:r_hand_world/hands:b_r_hand/hands:b_r_index1/hands:b_r_index2/hands:b_r_index3/hands:b_r_index_ignore",
- "hands:r_hand_world/hands:b_r_hand/hands:b_r_thumb1/hands:b_r_thumb2",
- "hands:r_hand_world/hands:b_r_hand/hands:b_r_thumb1/hands:b_r_thumb2/hands:b_r_thumb3/hands:b_r_thumb_ignore"
- },
- {
- "hands:l_hand_world",
- "hands:l_hand_world/hands:b_l_hand/hands:b_l_index1",
- "hands:l_hand_world/hands:b_l_hand/hands:b_l_index1/hands:b_l_index2/hands:b_l_index3/hands:b_l_index_ignore",
- "hands:l_hand_world/hands:b_l_hand/hands:b_l_thumb1/hands:b_l_thumb2",
- "hands:l_hand_world/hands:b_l_hand/hands:b_l_thumb1/hands:b_l_thumb2/hands:b_l_thumb3/hands:b_l_thumb_ignore"
- }
- };
-
- static OvrAvatar()
- {
- // This size has to match the 'MarshalAs' attribute in the ovrAvatarVisemes declaration.
- RuntimeVisemes.visemeParams = new float[32];
- RuntimeVisemes.visemeParamCount = VISEME_COUNT;
- }
-
- void OnDestroy()
- {
- if (sdkAvatar != IntPtr.Zero)
- {
- CAPI.ovrAvatar_Destroy(sdkAvatar);
- }
- }
-
- public void AssetLoadedCallback(OvrAvatarAsset asset)
- {
- assetLoadingIds.Remove(asset.assetID);
- }
-
- public void CombinedMeshLoadedCallback(IntPtr assetPtr)
- {
- if (!waitingForCombinedMesh)
- {
- return;
- }
-
- var meshIDs = CAPI.ovrAvatarAsset_GetCombinedMeshIDs(assetPtr);
- foreach (var id in meshIDs)
- {
- assetLoadingIds.Remove(id);
- }
-
- CAPI.ovrAvatar_GetCombinedMeshAlphaData(sdkAvatar, ref clothingAlphaTexture, ref clothingAlphaOffset);
-
- waitingForCombinedMesh = false;
- }
-
- private OvrAvatarSkinnedMeshRenderComponent AddSkinnedMeshRenderComponent(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRender skinnedMeshRender)
- {
- OvrAvatarSkinnedMeshRenderComponent skinnedMeshRenderer = gameObject.AddComponent<OvrAvatarSkinnedMeshRenderComponent>();
- skinnedMeshRenderer.Initialize(skinnedMeshRender, Monochrome_SurfaceShader, Monochrome_SurfaceShader_SelfOccluding, ThirdPersonLayer.layerIndex, FirstPersonLayer.layerIndex);
- return skinnedMeshRenderer;
- }
-
- private OvrAvatarSkinnedMeshRenderPBSComponent AddSkinnedMeshRenderPBSComponent(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRenderPBS skinnedMeshRenderPBS)
- {
- OvrAvatarSkinnedMeshRenderPBSComponent skinnedMeshRenderer = gameObject.AddComponent<OvrAvatarSkinnedMeshRenderPBSComponent>();
- skinnedMeshRenderer.Initialize(skinnedMeshRenderPBS, Monochrome_SurfaceShader_PBS, ThirdPersonLayer.layerIndex, FirstPersonLayer.layerIndex);
- return skinnedMeshRenderer;
- }
-
- private OvrAvatarSkinnedMeshPBSV2RenderComponent AddSkinnedMeshRenderPBSV2Component(
- IntPtr renderPart,
- GameObject go,
- ovrAvatarRenderPart_SkinnedMeshRenderPBS_V2 skinnedMeshRenderPBSV2,
- bool isBodyPartZero,
- bool isControllerModel)
- {
- OvrAvatarSkinnedMeshPBSV2RenderComponent skinnedMeshRenderer = go.AddComponent<OvrAvatarSkinnedMeshPBSV2RenderComponent>();
- skinnedMeshRenderer.Initialize(
- renderPart,
- skinnedMeshRenderPBSV2,
- materialManager,
- ThirdPersonLayer.layerIndex,
- FirstPersonLayer.layerIndex,
- isBodyPartZero && CombineMeshes,
- LevelOfDetail,
- isBodyPartZero && EnableExpressive,
- this,
- isControllerModel);
-
- return skinnedMeshRenderer;
- }
-
- static public IntPtr GetRenderPart(ovrAvatarComponent component, UInt32 renderPartIndex)
- {
- return Marshal.ReadIntPtr(component.renderParts, Marshal.SizeOf(typeof(IntPtr)) * (int)renderPartIndex);
- }
-
- private static string GetRenderPartName(ovrAvatarComponent component, uint renderPartIndex)
- {
- return component.name + "_renderPart_" + (int)renderPartIndex;
- }
-
- internal static void ConvertTransform(float[] transform, ref ovrAvatarTransform target)
- {
- target.position.x = transform[0];
- target.position.y = transform[1];
- target.position.z = transform[2];
-
- target.orientation.x = transform[3];
- target.orientation.y = transform[4];
- target.orientation.z = transform[5];
- target.orientation.w = transform[6];
-
- target.scale.x = transform[7];
- target.scale.y = transform[8];
- target.scale.z = transform[9];
- }
-
- internal static 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;
- }
-
- public static ovrAvatarTransform CreateOvrAvatarTransform(Vector3 position, Quaternion orientation)
- {
- return new ovrAvatarTransform
- {
- position = new Vector3(position.x, position.y, -position.z),
- orientation = new Quaternion(-orientation.x, -orientation.y, orientation.z, orientation.w),
- scale = Vector3.one
- };
- }
-
- private static ovrAvatarGazeTarget CreateOvrGazeTarget(uint targetId, Vector3 targetPosition, ovrAvatarGazeTargetType targetType)
- {
- return new ovrAvatarGazeTarget
- {
- id = targetId,
- // Do coordinate system switch.
- worldPosition = new Vector3(targetPosition.x, targetPosition.y, -targetPosition.z),
- type = targetType
- };
- }
-
- private void BuildRenderComponents()
- {
- ovrAvatarBaseComponent baseComponnet = new ovrAvatarBaseComponent();
- ovrAvatarHandComponent leftHandComponnet = new ovrAvatarHandComponent();
- ovrAvatarHandComponent rightHandComponnet = new ovrAvatarHandComponent();
- ovrAvatarControllerComponent leftControllerComponent = new ovrAvatarControllerComponent();
- ovrAvatarControllerComponent rightControllerComponent = new ovrAvatarControllerComponent();
- ovrAvatarBodyComponent bodyComponent = new ovrAvatarBodyComponent();
-
- ovrAvatarComponent dummyComponent = new ovrAvatarComponent();
-
- const bool FetchName = true;
-
- if (CAPI.ovrAvatarPose_GetLeftHandComponent(sdkAvatar, ref leftHandComponnet))
- {
- CAPI.ovrAvatarComponent_Get(leftHandComponnet.renderComponent, FetchName, ref dummyComponent);
- AddAvatarComponent(ref HandLeft, dummyComponent);
- HandLeft.isLeftHand = true;
- }
-
- if (CAPI.ovrAvatarPose_GetRightHandComponent(sdkAvatar, ref rightHandComponnet))
- {
- CAPI.ovrAvatarComponent_Get(rightHandComponnet.renderComponent, FetchName, ref dummyComponent);
- AddAvatarComponent(ref HandRight, dummyComponent);
- HandRight.isLeftHand = false;
- }
-
- if (CAPI.ovrAvatarPose_GetBodyComponent(sdkAvatar, ref bodyComponent))
- {
- CAPI.ovrAvatarComponent_Get(bodyComponent.renderComponent, FetchName, ref dummyComponent);
- AddAvatarComponent(ref Body, dummyComponent);
- }
-
- if (CAPI.ovrAvatarPose_GetLeftControllerComponent(sdkAvatar, ref leftControllerComponent))
- {
- CAPI.ovrAvatarComponent_Get(leftControllerComponent.renderComponent, FetchName, ref dummyComponent);
- AddAvatarComponent(ref ControllerLeft, dummyComponent);
- ControllerLeft.isLeftHand = true;
- }
-
- if (CAPI.ovrAvatarPose_GetRightControllerComponent(sdkAvatar, ref rightControllerComponent))
- {
- CAPI.ovrAvatarComponent_Get(rightControllerComponent.renderComponent, FetchName, ref dummyComponent);
- AddAvatarComponent(ref ControllerRight, dummyComponent);
- ControllerRight.isLeftHand = false;
- }
-
- if (CAPI.ovrAvatarPose_GetBaseComponent(sdkAvatar, ref baseComponnet))
- {
- CAPI.ovrAvatarComponent_Get(baseComponnet.renderComponent, FetchName, ref dummyComponent);
- AddAvatarComponent(ref Base, dummyComponent);
- }
- }
-
- 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>();
- root.SetOvrAvatarOwner(this);
- AddRenderParts(root, nativeComponent, componentObject.transform);
- }
-
- void UpdateCustomPoses()
- {
- // Check to see if the pose roots changed
- if (UpdatePoseRoot(LeftHandCustomPose, ref cachedLeftHandCustomPose, ref cachedCustomLeftHandJoints, ref cachedLeftHandTransforms))
- {
- if (cachedLeftHandCustomPose == null && sdkAvatar != IntPtr.Zero)
- {
- CAPI.ovrAvatar_SetLeftHandGesture(sdkAvatar, ovrAvatarHandGesture.Default);
- }
- }
- if (UpdatePoseRoot(RightHandCustomPose, ref cachedRightHandCustomPose, ref cachedCustomRightHandJoints, ref cachedRightHandTransforms))
- {
- if (cachedRightHandCustomPose == null && sdkAvatar != IntPtr.Zero)
- {
- CAPI.ovrAvatar_SetRightHandGesture(sdkAvatar, ovrAvatarHandGesture.Default);
- }
- }
-
- // Check to see if the custom gestures need to be updated
- if (sdkAvatar != IntPtr.Zero)
- {
- if (cachedLeftHandCustomPose != null && UpdateTransforms(cachedCustomLeftHandJoints, cachedLeftHandTransforms))
- {
- CAPI.ovrAvatar_SetLeftHandCustomGesture(sdkAvatar, (uint)cachedLeftHandTransforms.Length, cachedLeftHandTransforms);
- }
- if (cachedRightHandCustomPose != null && UpdateTransforms(cachedCustomRightHandJoints, cachedRightHandTransforms))
- {
- CAPI.ovrAvatar_SetRightHandCustomGesture(sdkAvatar, (uint)cachedRightHandTransforms.Length, cachedRightHandTransforms);
- }
- }
- }
-
- static bool UpdatePoseRoot(Transform poseRoot, ref Transform cachedPoseRoot, ref Transform[] cachedPoseJoints, ref ovrAvatarTransform[] transforms)
- {
- if (poseRoot == cachedPoseRoot)
- {
- return false;
- }
-
- if (!poseRoot)
- {
- cachedPoseRoot = null;
- cachedPoseJoints = null;
- transforms = null;
- }
- else
- {
- List<Transform> joints = new List<Transform>();
- OrderJoints(poseRoot, joints);
- cachedPoseRoot = poseRoot;
- cachedPoseJoints = joints.ToArray();
- transforms = new ovrAvatarTransform[joints.Count];
- }
- return true;
- }
-
- static bool UpdateTransforms(Transform[] joints, ovrAvatarTransform[] transforms)
- {
- bool updated = false;
- for (int i = 0; i < joints.Length; ++i)
- {
- Transform joint = joints[i];
- ovrAvatarTransform transform = CreateOvrAvatarTransform(joint.localPosition, joint.localRotation);
- if (transform.position != transforms[i].position || transform.orientation != transforms[i].orientation)
- {
- transforms[i] = transform;
- updated = true;
- }
- }
- return updated;
- }
-
-
- private static void OrderJoints(Transform transform, List<Transform> joints)
- {
- joints.Add(transform);
- for (int i = 0; i < transform.childCount; ++i)
- {
- Transform child = transform.GetChild(i);
- OrderJoints(child, joints);
- }
- }
-
- void AvatarSpecificationCallback(IntPtr avatarSpecification)
- {
- sdkAvatar = CAPI.ovrAvatar_Create(avatarSpecification, Capabilities);
- ShowLeftController(showLeftController);
- ShowRightController(showRightController);
-
- // Pump the Remote driver once to push the controller type through
- if (Driver != null)
- {
- Driver.UpdateTransformsFromPose(sdkAvatar);
- }
-
- //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,
- LevelOfDetail,
- AssetLoadedCallback);
-
- assetLoadingIds.Add(id);
- }
- }
-
- if (CombineMeshes)
- {
- OvrAvatarSDKManager.Instance.RegisterCombinedMeshCallback(
- sdkAvatar,
- CombinedMeshLoadedCallback);
- }
- }
-
- void Start()
- {
- if (OvrAvatarSDKManager.Instance == null)
- {
- return;
- }
- #if !UNITY_ANDROID
- if (CombineMeshes)
- {
- CombineMeshes = false;
- AvatarLogger.Log("Combined Meshes currently only supported on mobile");
- }
- #endif
- #if !UNITY_5_5_OR_NEWER
- if (CombineMeshes)
- {
- CombineMeshes = false;
- AvatarLogger.LogWarning("Combined Meshes requires Unity 5.5.0+");
- }
- #endif
- materialManager = gameObject.AddComponent<OvrAvatarMaterialManager>();
-
- try
- {
- oculusUserIDInternal = UInt64.Parse(oculusUserID);
- }
- catch (Exception)
- {
- oculusUserIDInternal = 0;
- AvatarLogger.LogWarning("Invalid Oculus User ID Format");
- }
-
- // If no oculus ID is supplied then turn off combine meshes to prevent the texture arrays
- // being populated by invalid textures.
- if (oculusUserIDInternal == 0)
- {
- AvatarLogger.LogWarning("Oculus User ID set to 0. Provide actual user ID: " + gameObject.name);
- CombineMeshes = false;
- }
-
- AvatarLogger.Log("Starting OvrAvatar " + gameObject.name);
- AvatarLogger.Log(AvatarLogger.Tab + "LOD: " + LevelOfDetail.ToString());
- AvatarLogger.Log(AvatarLogger.Tab + "Combine Meshes: " + CombineMeshes);
- AvatarLogger.Log(AvatarLogger.Tab + "Force Mobile Textures: " + USE_MOBILE_TEXTURE_FORMAT);
- AvatarLogger.Log(AvatarLogger.Tab + "Oculus User ID: " + oculusUserIDInternal);
-
- Capabilities = 0;
-
- bool is3Dof = false;
- var headsetType = OVRPlugin.GetSystemHeadsetType();
- switch (headsetType)
- {
- 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:
- case OVRPlugin.SystemHeadset.Oculus_Go:
- is3Dof = true;
- break;
- case OVRPlugin.SystemHeadset.Oculus_Quest:
- case OVRPlugin.SystemHeadset.Rift_S:
- case OVRPlugin.SystemHeadset.Rift_DK1:
- case OVRPlugin.SystemHeadset.Rift_DK2:
- case OVRPlugin.SystemHeadset.Rift_CV1:
- default:
- break;
- }
-
- // The SDK 3 DOF Arm Model requires the body skeleton to pose itself. It will crash without it
- // The likely use case here is trying to have an invisible body.
- // T45010595
- if (is3Dof && !EnableBody)
- {
- AvatarLogger.Log("Forcing the Body component for 3Dof hand tracking, and setting the visibility to 1st person");
- EnableBody = true;
- ShowFirstPerson = true;
- ShowThirdPerson = false;
- }
-
- if (EnableBody) Capabilities |= ovrAvatarCapabilities.Body;
- if (EnableHands) Capabilities |= ovrAvatarCapabilities.Hands;
- if (EnableBase && EnableBody) Capabilities |= ovrAvatarCapabilities.Base;
- if (EnableExpressive) Capabilities |= ovrAvatarCapabilities.Expressive;
-
- // Enable body tilt on 6dof devices
- if(OVRPlugin.positionSupported)
- {
- Capabilities |= ovrAvatarCapabilities.BodyTilt;
- }
-
- ShowLeftController(StartWithControllers);
- ShowRightController(StartWithControllers);
-
- OvrAvatarSDKManager.AvatarSpecRequestParams avatarSpecRequest = new OvrAvatarSDKManager.AvatarSpecRequestParams(
- oculusUserIDInternal,
- this.AvatarSpecificationCallback,
- CombineMeshes,
- LevelOfDetail,
- USE_MOBILE_TEXTURE_FORMAT,
- LookAndFeelVersion,
- FallbackLookAndFeelVersion,
- EnableExpressive);
-
- OvrAvatarSDKManager.Instance.RequestAvatarSpecification(avatarSpecRequest);
- OvrAvatarSDKManager.Instance.AddLoadingAvatar(GetInstanceID());
-
- waitingForCombinedMesh = CombineMeshes;
- if (Driver != null)
- {
- Driver.Mode = UseSDKPackets ? OvrAvatarDriver.PacketMode.SDK : OvrAvatarDriver.PacketMode.Unity;
- }
- }
-
- void Update()
- {
- if (!OvrAvatarSDKManager.Instance || sdkAvatar == IntPtr.Zero || materialManager == null)
- {
- return;
- }
-
- if (Driver != null)
- {
- Driver.UpdateTransforms(sdkAvatar);
-
- foreach (float[] voiceUpdate in voiceUpdates)
- {
- CAPI.ovrAvatarPose_UpdateVoiceVisualization(sdkAvatar, voiceUpdate);
- }
-
- voiceUpdates.Clear();
- #if AVATAR_INTERNAL
- if (BlendController != null)
- {
- BlendController.UpdateBlend(sdkAvatar);
- }
- #endif
- CAPI.ovrAvatarPose_Finalize(sdkAvatar, Time.deltaTime);
- }
-
- if (RecordPackets)
- {
- RecordFrame();
- }
-
- if (assetLoadingIds.Count == 0)
- {
- if (!assetsFinishedLoading)
- {
- try
- {
- BuildRenderComponents();
- }
- catch (Exception e)
- {
- assetsFinishedLoading = true;
- throw e; // rethrow the original exception to preserve callstack
- }
- #if AVATAR_INTERNAL
- AssetsDoneLoading.Invoke();
- #endif
- InitPostLoad();
- assetsFinishedLoading = true;
- OvrAvatarSDKManager.Instance.RemoveLoadingAvatar(GetInstanceID());
- }
-
- UpdateVoiceBehavior();
- UpdateCustomPoses();
- if (EnableExpressive)
- {
- UpdateExpressive();
- }
- }
- }
-
- public static ovrAvatarHandInputState CreateInputState(ovrAvatarTransform transform, OvrAvatarDriver.ControllerPose pose)
- {
- ovrAvatarHandInputState inputState = new ovrAvatarHandInputState();
- inputState.transform = transform;
- inputState.buttonMask = pose.buttons;
- inputState.touchMask = pose.touches;
- inputState.joystickX = pose.joystickPosition.x;
- inputState.joystickY = pose.joystickPosition.y;
- inputState.indexTrigger = pose.indexTrigger;
- inputState.handTrigger = pose.handTrigger;
- inputState.isActive = pose.isActive;
- return inputState;
- }
-
- public void ShowControllers(bool show)
- {
- ShowLeftController(show);
- ShowRightController(show);
- }
-
- public void ShowLeftController(bool show)
- {
- if (sdkAvatar != IntPtr.Zero)
- {
- CAPI.ovrAvatar_SetLeftControllerVisibility(sdkAvatar, show);
- }
- showLeftController = show;
- }
-
- public void ShowRightController(bool show)
- {
- if (sdkAvatar != IntPtr.Zero)
- {
- CAPI.ovrAvatar_SetRightControllerVisibility(sdkAvatar, show);
- }
- showRightController = show;
- }
-
- public void UpdateVoiceVisualization(float[] voiceSamples)
- {
- voiceUpdates.Add(voiceSamples);
- }
-
- void RecordFrame()
- {
- if(UseSDKPackets)
- {
- RecordSDKFrame();
- }
- else
- {
- RecordUnityFrame();
- }
- }
-
- // Meant to be used mutually exclusively with RecordSDKFrame to give user more options to optimize or tweak packet data
- private void RecordUnityFrame()
- {
- var deltaSeconds = Time.deltaTime;
- var frame = Driver.GetCurrentPose();
- // If this is our first packet, store the pose as the initial frame
- if (CurrentUnityPacket == null)
- {
- CurrentUnityPacket = new OvrAvatarPacket(frame);
- deltaSeconds = 0;
- }
-
- float recordedSeconds = 0;
- while (recordedSeconds < deltaSeconds)
- {
- float remainingSeconds = deltaSeconds - recordedSeconds;
- float remainingPacketSeconds = PacketSettings.UpdateRate - CurrentUnityPacket.Duration;
-
- // If we're not going to fill the packet, just add the frame
- if (remainingSeconds < remainingPacketSeconds)
- {
- CurrentUnityPacket.AddFrame(frame, remainingSeconds);
- recordedSeconds += remainingSeconds;
- }
-
- // If we're going to fill the packet, interpolate the pose, send the packet,
- // and open a new one
- else
- {
- // Interpolate between the packet's last frame and our target pose
- // to compute a pose at the end of the packet time.
- OvrAvatarDriver.PoseFrame a = CurrentUnityPacket.FinalFrame;
- OvrAvatarDriver.PoseFrame b = frame;
- float t = remainingPacketSeconds / remainingSeconds;
- OvrAvatarDriver.PoseFrame intermediatePose = OvrAvatarDriver.PoseFrame.Interpolate(a, b, t);
- CurrentUnityPacket.AddFrame(intermediatePose, remainingPacketSeconds);
- recordedSeconds += remainingPacketSeconds;
-
- // Broadcast the recorded packet
- if (PacketRecorded != null)
- {
- PacketRecorded(this, new PacketEventArgs(CurrentUnityPacket));
- }
-
- // Open a new packet
- CurrentUnityPacket = new OvrAvatarPacket(intermediatePose);
- }
- }
- }
-
- private void RecordSDKFrame()
- {
- if (sdkAvatar == IntPtr.Zero)
- {
- return;
- }
-
- if (!PacketSettings.RecordingFrames)
- {
- CAPI.ovrAvatarPacket_BeginRecording(sdkAvatar);
- PacketSettings.AccumulatedTime = 0.0f;
- PacketSettings.RecordingFrames = true;
- }
-
- PacketSettings.AccumulatedTime += Time.deltaTime;
-
- if (PacketSettings.AccumulatedTime >= PacketSettings.UpdateRate)
- {
- PacketSettings.AccumulatedTime = 0.0f;
- var packet = CAPI.ovrAvatarPacket_EndRecording(sdkAvatar);
- CAPI.ovrAvatarPacket_BeginRecording(sdkAvatar);
-
- if (PacketRecorded != null)
- {
- PacketRecorded(this, new PacketEventArgs(new OvrAvatarPacket { ovrNativePacket = packet }));
- }
-
- CAPI.ovrAvatarPacket_Free(packet);
- }
- }
-
- private void AddRenderParts(
- OvrAvatarComponent ovrComponent,
- ovrAvatarComponent component,
- Transform parent)
- {
- bool isBody = ovrComponent.name == "body";
- bool isLeftController = ovrComponent.name == "controller_left";
- bool isReftController = ovrComponent.name == "controller_right";
-
- for (UInt32 renderPartIndex = 0; renderPartIndex < component.renderPartCount; renderPartIndex++)
- {
- GameObject renderPartObject = new GameObject();
- renderPartObject.name = GetRenderPartName(component, renderPartIndex);
- renderPartObject.transform.SetParent(parent);
- IntPtr renderPart = GetRenderPart(component, renderPartIndex);
- ovrAvatarRenderPartType type = CAPI.ovrAvatarRenderPart_GetType(renderPart);
- OvrAvatarRenderComponent ovrRenderPart = null;
- switch (type)
- {
- case ovrAvatarRenderPartType.SkinnedMeshRender:
- ovrRenderPart = AddSkinnedMeshRenderComponent(renderPartObject, CAPI.ovrAvatarRenderPart_GetSkinnedMeshRender(renderPart));
- break;
- case ovrAvatarRenderPartType.SkinnedMeshRenderPBS:
- ovrRenderPart = AddSkinnedMeshRenderPBSComponent(renderPartObject, CAPI.ovrAvatarRenderPart_GetSkinnedMeshRenderPBS(renderPart));
- break;
- case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2:
- {
- ovrRenderPart = AddSkinnedMeshRenderPBSV2Component(
- renderPart,
- renderPartObject,
- CAPI.ovrAvatarRenderPart_GetSkinnedMeshRenderPBSV2(renderPart),
- isBody && renderPartIndex == 0,
- isLeftController || isReftController);
- }
- break;
- default:
- break;
- }
-
- if (ovrRenderPart != null)
- {
- ovrComponent.RenderParts.Add(ovrRenderPart);
- }
- }
- }
-
- public void RefreshBodyParts()
- {
- if (Body != null)
- {
- foreach (var part in Body.RenderParts)
- {
- Destroy(part.gameObject);
- }
-
- Body.RenderParts.Clear();
-
- var nativeAvatarComponent = Body.GetNativeAvatarComponent();
- if (nativeAvatarComponent.HasValue)
- {
- AddRenderParts(Body, nativeAvatarComponent.Value, Body.gameObject.transform);
- }
- }
- }
-
- public ovrAvatarBodyComponent? GetBodyComponent()
- {
- if (Body != null)
- {
- CAPI.ovrAvatarPose_GetBodyComponent(sdkAvatar, ref Body.component);
- return Body.component;
- }
-
- return null;
- }
-
- public Transform GetHandTransform(HandType hand, HandJoint joint)
- {
- if (hand >= HandType.Max || joint >= HandJoint.Max)
- {
- return null;
- }
-
- var HandObject = hand == HandType.Left ? HandLeft : HandRight;
-
- if (HandObject != null)
- {
- var AvatarComponent = HandObject.GetComponent<OvrAvatarComponent>();
- if (AvatarComponent != null && AvatarComponent.RenderParts.Count > 0)
- {
- var SkinnedMesh = AvatarComponent.RenderParts[0];
- return SkinnedMesh.transform.Find(HandJoints[(int)hand, (int)joint]);
- }
- }
-
- return null;
- }
-
- public void GetPointingDirection(HandType hand, ref Vector3 forward, ref Vector3 up)
- {
- Transform handBase = GetHandTransform(hand, HandJoint.HandBase);
-
- if (handBase != null)
- {
- forward = handBase.forward;
- up = handBase.up;
- }
- }
-
- static Vector3 MOUTH_POSITION_OFFSET = new Vector3(0, -0.018f, 0.1051f);
- static string VOICE_PROPERTY = "_Voice";
- static string MOUTH_POSITION_PROPERTY = "_MouthPosition";
- static string MOUTH_DIRECTION_PROPERTY = "_MouthDirection";
- static string MOUTH_SCALE_PROPERTY = "_MouthEffectScale";
-
- static float MOUTH_SCALE_GLOBAL = 0.007f;
- static float MOUTH_MAX_GLOBAL = 0.007f;
- static string NECK_JONT = "root_JNT/body_JNT/chest_JNT/neckBase_JNT/neck_JNT";
-
- public float VoiceAmplitude = 0f;
- public bool EnableMouthVertexAnimation = false;
-
- private void UpdateVoiceBehavior()
- {
- if (!EnableMouthVertexAnimation)
- {
- return;
- }
-
- if (Body != null)
- {
- OvrAvatarComponent component = Body.GetComponent<OvrAvatarComponent>();
-
- VoiceAmplitude = Mathf.Clamp(VoiceAmplitude, 0f, 1f);
-
- if (component.RenderParts.Count > 0)
- {
- var material = component.RenderParts[0].mesh.sharedMaterial;
- var neckJoint = component.RenderParts[0].mesh.transform.Find(NECK_JONT);
- var scaleDiff = neckJoint.TransformPoint(Vector3.up) - neckJoint.position;
-
- material.SetFloat(MOUTH_SCALE_PROPERTY, scaleDiff.magnitude);
-
- material.SetFloat(
- VOICE_PROPERTY,
- Mathf.Min(scaleDiff.magnitude * MOUTH_MAX_GLOBAL, scaleDiff.magnitude * VoiceAmplitude * MOUTH_SCALE_GLOBAL));
-
- material.SetVector(
- MOUTH_POSITION_PROPERTY,
- neckJoint.TransformPoint(MOUTH_POSITION_OFFSET));
-
- material.SetVector(MOUTH_DIRECTION_PROPERTY, neckJoint.up);
- }
- }
- }
-
- bool IsValidMic()
- {
- string[] devices = Microphone.devices;
-
- if (devices.Length < 1)
- {
- return false;
- }
-
- int selectedDeviceIndex = 0;
- #if UNITY_STANDALONE_WIN
- for (int i = 1; i < devices.Length; i++)
- {
- if (devices[i].ToUpper().Contains("RIFT"))
- {
- selectedDeviceIndex = i;
- break;
- }
- }
- #endif
-
- string selectedDevice = devices[selectedDeviceIndex];
-
- int minFreq;
- int maxFreq;
- Microphone.GetDeviceCaps(selectedDevice, out minFreq, out maxFreq);
-
- if (maxFreq == 0)
- {
- maxFreq = 44100;
- }
-
- AudioClip clip = Microphone.Start(selectedDevice, true, 1, maxFreq);
- if (clip == null)
- {
- return false;
- }
-
- Microphone.End(selectedDevice);
- return true;
- }
-
- void InitPostLoad()
- {
- ExpressiveGlobalInit();
-
- ConfigureHelpers();
-
- if (GetComponent<OvrAvatarLocalDriver>() != null)
- {
- // Use mic.
- lipsyncContext.audioLoopback = false;
- if (CanOwnMicrophone && IsValidMic())
- {
- micInput = MouthAnchor.gameObject.AddComponent<OVRLipSyncMicInput>();
- micInput.enableMicSelectionGUI = false;
- micInput.MicFrequency = 44100;
- micInput.micControl = OVRLipSyncMicInput.micActivation.ConstantSpeak;
- }
-
- // Set lipsync animation parameters in SDK
- CAPI.ovrAvatar_SetActionUnitOnsetSpeed(sdkAvatar, ACTION_UNIT_ONSET_SPEED);
- CAPI.ovrAvatar_SetActionUnitFalloffSpeed(sdkAvatar, ACTION_UNIT_FALLOFF_SPEED);
- CAPI.ovrAvatar_SetVisemeMultiplier(sdkAvatar, VISEME_LEVEL_MULTIPLIER);
- }
- }
-
- static ovrAvatarLights ovrLights = new ovrAvatarLights();
- static void ExpressiveGlobalInit()
- {
- if (doneExpressiveGlobalInit)
- {
- return;
- }
-
- doneExpressiveGlobalInit = true;
-
- // This array size has to match the 'MarshalAs' attribute in the ovrAvatarLights declaration.
- const int MAXSIZE = 16;
- ovrLights.lights = new ovrAvatarLight[MAXSIZE];
-
- InitializeLights();
- }
-
- static void InitializeLights()
- {
- // Set light info. Lights are shared across all avatar instances.
- ovrLights.ambientIntensity = RenderSettings.ambientLight.grayscale * 0.5f;
-
- Light[] sceneLights = FindObjectsOfType(typeof(Light)) as Light[];
- int i = 0;
- for (i = 0; i < sceneLights.Length && i < ovrLights.lights.Length; ++i)
- {
- Light sceneLight = sceneLights[i];
- if (sceneLight && sceneLight.enabled)
- {
- uint instanceID = (uint)sceneLight.transform.GetInstanceID();
- switch (sceneLight.type)
- {
- case LightType.Directional:
- {
- CreateLightDirectional(instanceID, sceneLight.transform.forward, sceneLight.intensity, ref ovrLights.lights[i]);
- break;
- }
- case LightType.Point:
- {
- CreateLightPoint(instanceID, sceneLight.transform.position, sceneLight.range, sceneLight.intensity, ref ovrLights.lights[i]);
- break;
- }
- case LightType.Spot:
- {
- CreateLightSpot(instanceID, sceneLight.transform.position, sceneLight.transform.forward, sceneLight.spotAngle, sceneLight.range, sceneLight.intensity, ref ovrLights.lights[i]);
- break;
- }
- }
- }
- }
-
- ovrLights.lightCount = (uint)i;
-
- CAPI.ovrAvatar_UpdateLights(ovrLights);
- }
-
- static ovrAvatarLight CreateLightDirectional(uint id, Vector3 direction, float intensity, ref ovrAvatarLight light)
- {
- light.id = id;
- light.type = ovrAvatarLightType.Direction;
- light.worldDirection = new Vector3(direction.x, direction.y, -direction.z);
- light.intensity = intensity;
- return light;
- }
-
- static ovrAvatarLight CreateLightPoint(uint id, Vector3 position, float range, float intensity, ref ovrAvatarLight light)
- {
- light.id = id;
- light.type = ovrAvatarLightType.Point;
- light.worldPosition = new Vector3(position.x, position.y, -position.z);
- light.range = range;
- light.intensity = intensity;
- return light;
- }
-
- static ovrAvatarLight CreateLightSpot(uint id, Vector3 position, Vector3 direction, float spotAngleDeg, float range, float intensity, ref ovrAvatarLight light)
- {
- light.id = id;
- light.type = ovrAvatarLightType.Spot;
- light.worldPosition = new Vector3(position.x, position.y, -position.z);
- light.worldDirection = new Vector3(direction.x, direction.y, -direction.z);
- light.spotAngleDeg = spotAngleDeg;
- light.range = range;
- light.intensity = intensity;
- return light;
- }
-
- void UpdateExpressive()
- {
- ovrAvatarTransform baseTransform = OvrAvatar.CreateOvrAvatarTransform(transform.position, transform.rotation);
- CAPI.ovrAvatar_UpdateWorldTransform(sdkAvatar, baseTransform);
-
- UpdateFacewave();
- }
-
- private void ConfigureHelpers()
- {
- Transform head =
- transform.Find("body/body_renderPart_0/root_JNT/body_JNT/chest_JNT/neckBase_JNT/neck_JNT/head_JNT");
- if (head == null)
- {
- AvatarLogger.LogError("Avatar helper config failed. Cannot find head transform. All helpers spawning on root avatar transform");
- head = transform;
- }
-
- if (MouthAnchor == null)
- {
- MouthAnchor = CreateHelperObject(head, MOUTH_HEAD_OFFSET, MOUTH_HELPER_NAME);
- }
-
- if (GetComponent<OvrAvatarLocalDriver>() != null)
- {
- if (audioSource == null)
- {
- audioSource = MouthAnchor.gameObject.AddComponent<AudioSource>();
- }
- spatializedSource = MouthAnchor.GetComponent<ONSPAudioSource>();
-
- if (spatializedSource == null)
- {
- spatializedSource = MouthAnchor.gameObject.AddComponent<ONSPAudioSource>();
- }
-
- spatializedSource.UseInvSqr = true;
- spatializedSource.EnableRfl = false;
- spatializedSource.EnableSpatialization = true;
- spatializedSource.Far = 100f;
- spatializedSource.Near = 0.1f;
-
- // Add phoneme context to the mouth anchor
- lipsyncContext = MouthAnchor.GetComponent<OVRLipSyncContext>();
- if (lipsyncContext == null)
- {
- lipsyncContext = MouthAnchor.gameObject.AddComponent<OVRLipSyncContext>();
- }
-
- lipsyncContext.provider = EnableLaughter
- ? OVRLipSync.ContextProviders.Enhanced_with_Laughter
- : OVRLipSync.ContextProviders.Enhanced;
-
- // Ignore audio callback if microphone is owned by VoIP
- lipsyncContext.skipAudioSource = !CanOwnMicrophone;
-
- StartCoroutine(WaitForMouthAudioSource());
- }
-
- if (GetComponent<OvrAvatarRemoteDriver>() != null)
- {
- GazeTarget headTarget = head.gameObject.AddComponent<GazeTarget>();
- headTarget.Type = ovrAvatarGazeTargetType.AvatarHead;
- AvatarLogger.Log("Added head as gaze target");
-
- Transform hand = transform.Find("hand_left");
- if (hand == null)
- {
- AvatarLogger.LogWarning("Gaze target helper config failed: Cannot find left hand transform");
- }
- else
- {
- GazeTarget handTarget = hand.gameObject.AddComponent<GazeTarget>();
- handTarget.Type = ovrAvatarGazeTargetType.AvatarHand;
- AvatarLogger.Log("Added left hand as gaze target");
- }
-
- hand = transform.Find("hand_right");
- if (hand == null)
- {
- AvatarLogger.Log("Gaze target helper config failed: Cannot find right hand transform");
- }
- else
- {
- GazeTarget handTarget = hand.gameObject.AddComponent<GazeTarget>();
- handTarget.Type = ovrAvatarGazeTargetType.AvatarHand;
- AvatarLogger.Log("Added right hand as gaze target");
- }
- }
- }
-
- private IEnumerator WaitForMouthAudioSource()
- {
- while (MouthAnchor.GetComponent<AudioSource>() == null)
- {
- yield return new WaitForSeconds(0.1f);
- }
- AudioSource AS = MouthAnchor.GetComponent<AudioSource>();
- AS.minDistance = 0.3f;
- AS.maxDistance = 4f;
- AS.rolloffMode = AudioRolloffMode.Logarithmic;
- AS.loop = true;
- AS.playOnAwake = true;
- AS.spatialBlend = 1.0f;
- AS.spatialize = true;
- AS.spatializePostEffects = true;
- }
-
- public void DestroyHelperObjects()
- {
- if (MouthAnchor)
- {
- DestroyImmediate(MouthAnchor.gameObject);
- }
- }
-
- public GameObject CreateHelperObject(Transform parent, Vector3 localPositionOffset, string helperName,
- string helperTag = "")
- {
- GameObject helper = new GameObject();
- helper.name = helperName;
- if (helperTag != "")
- {
- helper.tag = helperTag;
- }
- helper.transform.SetParent(parent);
- helper.transform.localRotation = Quaternion.identity;
- helper.transform.localPosition = localPositionOffset;
- return helper;
- }
-
- public void UpdateVoiceData(short[] pcmData, int numChannels)
- {
- if (lipsyncContext != null && micInput == null)
- {
- lipsyncContext.ProcessAudioSamplesRaw(pcmData, numChannels);
- }
- }
- public void UpdateVoiceData(float[] pcmData, int numChannels)
- {
- if (lipsyncContext != null && micInput == null)
- {
- lipsyncContext.ProcessAudioSamplesRaw(pcmData, numChannels);
- }
- }
-
-
- private void UpdateFacewave()
- {
- if (lipsyncContext != null && (micInput != null || CanOwnMicrophone == false))
- {
- // Get the current viseme frame
- currentFrame = lipsyncContext.GetCurrentPhonemeFrame();
-
- // Verify length (-1 for laughter)
- if (currentFrame.Visemes.Length != (VISEME_COUNT - 1))
- {
- Debug.LogError("Unexpected number of visemes " + currentFrame.Visemes);
- return;
- }
-
- // Copy to viseme array
- currentFrame.Visemes.CopyTo(visemes, 0);
- // Copy laughter as final element
- visemes[VISEME_COUNT - 1] = EnableLaughter ? currentFrame.laughterScore : 0.0f;
-
- // Send visemes to native implementation.
- for (int i = 0; i < VISEME_COUNT; i++)
- {
- RuntimeVisemes.visemeParams[i] = visemes[i];
- }
- CAPI.ovrAvatar_SetVisemes(sdkAvatar, RuntimeVisemes);
- }
- }
- }
|