using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using BitStrap; using Oculus.Avatar; using UnityEngine; public class OvrAvatar : MonoBehaviour { public class PacketEventArgs : EventArgs { public readonly OvrAvatarPacket Packet; public PacketEventArgs(OvrAvatarPacket packet) { Packet = packet; } } public enum HandType { Right = 0, Left = 1, Max = 2 } public enum HandJoint { HandBase = 0, IndexBase = 1, IndexTip = 2, ThumbBase = 3, ThumbTip = 4, Max = 5 } public OvrAvatarMaterialManager DefaultBodyMaterialManager; public OvrAvatarMaterialManager DefaultHandMaterialManager; public OvrAvatarDriver Driver; internal OvrAvatarBase Base; internal OvrAvatarTouchController ControllerLeft; internal OvrAvatarTouchController ControllerRight; internal OvrAvatarBody Body; internal OvrAvatarHand HandLeft; internal OvrAvatarHand HandRight; [ReadOnly] public Transform leftControllerAnchor; [ReadOnly] public Transform rightControllerAnchor; [Header("Oculus User ID")] public string oculusUserID; internal ulong oculusUserIDInternal; [Header("Capabilities")] public bool EnableBody = true; public bool EnableHands = true; public bool EnableBase = true; public bool EnableExpressive; [Header("Network")] public bool RecordPackets; public bool UseSDKPackets = true; public PacketRecordSettings PacketSettings = new PacketRecordSettings(); [Header("Other")] public bool StartWithControllers; public AvatarLayer FirstPersonLayer; public AvatarLayer ThirdPersonLayer; public bool ShowFirstPerson = true; public bool ShowThirdPerson; public bool CanOwnMicrophone = true; internal ovrAvatarCapabilities Capabilities = ovrAvatarCapabilities.Body; [Tooltip("Enable this to use transparent queue, disable to use for geometry queue. Requires restart to take effect.")] [Header("Shaders")] public bool UseTransparentRenderQueue = true; 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; private static readonly Vector3 MOUTH_HEAD_OFFSET; private const string MOUTH_HELPER_NAME = "MouthAnchor"; private OVRLipSyncMicInput micInput; private OVRLipSyncContext lipsyncContext; private OVRLipSync.Frame currentFrame = new OVRLipSync.Frame(); private float[] visemes = new float[15]; private AudioSource audioSource; private ONSPAudioSource spatializedSource; private int renderPartCount; private bool showLeftController; private bool showRightController; private List voiceUpdates = new List(); private bool CombineMeshes; private bool ForceMobileTextureFormat; private bool WaitingForCombinedMesh; public IntPtr sdkAvatar = IntPtr.Zero; private HashSet assetLoadingIds = new HashSet(); private Dictionary trackedComponents = new Dictionary(); private bool assetsFinishedLoading; private static bool doneExpressiveGlobalInit; [Header("Misc")] public GameObject MouthAnchor; public Transform LeftHandCustomPose; public Transform RightHandCustomPose; private Transform cachedLeftHandCustomPose; private Transform[] cachedCustomLeftHandJoints; private ovrAvatarTransform[] cachedLeftHandTransforms; private Transform cachedRightHandCustomPose; private Transform[] cachedCustomRightHandJoints; private ovrAvatarTransform[] cachedRightHandTransforms; private Vector4 clothingAlphaOffset = new Vector4(0f, 0f, 0f, 1f); private ulong clothingAlphaTexture; private OvrAvatarPacket CurrentUnityPacket; private static string[,] HandJoints; internal ovrAvatarAssetLevelOfDetail LevelOfDetail = ovrAvatarAssetLevelOfDetail.Highest; internal ovrAvatarLookAndFeelVersion LookAndFeelVersion = ovrAvatarLookAndFeelVersion.Two; internal ovrAvatarLookAndFeelVersion FallbackLookAndFeelVersion; private static ovrAvatarVisemes RuntimeVisemes; public EventHandler PacketRecorded; private static Vector3 MOUTH_POSITION_OFFSET; private static string VOICE_PROPERTY; private static string MOUTH_POSITION_PROPERTY; private static string MOUTH_DIRECTION_PROPERTY; private static string MOUTH_SCALE_PROPERTY; private static float MOUTH_SCALE_GLOBAL; private static float MOUTH_MAX_GLOBAL; private static string NECK_JONT; public float VoiceAmplitude; public bool EnableMouthVertexAnimation; static OvrAvatar() { MOUTH_HEAD_OFFSET = new Vector3(0f, -0.085f, 0.09f); doneExpressiveGlobalInit = false; HandJoints = new string[2, 5] { { "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" } }; MOUTH_POSITION_OFFSET = new Vector3(0f, -0.018f, 0.1051f); VOICE_PROPERTY = "_Voice"; MOUTH_POSITION_PROPERTY = "_MouthPosition"; MOUTH_DIRECTION_PROPERTY = "_MouthDirection"; MOUTH_SCALE_PROPERTY = "_MouthEffectScale"; MOUTH_SCALE_GLOBAL = 0.007f; MOUTH_MAX_GLOBAL = 0.007f; NECK_JONT = "root_JNT/body_JNT/chest_JNT/neckBase_JNT/neck_JNT"; RuntimeVisemes.visemeParams = new float[32]; RuntimeVisemes.visemeParamCount = 15u; } private void OnEnable() { if ((bool)VRControllersManager.Instance && (bool)ControllerRight) { VRControllersManager.Instance.ChangeAvatar(this); } } private 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) { ulong[] array = CAPI.ovrAvatarAsset_GetCombinedMeshIDs(assetPtr); ulong[] array2 = array; foreach (ulong item in array2) { assetLoadingIds.Remove(item); } CAPI.ovrAvatar_GetCombinedMeshAlphaData(sdkAvatar, ref clothingAlphaTexture, ref clothingAlphaOffset); WaitingForCombinedMesh = false; } } private void AddAvatarComponent(GameObject componentObject, ovrAvatarComponent component) { OvrAvatarComponent ovrAvatarComponent2 = componentObject.AddComponent(); trackedComponents.Add(component.name, ovrAvatarComponent2); if (ovrAvatarComponent2.name == "body") { ovrAvatarComponent2.ClothingAlphaOffset = clothingAlphaOffset; ovrAvatarComponent2.ClothingAlphaTexture = clothingAlphaTexture; } AddRenderParts(ovrAvatarComponent2, component, componentObject.transform); } private OvrAvatarSkinnedMeshRenderComponent AddSkinnedMeshRenderComponent(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRender skinnedMeshRender) { OvrAvatarSkinnedMeshRenderComponent ovrAvatarSkinnedMeshRenderComponent = gameObject.AddComponent(); ovrAvatarSkinnedMeshRenderComponent.Initialize(skinnedMeshRender, Monochrome_SurfaceShader, Monochrome_SurfaceShader_SelfOccluding, ThirdPersonLayer.layerIndex, FirstPersonLayer.layerIndex, renderPartCount++); return ovrAvatarSkinnedMeshRenderComponent; } private OvrAvatarSkinnedMeshRenderPBSComponent AddSkinnedMeshRenderPBSComponent(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRenderPBS skinnedMeshRenderPBS) { OvrAvatarSkinnedMeshRenderPBSComponent ovrAvatarSkinnedMeshRenderPBSComponent = gameObject.AddComponent(); ovrAvatarSkinnedMeshRenderPBSComponent.Initialize(skinnedMeshRenderPBS, Monochrome_SurfaceShader_PBS, ThirdPersonLayer.layerIndex, FirstPersonLayer.layerIndex, renderPartCount++); return ovrAvatarSkinnedMeshRenderPBSComponent; } private OvrAvatarSkinnedMeshPBSV2RenderComponent AddSkinnedMeshRenderPBSV2Component(IntPtr renderPart, GameObject go, ovrAvatarRenderPart_SkinnedMeshRenderPBS_V2 skinnedMeshRenderPBSV2, OvrAvatarMaterialManager materialManager, bool isBodyPartZero, bool isControllerModel) { OvrAvatarSkinnedMeshPBSV2RenderComponent ovrAvatarSkinnedMeshPBSV2RenderComponent = go.AddComponent(); ovrAvatarSkinnedMeshPBSV2RenderComponent.Initialize(renderPart, skinnedMeshRenderPBSV2, materialManager, ThirdPersonLayer.layerIndex, FirstPersonLayer.layerIndex, renderPartCount++, isBodyPartZero && CombineMeshes, LevelOfDetail, isBodyPartZero && EnableExpressive, this, isControllerModel); return ovrAvatarSkinnedMeshPBSV2RenderComponent; } private OvrAvatarProjectorRenderComponent AddProjectorRenderComponent(GameObject gameObject, ovrAvatarRenderPart_ProjectorRender projectorRender) { ovrAvatarComponent ovrAvatarComponent2 = CAPI.ovrAvatarComponent_Get(sdkAvatar, projectorRender.componentIndex); OvrAvatarComponent value; if (trackedComponents.TryGetValue(ovrAvatarComponent2.name, out value) && projectorRender.renderPartIndex < value.RenderParts.Count) { OvrAvatarRenderComponent target = value.RenderParts[(int)projectorRender.renderPartIndex]; OvrAvatarProjectorRenderComponent ovrAvatarProjectorRenderComponent = gameObject.AddComponent(); ovrAvatarProjectorRenderComponent.InitializeProjectorRender(projectorRender, Monochrome_SurfaceShader, target); return ovrAvatarProjectorRenderComponent; } return null; } public static IntPtr GetRenderPart(ovrAvatarComponent component, uint renderPartIndex) { long num = Marshal.SizeOf(typeof(IntPtr)) * renderPartIndex; IntPtr ptr = new IntPtr(component.renderParts.ToInt64() + num); return (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr)); } private void UpdateAvatarComponent(ovrAvatarComponent component) { OvrAvatarComponent value; if (!trackedComponents.TryGetValue(component.name, out value)) { throw new Exception(string.Format("trackedComponents didn't have {0}", component.name)); } value.UpdateAvatar(component, this); } private static string GetRenderPartName(ovrAvatarComponent component, uint renderPartIndex) { return component.name + "_renderPart_" + (int)renderPartIndex; } internal static void ConvertTransform(ovrAvatarTransform transform, Transform target) { Vector3 position = transform.position; position.z = 0f - position.z; Quaternion orientation = transform.orientation; orientation.x = 0f - orientation.x; orientation.y = 0f - 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, 0f - position.z), orientation = new Quaternion(0f - orientation.x, 0f - orientation.y, orientation.z, orientation.w), scale = Vector3.one }; } private static ovrAvatarGazeTarget CreateOvrGazeTarget(uint targetId, Vector3 targetPosition, ovrAvatarGazeTargetType targetType) { return new ovrAvatarGazeTarget { id = targetId, worldPosition = new Vector3(targetPosition.x, targetPosition.y, 0f - targetPosition.z), type = targetType }; } private void BuildRenderComponents() { ovrAvatarHandComponent? ovrAvatarHandComponent2 = CAPI.ovrAvatarPose_GetLeftHandComponent(sdkAvatar); ovrAvatarHandComponent? ovrAvatarHandComponent3 = CAPI.ovrAvatarPose_GetRightHandComponent(sdkAvatar); ovrAvatarBodyComponent? ovrAvatarBodyComponent2 = CAPI.ovrAvatarPose_GetBodyComponent(sdkAvatar); ovrAvatarControllerComponent? ovrAvatarControllerComponent2 = CAPI.ovrAvatarPose_GetLeftControllerComponent(sdkAvatar); ovrAvatarControllerComponent? ovrAvatarControllerComponent3 = CAPI.ovrAvatarPose_GetRightControllerComponent(sdkAvatar); ovrAvatarBaseComponent? ovrAvatarBaseComponent2 = CAPI.ovrAvatarPose_GetBaseComponent(sdkAvatar); uint num = CAPI.ovrAvatarComponent_Count(sdkAvatar); for (uint num2 = 0u; num2 < num; num2++) { IntPtr intPtr = CAPI.ovrAvatarComponent_Get_Native(sdkAvatar, num2); ovrAvatarComponent component = (ovrAvatarComponent)Marshal.PtrToStructure(intPtr, typeof(ovrAvatarComponent)); if (!trackedComponents.ContainsKey(component.name)) { GameObject gameObject = new GameObject(); gameObject.name = component.name; gameObject.transform.SetParent(base.transform); AddAvatarComponent(gameObject, component); if (ovrAvatarHandComponent2.HasValue && intPtr == ovrAvatarHandComponent2.Value.renderComponent) { HandLeft = gameObject.AddComponent(); } if (ovrAvatarHandComponent3.HasValue && intPtr == ovrAvatarHandComponent3.Value.renderComponent) { HandRight = gameObject.AddComponent(); } if (ovrAvatarBodyComponent2.HasValue && intPtr == ovrAvatarBodyComponent2.Value.renderComponent) { Body = gameObject.AddComponent(); } if (ovrAvatarControllerComponent2.HasValue && intPtr == ovrAvatarControllerComponent2.Value.renderComponent) { ControllerLeft = gameObject.AddComponent(); } if (ovrAvatarControllerComponent3.HasValue && intPtr == ovrAvatarControllerComponent3.Value.renderComponent) { ControllerRight = gameObject.AddComponent(); } if (ovrAvatarBaseComponent2.HasValue && intPtr == ovrAvatarBaseComponent2.Value.renderComponent) { Base = gameObject.AddComponent(); } } } Utilities.SetLayerRecursively(ControllerLeft.gameObject, "TransparentFX"); Utilities.SetLayerRecursively(ControllerRight.gameObject, "TransparentFX"); Body.gameObject.SetActive(false); HandLeft.gameObject.SetActive(false); HandRight.gameObject.SetActive(false); if ((bool)VRControllersManager.Instance) { VRControllersManager.Instance.ChangeAvatar(this); } } private void UpdateSDKAvatarUnityState() { uint num = CAPI.ovrAvatarComponent_Count(sdkAvatar); for (uint num2 = 0u; num2 < num; num2++) { IntPtr ptr = CAPI.ovrAvatarComponent_Get_Native(sdkAvatar, num2); ovrAvatarComponent component = (ovrAvatarComponent)Marshal.PtrToStructure(ptr, typeof(ovrAvatarComponent)); UpdateAvatarComponent(component); } UpdateVoiceBehavior(); } private void UpdateCustomPoses() { if (UpdatePoseRoot(LeftHandCustomPose, ref cachedLeftHandCustomPose, ref cachedCustomLeftHandJoints, ref cachedLeftHandTransforms) && cachedLeftHandCustomPose == null && sdkAvatar != IntPtr.Zero) { CAPI.ovrAvatar_SetLeftHandGesture(sdkAvatar, ovrAvatarHandGesture.Default); } if (UpdatePoseRoot(RightHandCustomPose, ref cachedRightHandCustomPose, ref cachedCustomRightHandJoints, ref cachedRightHandTransforms) && cachedRightHandCustomPose == null && sdkAvatar != IntPtr.Zero) { CAPI.ovrAvatar_SetRightHandGesture(sdkAvatar, ovrAvatarHandGesture.Default); } 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); } } } private 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 list = new List(); OrderJoints(poseRoot, list); cachedPoseRoot = poseRoot; cachedPoseJoints = list.ToArray(); transforms = new ovrAvatarTransform[list.Count]; } return true; } private static bool UpdateTransforms(Transform[] joints, ovrAvatarTransform[] transforms) { bool result = false; for (int i = 0; i < joints.Length; i++) { Transform transform = joints[i]; ovrAvatarTransform ovrAvatarTransform2 = CreateOvrAvatarTransform(transform.localPosition, transform.localRotation); if (ovrAvatarTransform2.position != transforms[i].position || ovrAvatarTransform2.orientation != transforms[i].orientation) { transforms[i] = ovrAvatarTransform2; result = true; } } return result; } private static void OrderJoints(Transform transform, List joints) { joints.Add(transform); for (int i = 0; i < transform.childCount; i++) { Transform child = transform.GetChild(i); OrderJoints(child, joints); } } private void AvatarSpecificationCallback(IntPtr avatarSpecification) { sdkAvatar = CAPI.ovrAvatar_Create(avatarSpecification, Capabilities); ShowLeftController(showLeftController); ShowRightController(showRightController); uint num = CAPI.ovrAvatar_GetReferencedAssetCount(sdkAvatar); for (uint num2 = 0u; num2 < num; num2++) { ulong num3 = CAPI.ovrAvatar_GetReferencedAsset(sdkAvatar, num2); if (OvrAvatarSDKManager.Instance.GetAsset(num3) == null) { OvrAvatarSDKManager.Instance.BeginLoadingAsset(num3, LevelOfDetail, AssetLoadedCallback); assetLoadingIds.Add(num3); } } if (CombineMeshes) { OvrAvatarSDKManager.Instance.RegisterCombinedMeshCallback(sdkAvatar, CombinedMeshLoadedCallback); } } private void Start() { if (CombineMeshes) { CombineMeshes = false; } try { oculusUserIDInternal = ulong.Parse(oculusUserID); } catch (Exception) { oculusUserIDInternal = 0uL; } Capabilities = (ovrAvatarCapabilities)0; if (EnableBody) { Capabilities |= ovrAvatarCapabilities.Body; } if (EnableHands) { Capabilities |= ovrAvatarCapabilities.Hands; } if (EnableBase && EnableBody) { Capabilities |= ovrAvatarCapabilities.Base; } if (EnableExpressive) { Capabilities |= ovrAvatarCapabilities.Expressive; } Capabilities |= ovrAvatarCapabilities.BodyTilt; leftControllerAnchor = base.transform.parent.Find("LeftHandAnchor").Find("LeftControllerAnchor"); rightControllerAnchor = base.transform.parent.Find("RightHandAnchor").Find("RightControllerAnchor"); ShowLeftController(StartWithControllers); ShowRightController(StartWithControllers); OvrAvatarSDKManager.Instance.RequestAvatarSpecification(oculusUserIDInternal, AvatarSpecificationCallback, CombineMeshes, LevelOfDetail, ForceMobileTextureFormat, LookAndFeelVersion, FallbackLookAndFeelVersion, EnableExpressive); WaitingForCombinedMesh = CombineMeshes; if (Driver != null) { Driver.Mode = ((!UseSDKPackets) ? OvrAvatarDriver.PacketMode.Unity : OvrAvatarDriver.PacketMode.SDK); } } private void Update() { if (sdkAvatar == IntPtr.Zero) { return; } if (Driver != null) { Driver.UpdateTransforms(sdkAvatar); foreach (float[] voiceUpdate in voiceUpdates) { CAPI.ovrAvatarPose_UpdateVoiceVisualization(sdkAvatar, voiceUpdate); } voiceUpdates.Clear(); CAPI.ovrAvatarPose_Finalize(sdkAvatar, Time.deltaTime); } if (RecordPackets) { RecordFrame(); } if (assetLoadingIds.Count == 0) { if (!assetsFinishedLoading) { BuildRenderComponents(); InitPostLoad(); assetsFinishedLoading = true; } UpdateSDKAvatarUnityState(); UpdateCustomPoses(); if (EnableExpressive) { UpdateExpressive(); } } } public static ovrAvatarHandInputState CreateInputState(ovrAvatarTransform transform, OvrAvatarDriver.ControllerPose pose) { return new ovrAvatarHandInputState { transform = transform, buttonMask = pose.buttons, touchMask = pose.touches, joystickX = pose.joystickPosition.x, joystickY = pose.joystickPosition.y, indexTrigger = pose.indexTrigger, handTrigger = pose.handTrigger, isActive = pose.isActive }; } 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); } private void RecordFrame() { if (UseSDKPackets) { RecordSDKFrame(); } else { RecordUnityFrame(); } } private void RecordUnityFrame() { float num = Time.deltaTime; OvrAvatarDriver.PoseFrame currentPose = Driver.GetCurrentPose(); if (CurrentUnityPacket == null) { CurrentUnityPacket = new OvrAvatarPacket(currentPose); num = 0f; } float num2 = 0f; while (num2 < num) { float num3 = num - num2; float num4 = PacketSettings.UpdateRate - CurrentUnityPacket.Duration; if (num3 < num4) { CurrentUnityPacket.AddFrame(currentPose, num3); num2 += num3; continue; } OvrAvatarDriver.PoseFrame finalFrame = CurrentUnityPacket.FinalFrame; OvrAvatarDriver.PoseFrame b = currentPose; float t = num4 / num3; OvrAvatarDriver.PoseFrame poseFrame = OvrAvatarDriver.PoseFrame.Interpolate(finalFrame, b, t); CurrentUnityPacket.AddFrame(poseFrame, num4); num2 += num4; if (PacketRecorded != null) { PacketRecorded(this, new PacketEventArgs(CurrentUnityPacket)); } CurrentUnityPacket = new OvrAvatarPacket(poseFrame); } } private void RecordSDKFrame() { if (sdkAvatar == IntPtr.Zero) { return; } if (!PacketSettings.RecordingFrames) { CAPI.ovrAvatarPacket_BeginRecording(sdkAvatar); PacketSettings.AccumulatedTime = 0f; PacketSettings.RecordingFrames = true; } PacketSettings.AccumulatedTime += Time.deltaTime; if (PacketSettings.AccumulatedTime >= PacketSettings.UpdateRate) { PacketSettings.AccumulatedTime = 0f; IntPtr intPtr = CAPI.ovrAvatarPacket_EndRecording(sdkAvatar); CAPI.ovrAvatarPacket_BeginRecording(sdkAvatar); if (PacketRecorded != null) { PacketRecorded(this, new PacketEventArgs(new OvrAvatarPacket { ovrNativePacket = intPtr })); } CAPI.ovrAvatarPacket_Free(intPtr); } } private void AddRenderParts(OvrAvatarComponent ovrComponent, ovrAvatarComponent component, Transform parent) { bool flag = ovrComponent.name == "body"; bool flag2 = ovrComponent.name == "controller_left"; bool flag3 = ovrComponent.name == "controller_right"; for (uint num = 0u; num < component.renderPartCount; num++) { GameObject gameObject = new GameObject(); gameObject.name = GetRenderPartName(component, num); gameObject.transform.SetParent(parent); IntPtr renderPart = GetRenderPart(component, num); ovrAvatarRenderPartType ovrAvatarRenderPartType2 = CAPI.ovrAvatarRenderPart_GetType(renderPart); OvrAvatarRenderComponent item; switch (ovrAvatarRenderPartType2) { case ovrAvatarRenderPartType.SkinnedMeshRender: item = AddSkinnedMeshRenderComponent(gameObject, CAPI.ovrAvatarRenderPart_GetSkinnedMeshRender(renderPart)); break; case ovrAvatarRenderPartType.SkinnedMeshRenderPBS: item = AddSkinnedMeshRenderPBSComponent(gameObject, CAPI.ovrAvatarRenderPart_GetSkinnedMeshRenderPBS(renderPart)); break; case ovrAvatarRenderPartType.ProjectorRender: item = AddProjectorRenderComponent(gameObject, CAPI.ovrAvatarRenderPart_GetProjectorRender(renderPart)); break; case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2: item = AddSkinnedMeshRenderPBSV2Component(renderPart, gameObject, CAPI.ovrAvatarRenderPart_GetSkinnedMeshRenderPBSV2(renderPart), (!flag) ? DefaultHandMaterialManager : DefaultBodyMaterialManager, flag && num == 0, flag2 || flag3); break; default: throw new NotImplementedException(string.Format("Unsupported render part type: {0}", ovrAvatarRenderPartType2.ToString())); } ovrComponent.RenderParts.Add(item); } } public void RefreshBodyParts() { if (!(Body != null)) { return; } OvrAvatarComponent component = Body.GetComponent(); foreach (OvrAvatarRenderComponent renderPart in component.RenderParts) { UnityEngine.Object.Destroy(renderPart.gameObject); } component.RenderParts.Clear(); ovrAvatarBodyComponent? ovrAvatarBodyComponent2 = CAPI.ovrAvatarPose_GetBodyComponent(sdkAvatar); if (ovrAvatarBodyComponent2.HasValue) { ovrAvatarComponent component2 = (ovrAvatarComponent)Marshal.PtrToStructure(ovrAvatarBodyComponent2.Value.renderComponent, typeof(ovrAvatarComponent)); AddRenderParts(component, component2, Body.gameObject.transform); return; } throw new Exception("Destroyed the body component, but didn't find a new one in the SDK"); } public ovrAvatarBodyComponent? GetBodyComponent() { return CAPI.ovrAvatarPose_GetBodyComponent(sdkAvatar); } public Transform GetHandTransform(HandType hand, HandJoint joint) { if (hand >= HandType.Max || joint >= HandJoint.Max) { return null; } OvrAvatarHand ovrAvatarHand = ((hand != HandType.Left) ? HandRight : HandLeft); if (ovrAvatarHand != null) { OvrAvatarComponent component = ovrAvatarHand.GetComponent(); if (component != null && component.RenderParts.Count > 0) { OvrAvatarRenderComponent ovrAvatarRenderComponent = component.RenderParts[0]; return ovrAvatarRenderComponent.transform.Find(HandJoints[(int)hand, (int)joint]); } } return null; } public void GetPointingDirection(HandType hand, ref Vector3 forward, ref Vector3 up) { Transform handTransform = GetHandTransform(hand, HandJoint.HandBase); if (handTransform != null) { forward = handTransform.forward; up = handTransform.up; } } public Transform GetMouthTransform() { OvrAvatarComponent value; if (trackedComponents.TryGetValue("voice", out value) && value.RenderParts.Count > 0) { return value.RenderParts[0].transform; } return null; } private void UpdateVoiceBehavior() { if (EnableMouthVertexAnimation && Body != null) { OvrAvatarComponent component = Body.GetComponent(); VoiceAmplitude = Mathf.Clamp(VoiceAmplitude, 0f, 1f); if (component.RenderParts.Count > 0) { Material sharedMaterial = component.RenderParts[0].mesh.sharedMaterial; Transform transform = component.RenderParts[0].mesh.transform.Find(NECK_JONT); Vector3 vector = transform.TransformPoint(Vector3.up) - transform.position; sharedMaterial.SetFloat(MOUTH_SCALE_PROPERTY, vector.magnitude); sharedMaterial.SetFloat(VOICE_PROPERTY, Mathf.Min(vector.magnitude * MOUTH_MAX_GLOBAL, vector.magnitude * VoiceAmplitude * MOUTH_SCALE_GLOBAL)); sharedMaterial.SetVector(MOUTH_POSITION_PROPERTY, transform.TransformPoint(MOUTH_POSITION_OFFSET)); sharedMaterial.SetVector(MOUTH_DIRECTION_PROPERTY, transform.up); } } } private bool IsValidMic() { if (Microphone.devices.Length < 1) { return false; } string deviceName = Microphone.devices[0].ToString(); int minFreq; int maxFreq; Microphone.GetDeviceCaps(deviceName, out minFreq, out maxFreq); if (maxFreq == 0) { maxFreq = 44100; } AudioClip audioClip = Microphone.Start(deviceName, true, 1, maxFreq); if (audioClip == null) { return false; } Microphone.End(deviceName); return true; } private void InitPostLoad() { ExpressiveGlobalInit(); ConfigureHelpers(); if (GetComponent() != null) { lipsyncContext.audioLoopback = false; if (CanOwnMicrophone && IsValidMic()) { micInput = MouthAnchor.gameObject.AddComponent(); micInput.enableMicSelectionGUI = false; micInput.MicFrequency = 44100f; micInput.micControl = OVRLipSyncMicInput.micActivation.ConstantSpeak; } } } private static void ExpressiveGlobalInit() { if (doneExpressiveGlobalInit) { return; } doneExpressiveGlobalInit = true; ovrAvatarLights lights = new ovrAvatarLights { ambientIntensity = RenderSettings.ambientLight.grayscale * 0.5f, lights = new ovrAvatarLight[16] }; Light[] array = UnityEngine.Object.FindObjectsOfType(typeof(Light)) as Light[]; int num = 0; foreach (Light light in array) { if ((bool)light && light.enabled) { uint instanceID = (uint)light.transform.GetInstanceID(); switch (light.type) { case LightType.Directional: lights.lights[num++] = CreateLightDirectional(instanceID, light.transform.forward, light.intensity); break; case LightType.Point: lights.lights[num++] = CreateLightPoint(instanceID, light.transform.position, light.range, light.intensity); break; case LightType.Spot: lights.lights[num++] = CreateLightSpot(instanceID, light.transform.position, light.transform.forward, light.spotAngle, light.range, light.intensity); break; } } if (num >= 16) { break; } } lights.lightCount = (uint)num; CAPI.ovrAvatar_UpdateLights(lights); } private static ovrAvatarLight CreateLightDirectional(uint id, Vector3 direction, float intensity) { return new ovrAvatarLight { id = id, type = ovrAvatarLightType.Direction, worldDirection = new Vector3(direction.x, direction.y, 0f - direction.z), intensity = intensity }; } private static ovrAvatarLight CreateLightPoint(uint id, Vector3 position, float range, float intensity) { return new ovrAvatarLight { id = id, type = ovrAvatarLightType.Point, worldPosition = new Vector3(position.x, position.y, 0f - position.z), range = range, intensity = intensity }; } private static ovrAvatarLight CreateLightSpot(uint id, Vector3 position, Vector3 direction, float spotAngleDeg, float range, float intensity) { return new ovrAvatarLight { id = id, type = ovrAvatarLightType.Spot, worldPosition = new Vector3(position.x, position.y, 0f - position.z), worldDirection = new Vector3(direction.x, direction.y, 0f - direction.z), spotAngleDeg = spotAngleDeg, range = range, intensity = intensity }; } private void UpdateExpressive() { ovrAvatarTransform ovrAvatarTransform2 = CreateOvrAvatarTransform(base.transform.position, base.transform.rotation); CAPI.ovrAvatar_UpdateWorldTransform(sdkAvatar, ovrAvatarTransform2); UpdateFacewave(); } private void ConfigureHelpers() { Transform transform = base.transform.Find("body/body_renderPart_0/root_JNT/body_JNT/chest_JNT/neckBase_JNT/neck_JNT/head_JNT"); if (transform == null) { transform = base.transform; } if (MouthAnchor == null) { MouthAnchor = CreateHelperObject(transform, MOUTH_HEAD_OFFSET, "MouthAnchor", string.Empty); } if (GetComponent() != null) { if (audioSource == null) { audioSource = MouthAnchor.gameObject.AddComponent(); } spatializedSource = MouthAnchor.GetComponent(); if (spatializedSource == null) { spatializedSource = MouthAnchor.gameObject.AddComponent(); } spatializedSource.UseInvSqr = true; spatializedSource.EnableRfl = false; spatializedSource.EnableSpatialization = true; spatializedSource.Far = 100f; spatializedSource.Near = 0.1f; lipsyncContext = MouthAnchor.GetComponent(); if (lipsyncContext == null) { lipsyncContext = MouthAnchor.gameObject.AddComponent(); lipsyncContext.provider = OVRLipSync.ContextProviders.Enhanced; lipsyncContext.skipAudioSource = !CanOwnMicrophone; } StartCoroutine(WaitForMouthAudioSource()); } if (GetComponent() != null) { GazeTarget gazeTarget = transform.gameObject.AddComponent(); gazeTarget.Type = ovrAvatarGazeTargetType.AvatarHead; Transform transform2 = base.transform.Find("hand_left"); if (!(transform2 == null)) { GazeTarget gazeTarget2 = transform2.gameObject.AddComponent(); gazeTarget2.Type = ovrAvatarGazeTargetType.AvatarHand; } transform2 = base.transform.Find("hand_right"); if (!(transform2 == null)) { GazeTarget gazeTarget3 = transform2.gameObject.AddComponent(); gazeTarget3.Type = ovrAvatarGazeTargetType.AvatarHand; } } } private IEnumerator WaitForMouthAudioSource() { while (MouthAnchor.GetComponent() == null) { yield return new WaitForSeconds(0.1f); } AudioSource AS = MouthAnchor.GetComponent(); AS.minDistance = 0.3f; AS.maxDistance = 4f; AS.rolloffMode = AudioRolloffMode.Logarithmic; AS.loop = true; AS.playOnAwake = true; AS.spatialBlend = 1f; AS.spatialize = true; AS.spatializePostEffects = true; } public void DestroyHelperObjects() { if ((bool)MouthAnchor) { UnityEngine.Object.DestroyImmediate(MouthAnchor.gameObject); } } public GameObject CreateHelperObject(Transform parent, Vector3 localPositionOffset, string helperName, string helperTag = "") { GameObject gameObject = new GameObject(); gameObject.name = helperName; if (helperTag != string.Empty) { gameObject.tag = helperTag; } gameObject.transform.SetParent(parent); gameObject.transform.localRotation = Quaternion.identity; gameObject.transform.localPosition = localPositionOffset; return gameObject; } 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)) { return; } currentFrame = lipsyncContext.GetCurrentPhonemeFrame(); if (currentFrame.Visemes.Length != 15) { Debug.LogError("Unexpected number of visemes " + currentFrame.Visemes); return; } currentFrame.Visemes.CopyTo(visemes, 0); for (int i = 0; i < 15; i++) { RuntimeVisemes.visemeParams[i] = visemes[i]; } CAPI.ovrAvatar_SetVisemes(sdkAvatar, RuntimeVisemes); } }