Working experiment hooray
This commit is contained in:
946
Assets/Oculus/Avatar/Scripts/OvrAvatar.cs
Normal file
946
Assets/Oculus/Avatar/Scripts/OvrAvatar.cs
Normal file
@@ -0,0 +1,946 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Oculus.Avatar;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.Events;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#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
|
||||
{
|
||||
public OvrAvatarMaterialManager DefaultBodyMaterialManager;
|
||||
public OvrAvatarMaterialManager DefaultHandMaterialManager;
|
||||
|
||||
public OvrAvatarDriver Driver;
|
||||
public OvrAvatarBase Base;
|
||||
public OvrAvatarBody Body;
|
||||
public OvrAvatarTouchController ControllerLeft;
|
||||
public OvrAvatarTouchController ControllerRight;
|
||||
public OvrAvatarHand HandLeft;
|
||||
public OvrAvatarHand HandRight;
|
||||
public bool RecordPackets;
|
||||
public bool UseSDKPackets = true;
|
||||
|
||||
public bool StartWithControllers;
|
||||
public AvatarLayer FirstPersonLayer;
|
||||
public AvatarLayer ThirdPersonLayer;
|
||||
public bool ShowFirstPerson = true;
|
||||
public bool ShowThirdPerson;
|
||||
public ovrAvatarCapabilities Capabilities = ovrAvatarCapabilities.All;
|
||||
public Shader SurfaceShader;
|
||||
public Shader SurfaceShaderSelfOccluding;
|
||||
public Shader SurfaceShaderPBS;
|
||||
public Shader SurfaceShaderPBSV2Single;
|
||||
public Shader SurfaceShaderPBSV2Combined;
|
||||
public Shader SurfaceShaderPBSV2Simple;
|
||||
public Shader SurfaceShaderPBSV2Loading;
|
||||
|
||||
int renderPartCount = 0;
|
||||
bool showLeftController;
|
||||
bool showRightController;
|
||||
List<float[]> voiceUpdates = new List<float[]>();
|
||||
|
||||
public string oculusUserID;
|
||||
internal UInt64 oculusUserIDInternal;
|
||||
|
||||
#if UNITY_ANDROID && UNITY_5_5_OR_NEWER && !UNITY_EDITOR
|
||||
bool CombineMeshes = true;
|
||||
#else
|
||||
bool CombineMeshes = false;
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR && UNITY_ANDROID
|
||||
bool ForceMobileTextureFormat = true;
|
||||
#else
|
||||
bool ForceMobileTextureFormat = false;
|
||||
|
||||
#endif
|
||||
|
||||
private bool WaitingForCombinedMesh = false;
|
||||
|
||||
public IntPtr sdkAvatar = IntPtr.Zero;
|
||||
private HashSet<UInt64> assetLoadingIds = new HashSet<UInt64>();
|
||||
private Dictionary<string, OvrAvatarComponent> trackedComponents =
|
||||
new Dictionary<string, OvrAvatarComponent>();
|
||||
|
||||
private UnityEvent AssetsDoneLoading = new UnityEvent();
|
||||
bool assetsFinishedLoading = false;
|
||||
|
||||
public Transform LeftHandCustomPose;
|
||||
public Transform RightHandCustomPose;
|
||||
Transform cachedLeftHandCustomPose;
|
||||
Transform[] cachedCustomLeftHandJoints;
|
||||
ovrAvatarTransform[] cachedLeftHandTransforms;
|
||||
Transform cachedRightHandCustomPose;
|
||||
Transform[] cachedCustomRightHandJoints;
|
||||
ovrAvatarTransform[] cachedRightHandTransforms;
|
||||
|
||||
|
||||
private Vector4 clothingAlphaOffset = new Vector4(0f, 0f, 0f, 1f);
|
||||
private UInt64 clothingAlphaTexture = 0;
|
||||
|
||||
public class PacketEventArgs : EventArgs
|
||||
{
|
||||
public readonly OvrAvatarPacket Packet;
|
||||
public PacketEventArgs(OvrAvatarPacket packet)
|
||||
{
|
||||
Packet = packet;
|
||||
}
|
||||
}
|
||||
|
||||
public PacketRecordSettings PacketSettings = new PacketRecordSettings();
|
||||
|
||||
OvrAvatarPacket CurrentUnityPacket;
|
||||
|
||||
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"
|
||||
}
|
||||
};
|
||||
|
||||
#if UNITY_ANDROID
|
||||
internal ovrAvatarAssetLevelOfDetail LevelOfDetail = ovrAvatarAssetLevelOfDetail.Medium;
|
||||
#else
|
||||
internal ovrAvatarAssetLevelOfDetail LevelOfDetail = ovrAvatarAssetLevelOfDetail.Highest;
|
||||
#endif
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (sdkAvatar != IntPtr.Zero)
|
||||
{
|
||||
CAPI.ovrAvatar_Destroy(sdkAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
public EventHandler<PacketEventArgs> PacketRecorded;
|
||||
|
||||
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 void AddAvatarComponent(GameObject componentObject, ovrAvatarComponent component)
|
||||
{
|
||||
OvrAvatarComponent ovrComponent = componentObject.AddComponent<OvrAvatarComponent>();
|
||||
trackedComponents.Add(component.name, ovrComponent);
|
||||
|
||||
if (ovrComponent.name == "body")
|
||||
{
|
||||
ovrComponent.ClothingAlphaOffset = clothingAlphaOffset;
|
||||
ovrComponent.ClothingAlphaTexture = clothingAlphaTexture;
|
||||
}
|
||||
|
||||
AddRenderParts(ovrComponent, component, componentObject.transform);
|
||||
}
|
||||
|
||||
private OvrAvatarSkinnedMeshRenderComponent AddSkinnedMeshRenderComponent(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRender skinnedMeshRender)
|
||||
{
|
||||
OvrAvatarSkinnedMeshRenderComponent skinnedMeshRenderer = gameObject.AddComponent<OvrAvatarSkinnedMeshRenderComponent>();
|
||||
skinnedMeshRenderer.Initialize(skinnedMeshRender, SurfaceShader, SurfaceShaderSelfOccluding, ThirdPersonLayer.layerIndex, FirstPersonLayer.layerIndex, renderPartCount++);
|
||||
return skinnedMeshRenderer;
|
||||
}
|
||||
|
||||
private OvrAvatarSkinnedMeshRenderPBSComponent AddSkinnedMeshRenderPBSComponent(GameObject gameObject, ovrAvatarRenderPart_SkinnedMeshRenderPBS skinnedMeshRenderPBS)
|
||||
{
|
||||
OvrAvatarSkinnedMeshRenderPBSComponent skinnedMeshRenderer = gameObject.AddComponent<OvrAvatarSkinnedMeshRenderPBSComponent>();
|
||||
skinnedMeshRenderer.Initialize(skinnedMeshRenderPBS, SurfaceShaderPBS, ThirdPersonLayer.layerIndex, FirstPersonLayer.layerIndex, renderPartCount++);
|
||||
return skinnedMeshRenderer;
|
||||
}
|
||||
|
||||
private OvrAvatarSkinnedMeshPBSV2RenderComponent AddSkinnedMeshRenderPBSV2Component(
|
||||
IntPtr renderPart,
|
||||
GameObject gameObject,
|
||||
ovrAvatarRenderPart_SkinnedMeshRenderPBS_V2 skinnedMeshRenderPBSV2,
|
||||
OvrAvatarMaterialManager materialManager)
|
||||
{
|
||||
OvrAvatarSkinnedMeshPBSV2RenderComponent skinnedMeshRenderer = gameObject.AddComponent<OvrAvatarSkinnedMeshPBSV2RenderComponent>();
|
||||
skinnedMeshRenderer.Initialize(
|
||||
renderPart,
|
||||
skinnedMeshRenderPBSV2,
|
||||
materialManager,
|
||||
ThirdPersonLayer.layerIndex,
|
||||
FirstPersonLayer.layerIndex,
|
||||
renderPartCount++,
|
||||
gameObject.name.Contains("body") && CombineMeshes,
|
||||
LevelOfDetail);
|
||||
|
||||
return skinnedMeshRenderer;
|
||||
}
|
||||
|
||||
private OvrAvatarProjectorRenderComponent AddProjectorRenderComponent(GameObject gameObject, ovrAvatarRenderPart_ProjectorRender projectorRender)
|
||||
{
|
||||
ovrAvatarComponent component = CAPI.ovrAvatarComponent_Get(sdkAvatar, projectorRender.componentIndex);
|
||||
OvrAvatarComponent ovrComponent;
|
||||
if (trackedComponents.TryGetValue(component.name, out ovrComponent))
|
||||
{
|
||||
if (projectorRender.renderPartIndex < ovrComponent.RenderParts.Count)
|
||||
{
|
||||
OvrAvatarRenderComponent targetRenderPart = ovrComponent.RenderParts[(int)projectorRender.renderPartIndex];
|
||||
OvrAvatarProjectorRenderComponent projectorComponent = gameObject.AddComponent<OvrAvatarProjectorRenderComponent>();
|
||||
projectorComponent.InitializeProjectorRender(projectorRender, SurfaceShader, targetRenderPart);
|
||||
return projectorComponent;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
private void UpdateAvatarComponent(ovrAvatarComponent component)
|
||||
{
|
||||
OvrAvatarComponent ovrComponent;
|
||||
if (!trackedComponents.TryGetValue(component.name, out ovrComponent))
|
||||
{
|
||||
throw new Exception(string.Format("trackedComponents didn't have {0}", component.name));
|
||||
}
|
||||
|
||||
ovrComponent.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 = -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 void RemoveAvatarComponent(string name)
|
||||
{
|
||||
OvrAvatarComponent componentObject;
|
||||
trackedComponents.TryGetValue(name, out componentObject);
|
||||
Destroy(componentObject.gameObject);
|
||||
trackedComponents.Remove(name);
|
||||
}
|
||||
|
||||
private void UpdateSDKAvatarUnityState()
|
||||
{
|
||||
//Iterate through all the render components
|
||||
UInt32 componentCount = CAPI.ovrAvatarComponent_Count(sdkAvatar);
|
||||
HashSet<string> componentsThisRun = new HashSet<string>();
|
||||
for (UInt32 i = 0; i < componentCount; i++)
|
||||
{
|
||||
IntPtr ptr = CAPI.ovrAvatarComponent_Get_Native(sdkAvatar, i);
|
||||
ovrAvatarComponent component = (ovrAvatarComponent)Marshal.PtrToStructure(ptr, typeof(ovrAvatarComponent));
|
||||
componentsThisRun.Add(component.name);
|
||||
if (!trackedComponents.ContainsKey(component.name))
|
||||
{
|
||||
GameObject componentObject = null;
|
||||
Type specificType = null;
|
||||
if ((Capabilities & ovrAvatarCapabilities.Base) != 0)
|
||||
{
|
||||
ovrAvatarBaseComponent? baseComponent = CAPI.ovrAvatarPose_GetBaseComponent(sdkAvatar);
|
||||
if (baseComponent.HasValue && ptr == baseComponent.Value.renderComponent)
|
||||
{
|
||||
specificType = typeof(OvrAvatarBase);
|
||||
if (Base != null)
|
||||
{
|
||||
componentObject = Base.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (specificType == null && (Capabilities & ovrAvatarCapabilities.Body) != 0)
|
||||
{
|
||||
ovrAvatarBodyComponent? bodyComponent = CAPI.ovrAvatarPose_GetBodyComponent(sdkAvatar);
|
||||
if (bodyComponent.HasValue && ptr == bodyComponent.Value.renderComponent)
|
||||
{
|
||||
specificType = typeof(OvrAvatarBody);
|
||||
if (Body != null)
|
||||
{
|
||||
componentObject = Body.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (specificType == null && (Capabilities & ovrAvatarCapabilities.Hands) != 0)
|
||||
{
|
||||
ovrAvatarControllerComponent? controllerComponent = CAPI.ovrAvatarPose_GetLeftControllerComponent(sdkAvatar);
|
||||
if (specificType == null && controllerComponent.HasValue && ptr == controllerComponent.Value.renderComponent)
|
||||
{
|
||||
specificType = typeof(OvrAvatarTouchController);
|
||||
if (ControllerLeft != null)
|
||||
{
|
||||
componentObject = ControllerLeft.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
controllerComponent = CAPI.ovrAvatarPose_GetRightControllerComponent(sdkAvatar);
|
||||
if (specificType == null && controllerComponent.HasValue && ptr == controllerComponent.Value.renderComponent)
|
||||
{
|
||||
specificType = typeof(OvrAvatarTouchController);
|
||||
if (ControllerRight != null)
|
||||
{
|
||||
componentObject = ControllerRight.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
ovrAvatarHandComponent? handComponent = CAPI.ovrAvatarPose_GetLeftHandComponent(sdkAvatar);
|
||||
if (specificType == null && handComponent.HasValue && ptr == handComponent.Value.renderComponent)
|
||||
{
|
||||
specificType = typeof(OvrAvatarHand);
|
||||
if (HandLeft != null)
|
||||
{
|
||||
componentObject = HandLeft.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
handComponent = CAPI.ovrAvatarPose_GetRightHandComponent(sdkAvatar);
|
||||
if (specificType == null && handComponent.HasValue && ptr == handComponent.Value.renderComponent)
|
||||
{
|
||||
specificType = typeof(OvrAvatarHand);
|
||||
if (HandRight != null)
|
||||
{
|
||||
componentObject = HandRight.gameObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is an unknown type, just create an object for the rendering
|
||||
if (componentObject == null && specificType == null)
|
||||
{
|
||||
componentObject = new GameObject();
|
||||
componentObject.name = component.name;
|
||||
componentObject.transform.SetParent(transform);
|
||||
}
|
||||
if (componentObject != null)
|
||||
{
|
||||
AddAvatarComponent(componentObject, component);
|
||||
}
|
||||
}
|
||||
UpdateAvatarComponent(component);
|
||||
}
|
||||
HashSet<string> deletableNames = new HashSet<string>(trackedComponents.Keys);
|
||||
deletableNames.ExceptWith(componentsThisRun);
|
||||
//deletableNames contains the name of all components which are tracked and were
|
||||
//not present in this run
|
||||
foreach (var name in deletableNames)
|
||||
{
|
||||
RemoveAvatarComponent(name);
|
||||
}
|
||||
|
||||
UpdateVoiceBehavior();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
#if UNITY_ANDROID
|
||||
Capabilities &= ~ovrAvatarCapabilities.BodyTilt;
|
||||
#endif
|
||||
sdkAvatar = CAPI.ovrAvatar_Create(avatarSpecification, Capabilities);
|
||||
ShowLeftController(showLeftController);
|
||||
ShowRightController(showRightController);
|
||||
|
||||
//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 !UNITY_ANDROID
|
||||
if (CombineMeshes)
|
||||
{
|
||||
CombineMeshes = false;
|
||||
AvatarLogger.Log("Combine Meshes Currently Only Supported On Android");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !UNITY_5_5_OR_NEWER
|
||||
if (CombineMeshes)
|
||||
{
|
||||
CombineMeshes = false;
|
||||
AvatarLogger.LogWarning("Unity Version too old to use Combined Mesh Shader, required 5.5.0+");
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
oculusUserIDInternal = UInt64.Parse(oculusUserID);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
oculusUserIDInternal = 0;
|
||||
|
||||
AvatarLogger.LogWarning("Invalid Oculus User ID Format");
|
||||
}
|
||||
|
||||
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: " + ForceMobileTextureFormat);
|
||||
AvatarLogger.Log(AvatarLogger.Tab + "Oculus User ID: " + oculusUserIDInternal);
|
||||
|
||||
ShowLeftController(StartWithControllers);
|
||||
ShowRightController(StartWithControllers);
|
||||
OvrAvatarSDKManager.Instance.RequestAvatarSpecification(
|
||||
oculusUserIDInternal,
|
||||
this.AvatarSpecificationCallback,
|
||||
CombineMeshes,
|
||||
LevelOfDetail,
|
||||
ForceMobileTextureFormat);
|
||||
|
||||
WaitingForCombinedMesh = CombineMeshes;
|
||||
Driver.Mode = UseSDKPackets ? OvrAvatarDriver.PacketMode.SDK : OvrAvatarDriver.PacketMode.Unity;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
UpdateSDKAvatarUnityState();
|
||||
UpdateCustomPoses();
|
||||
|
||||
if (!assetsFinishedLoading)
|
||||
{
|
||||
AssetsDoneLoading.Invoke();
|
||||
assetsFinishedLoading = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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.ProjectorRender:
|
||||
ovrRenderPart = AddProjectorRenderComponent(renderPartObject, CAPI.ovrAvatarRenderPart_GetProjectorRender(renderPart));
|
||||
break;
|
||||
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2:
|
||||
{
|
||||
OvrAvatarMaterialManager materialManager = null;
|
||||
|
||||
if (ovrComponent.name == "body")
|
||||
{
|
||||
materialManager = DefaultBodyMaterialManager;
|
||||
}
|
||||
else if( ovrComponent.name.Contains("hand"))
|
||||
{
|
||||
materialManager = DefaultHandMaterialManager;
|
||||
}
|
||||
|
||||
ovrRenderPart = AddSkinnedMeshRenderPBSV2Component(
|
||||
renderPart,
|
||||
renderPartObject,
|
||||
CAPI.ovrAvatarRenderPart_GetSkinnedMeshRenderPBSV2(renderPart),
|
||||
materialManager);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(string.Format("Unsupported render part type: {0}", type.ToString()));
|
||||
}
|
||||
|
||||
ovrComponent.RenderParts.Add(ovrRenderPart);
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshBodyParts()
|
||||
{
|
||||
OvrAvatarComponent component;
|
||||
if (trackedComponents.TryGetValue("body", out component) && Body != null)
|
||||
{
|
||||
foreach (var part in component.RenderParts)
|
||||
{
|
||||
Destroy(part.gameObject);
|
||||
}
|
||||
|
||||
component.RenderParts.Clear();
|
||||
|
||||
ovrAvatarBodyComponent? sdkBodyComponent = CAPI.ovrAvatarPose_GetBodyComponent(sdkAvatar);
|
||||
if (sdkBodyComponent != null)
|
||||
{
|
||||
ovrAvatarComponent sdKComponent = (ovrAvatarComponent)Marshal.PtrToStructure(sdkBodyComponent.Value.renderComponent, typeof(ovrAvatarComponent));
|
||||
AddRenderParts(component, sdKComponent, Body.gameObject.transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public Transform GetMouthTransform()
|
||||
{
|
||||
OvrAvatarComponent component;
|
||||
if (trackedComponents.TryGetValue("voice", out component))
|
||||
{
|
||||
if (component.RenderParts.Count > 0)
|
||||
{
|
||||
return component.RenderParts[0].transform;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
OvrAvatarComponent component;
|
||||
if (trackedComponents.TryGetValue("body", out component))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatar.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatar.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00f3402a2ea5bff4880c0313515240cd
|
||||
timeCreated: 1464046614
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
5
Assets/Oculus/Avatar/Scripts/OvrAvatarAsset.cs
Normal file
5
Assets/Oculus/Avatar/Scripts/OvrAvatarAsset.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
using System;
|
||||
|
||||
public class OvrAvatarAsset {
|
||||
public UInt64 assetID;
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarAsset.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarAsset.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7045bb39115f484a89ecaa778a2a60f
|
||||
timeCreated: 1475521356
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
219
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetMesh.cs
Normal file
219
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetMesh.cs
Normal file
@@ -0,0 +1,219 @@
|
||||
using System;
|
||||
using Oculus.Avatar;
|
||||
using UnityEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public class OvrAvatarAssetMesh : OvrAvatarAsset
|
||||
{
|
||||
public Mesh mesh;
|
||||
private ovrAvatarSkinnedMeshPose skinnedBindPose;
|
||||
public string[] jointNames;
|
||||
|
||||
public OvrAvatarAssetMesh(UInt64 _assetId, IntPtr asset, ovrAvatarAssetType meshType)
|
||||
{
|
||||
assetID = _assetId;
|
||||
mesh = new Mesh();
|
||||
mesh.name = "Procedural Geometry for asset " + _assetId;
|
||||
|
||||
switch (meshType)
|
||||
{
|
||||
case ovrAvatarAssetType.Mesh:
|
||||
{
|
||||
ovrAvatarMeshAssetData meshAssetData = CAPI.ovrAvatarAsset_GetMeshData(asset);
|
||||
|
||||
AvatarLogger.Log(
|
||||
"OvrAvatarAssetMesh: "
|
||||
+ _assetId
|
||||
+ " "
|
||||
+ meshType.ToString()
|
||||
+ " VertexCount:"
|
||||
+ meshAssetData.vertexCount);
|
||||
|
||||
|
||||
long vertexCount = (long)meshAssetData.vertexCount;
|
||||
Vector3[] vertices = new Vector3[vertexCount];
|
||||
Vector3[] normals = new Vector3[vertexCount];
|
||||
Vector4[] tangents = new Vector4[vertexCount];
|
||||
Vector2[] uv = new Vector2[vertexCount];
|
||||
Color[] colors = new Color[vertexCount];
|
||||
BoneWeight[] boneWeights = new BoneWeight[vertexCount];
|
||||
|
||||
long vertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarMeshVertex));
|
||||
long vertexBufferStart = meshAssetData.vertexBuffer.ToInt64();
|
||||
|
||||
for (long i = 0; i < vertexCount; i++)
|
||||
{
|
||||
long offset = vertexSize * i;
|
||||
|
||||
ovrAvatarMeshVertex vertex = (ovrAvatarMeshVertex)Marshal.PtrToStructure(new IntPtr(vertexBufferStart + offset), typeof(ovrAvatarMeshVertex));
|
||||
vertices[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
|
||||
normals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
|
||||
tangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz, vertex.tw);
|
||||
uv[i] = new Vector2(vertex.u, vertex.v);
|
||||
colors[i] = new Color(0, 0, 0, 1);
|
||||
|
||||
boneWeights[i].boneIndex0 = vertex.blendIndices[0];
|
||||
boneWeights[i].boneIndex1 = vertex.blendIndices[1];
|
||||
boneWeights[i].boneIndex2 = vertex.blendIndices[2];
|
||||
boneWeights[i].boneIndex3 = vertex.blendIndices[3];
|
||||
boneWeights[i].weight0 = vertex.blendWeights[0];
|
||||
boneWeights[i].weight1 = vertex.blendWeights[1];
|
||||
boneWeights[i].weight2 = vertex.blendWeights[2];
|
||||
boneWeights[i].weight3 = vertex.blendWeights[3];
|
||||
}
|
||||
|
||||
mesh.vertices = vertices;
|
||||
mesh.normals = normals;
|
||||
mesh.uv = uv;
|
||||
mesh.tangents = tangents;
|
||||
mesh.boneWeights = boneWeights;
|
||||
mesh.colors = colors;
|
||||
|
||||
skinnedBindPose = meshAssetData.skinnedBindPose;
|
||||
|
||||
ulong indexCount = meshAssetData.indexCount;
|
||||
Int16[] indices = new Int16[indexCount];
|
||||
IntPtr indexBufferPtr = meshAssetData.indexBuffer;
|
||||
Marshal.Copy(indexBufferPtr, indices, 0, (int)indexCount);
|
||||
Int32[] triangles = new Int32[indexCount];
|
||||
for (ulong i = 0; i < indexCount; i += 3)
|
||||
{
|
||||
triangles[i + 2] = (Int32)indices[i];
|
||||
triangles[i + 1] = (Int32)indices[i + 1];
|
||||
triangles[i] = (Int32)indices[i + 2];
|
||||
}
|
||||
mesh.triangles = triangles;
|
||||
|
||||
UInt32 jointCount = skinnedBindPose.jointCount;
|
||||
jointNames = new string[jointCount];
|
||||
for (UInt32 i = 0; i < jointCount; i++)
|
||||
{
|
||||
jointNames[i] = Marshal.PtrToStringAnsi(skinnedBindPose.jointNames[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ovrAvatarAssetType.CombinedMesh:
|
||||
{
|
||||
ovrAvatarMeshAssetDataV2 meshAssetData = CAPI.ovrAvatarAsset_GetCombinedMeshData(asset);
|
||||
|
||||
AvatarLogger.Log(
|
||||
"OvrAvatarAssetMesh: "
|
||||
+ _assetId
|
||||
+ " "
|
||||
+ meshType.ToString()
|
||||
+ " VertexCount:"
|
||||
+ meshAssetData.vertexCount);
|
||||
|
||||
long vertexCount = (long)meshAssetData.vertexCount;
|
||||
Vector3[] vertices = new Vector3[vertexCount];
|
||||
Vector3[] normals = new Vector3[vertexCount];
|
||||
Vector4[] tangents = new Vector4[vertexCount];
|
||||
Vector2[] uv = new Vector2[vertexCount];
|
||||
Color[] colors = new Color[vertexCount];
|
||||
BoneWeight[] boneWeights = new BoneWeight[vertexCount];
|
||||
|
||||
long vertexSize = (long)Marshal.SizeOf(typeof(ovrAvatarMeshVertexV2));
|
||||
long vertexBufferStart = meshAssetData.vertexBuffer.ToInt64();
|
||||
|
||||
for (long i = 0; i < vertexCount; i++)
|
||||
{
|
||||
long offset = vertexSize * i;
|
||||
|
||||
ovrAvatarMeshVertexV2 vertex = (ovrAvatarMeshVertexV2)Marshal.PtrToStructure(new IntPtr(vertexBufferStart + offset), typeof(ovrAvatarMeshVertexV2));
|
||||
vertices[i] = new Vector3(vertex.x, vertex.y, -vertex.z);
|
||||
normals[i] = new Vector3(vertex.nx, vertex.ny, -vertex.nz);
|
||||
tangents[i] = new Vector4(vertex.tx, vertex.ty, -vertex.tz, vertex.tw);
|
||||
uv[i] = new Vector2(vertex.u, vertex.v);
|
||||
colors[i] = new Color(vertex.r, vertex.g, vertex.b, vertex.a);
|
||||
|
||||
boneWeights[i].boneIndex0 = vertex.blendIndices[0];
|
||||
boneWeights[i].boneIndex1 = vertex.blendIndices[1];
|
||||
boneWeights[i].boneIndex2 = vertex.blendIndices[2];
|
||||
boneWeights[i].boneIndex3 = vertex.blendIndices[3];
|
||||
boneWeights[i].weight0 = vertex.blendWeights[0];
|
||||
boneWeights[i].weight1 = vertex.blendWeights[1];
|
||||
boneWeights[i].weight2 = vertex.blendWeights[2];
|
||||
boneWeights[i].weight3 = vertex.blendWeights[3];
|
||||
}
|
||||
|
||||
mesh.vertices = vertices;
|
||||
mesh.normals = normals;
|
||||
mesh.uv = uv;
|
||||
mesh.tangents = tangents;
|
||||
mesh.boneWeights = boneWeights;
|
||||
mesh.colors = colors;
|
||||
|
||||
skinnedBindPose = meshAssetData.skinnedBindPose;
|
||||
|
||||
ulong indexCount = meshAssetData.indexCount;
|
||||
Int16[] indices = new Int16[indexCount];
|
||||
IntPtr indexBufferPtr = meshAssetData.indexBuffer;
|
||||
Marshal.Copy(indexBufferPtr, indices, 0, (int)indexCount);
|
||||
Int32[] triangles = new Int32[indexCount];
|
||||
for (ulong i = 0; i < indexCount; i += 3)
|
||||
{
|
||||
triangles[i + 2] = (Int32)indices[i];
|
||||
triangles[i + 1] = (Int32)indices[i + 1];
|
||||
triangles[i] = (Int32)indices[i + 2];
|
||||
}
|
||||
mesh.triangles = triangles;
|
||||
|
||||
UInt32 jointCount = skinnedBindPose.jointCount;
|
||||
jointNames = new string[jointCount];
|
||||
for (UInt32 i = 0; i < jointCount; i++)
|
||||
{
|
||||
jointNames[i] = Marshal.PtrToStringAnsi(skinnedBindPose.jointNames[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Bad Mesh Asset Type");
|
||||
}
|
||||
}
|
||||
|
||||
public SkinnedMeshRenderer CreateSkinnedMeshRendererOnObject(GameObject target)
|
||||
{
|
||||
SkinnedMeshRenderer skinnedMeshRenderer = target.AddComponent<SkinnedMeshRenderer>();
|
||||
skinnedMeshRenderer.sharedMesh = mesh;
|
||||
mesh.name = "AvatarMesh_" + assetID;
|
||||
UInt32 jointCount = skinnedBindPose.jointCount;
|
||||
GameObject[] bones = new GameObject[jointCount];
|
||||
Transform[] boneTransforms = new Transform[jointCount];
|
||||
Matrix4x4[] bindPoses = new Matrix4x4[jointCount];
|
||||
for (UInt32 i = 0; i < jointCount; i++)
|
||||
{
|
||||
bones[i] = new GameObject();
|
||||
boneTransforms[i] = bones[i].transform;
|
||||
bones[i].name = jointNames[i];
|
||||
int parentIndex = skinnedBindPose.jointParents[i];
|
||||
if (parentIndex == -1)
|
||||
{
|
||||
bones[i].transform.parent = skinnedMeshRenderer.transform;
|
||||
skinnedMeshRenderer.rootBone = bones[i].transform;
|
||||
}
|
||||
else
|
||||
{
|
||||
bones[i].transform.parent = bones[parentIndex].transform;
|
||||
}
|
||||
|
||||
// Set the position relative to the parent
|
||||
Vector3 position = skinnedBindPose.jointTransform[i].position;
|
||||
position.z = -position.z;
|
||||
bones[i].transform.localPosition = position;
|
||||
|
||||
Quaternion orientation = skinnedBindPose.jointTransform[i].orientation;
|
||||
orientation.x = -orientation.x;
|
||||
orientation.y = -orientation.y;
|
||||
bones[i].transform.localRotation = orientation;
|
||||
|
||||
bones[i].transform.localScale = skinnedBindPose.jointTransform[i].scale;
|
||||
|
||||
bindPoses[i] = bones[i].transform.worldToLocalMatrix * skinnedMeshRenderer.transform.localToWorldMatrix;
|
||||
}
|
||||
skinnedMeshRenderer.bones = boneTransforms;
|
||||
mesh.bindposes = bindPoses;
|
||||
return skinnedMeshRenderer;
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetMesh.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetMesh.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80be643e69fa4a4478a5cb27a190bbd2
|
||||
timeCreated: 1475522461
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
58
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetTexture.cs
Normal file
58
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetTexture.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using Oculus.Avatar;
|
||||
using UnityEngine;
|
||||
|
||||
public class OvrAvatarAssetTexture : OvrAvatarAsset {
|
||||
public Texture2D texture;
|
||||
|
||||
private const int ASTCHeaderSize = 16;
|
||||
|
||||
public OvrAvatarAssetTexture(UInt64 _assetId, IntPtr asset) {
|
||||
assetID = _assetId;
|
||||
ovrAvatarTextureAssetData textureAssetData = CAPI.ovrAvatarAsset_GetTextureData(asset);
|
||||
TextureFormat format;
|
||||
IntPtr textureData = textureAssetData.textureData;
|
||||
int textureDataSize = (int)textureAssetData.textureDataSize;
|
||||
|
||||
AvatarLogger.Log(
|
||||
"OvrAvatarAssetTexture - "
|
||||
+ _assetId
|
||||
+ ": "
|
||||
+ textureAssetData.format.ToString()
|
||||
+ " "
|
||||
+ textureAssetData.sizeX
|
||||
+ "x"
|
||||
+ textureAssetData.sizeY);
|
||||
|
||||
switch (textureAssetData.format)
|
||||
{
|
||||
case ovrAvatarTextureFormat.RGB24:
|
||||
format = TextureFormat.RGB24;
|
||||
break;
|
||||
case ovrAvatarTextureFormat.DXT1:
|
||||
format = TextureFormat.DXT1;
|
||||
break;
|
||||
case ovrAvatarTextureFormat.DXT5:
|
||||
format = TextureFormat.DXT5;
|
||||
break;
|
||||
case ovrAvatarTextureFormat.ASTC_RGB_6x6:
|
||||
format = TextureFormat.ASTC_RGB_6x6;
|
||||
textureData = new IntPtr(textureData.ToInt64() + ASTCHeaderSize);
|
||||
textureDataSize -= ASTCHeaderSize;
|
||||
break;
|
||||
case ovrAvatarTextureFormat.ASTC_RGB_6x6_MIPMAPS:
|
||||
format = TextureFormat.ASTC_RGB_6x6;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(
|
||||
string.Format("Unsupported texture format {0}",
|
||||
textureAssetData.format.ToString()));
|
||||
}
|
||||
texture = new Texture2D(
|
||||
(int)textureAssetData.sizeX, (int)textureAssetData.sizeY,
|
||||
format, textureAssetData.mipCount > 1,
|
||||
QualitySettings.activeColorSpace == ColorSpace.Gamma ? false : true);
|
||||
texture.LoadRawTextureData(textureData, textureDataSize);
|
||||
texture.Apply(true, false);
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetTexture.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarAssetTexture.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a3167eed50e56346be5b1cc65ad7226
|
||||
timeCreated: 1475522480
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Avatar/Scripts/OvrAvatarBase.cs
Normal file
8
Assets/Oculus/Avatar/Scripts/OvrAvatarBase.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
public class OvrAvatarBase : MonoBehaviour
|
||||
{
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarBase.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarBase.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a0e33623ec5372748b5703f61a4df82d
|
||||
timeCreated: 1477606822
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
11
Assets/Oculus/Avatar/Scripts/OvrAvatarBody.cs
Normal file
11
Assets/Oculus/Avatar/Scripts/OvrAvatarBody.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
public class OvrAvatarBody : MonoBehaviour
|
||||
{
|
||||
public virtual void UpdatePose(float voiceAmplitude)
|
||||
{
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarBody.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarBody.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb7a6650b6cb46545967d3b380b7396c
|
||||
timeCreated: 1466814542
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
153
Assets/Oculus/Avatar/Scripts/OvrAvatarComponent.cs
Normal file
153
Assets/Oculus/Avatar/Scripts/OvrAvatarComponent.cs
Normal file
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Avatar;
|
||||
using System.Threading;
|
||||
|
||||
public class OvrAvatarComponent : MonoBehaviour
|
||||
{
|
||||
|
||||
public static readonly string[] LayerKeywords = new[] { "LAYERS_0", "LAYERS_1", "LAYERS_2", "LAYERS_3", "LAYERS_4", "LAYERS_5", "LAYERS_6", "LAYERS_7", "LAYERS_8", };
|
||||
public static readonly string[] LayerSampleModeParameters = new[] { "_LayerSampleMode0", "_LayerSampleMode1", "_LayerSampleMode2", "_LayerSampleMode3", "_LayerSampleMode4", "_LayerSampleMode5", "_LayerSampleMode6", "_LayerSampleMode7", };
|
||||
public static readonly string[] LayerBlendModeParameters = new[] { "_LayerBlendMode0", "_LayerBlendMode1", "_LayerBlendMode2", "_LayerBlendMode3", "_LayerBlendMode4", "_LayerBlendMode5", "_LayerBlendMode6", "_LayerBlendMode7", };
|
||||
public static readonly string[] LayerMaskTypeParameters = new[] { "_LayerMaskType0", "_LayerMaskType1", "_LayerMaskType2", "_LayerMaskType3", "_LayerMaskType4", "_LayerMaskType5", "_LayerMaskType6", "_LayerMaskType7", };
|
||||
public static readonly string[] LayerColorParameters = new[] { "_LayerColor0", "_LayerColor1", "_LayerColor2", "_LayerColor3", "_LayerColor4", "_LayerColor5", "_LayerColor6", "_LayerColor7", };
|
||||
public static readonly string[] LayerSurfaceParameters = new[] { "_LayerSurface0", "_LayerSurface1", "_LayerSurface2", "_LayerSurface3", "_LayerSurface4", "_LayerSurface5", "_LayerSurface6", "_LayerSurface7", };
|
||||
public static readonly string[] LayerSampleParametersParameters = new[] { "_LayerSampleParameters0", "_LayerSampleParameters1", "_LayerSampleParameters2", "_LayerSampleParameters3", "_LayerSampleParameters4", "_LayerSampleParameters5", "_LayerSampleParameters6", "_LayerSampleParameters7", };
|
||||
public static readonly string[] LayerMaskParametersParameters = new[] { "_LayerMaskParameters0", "_LayerMaskParameters1", "_LayerMaskParameters2", "_LayerMaskParameters3", "_LayerMaskParameters4", "_LayerMaskParameters5", "_LayerMaskParameters6", "_LayerMaskParameters7", };
|
||||
public static readonly string[] LayerMaskAxisParameters = new[] { "_LayerMaskAxis0", "_LayerMaskAxis1", "_LayerMaskAxis2", "_LayerMaskAxis3", "_LayerMaskAxis4", "_LayerMaskAxis5", "_LayerMaskAxis6", "_LayerMaskAxis7", };
|
||||
|
||||
private Dictionary<Material, ovrAvatarMaterialState> materialStates = new Dictionary<Material, ovrAvatarMaterialState>();
|
||||
public List<OvrAvatarRenderComponent> RenderParts = new List<OvrAvatarRenderComponent>();
|
||||
|
||||
private bool DrawSkeleton = false;
|
||||
private bool FirstMaterialUpdate = true;
|
||||
|
||||
public ulong ClothingAlphaTexture = 0;
|
||||
public Vector4 ClothingAlphaOffset;
|
||||
|
||||
public void UpdateAvatar(ovrAvatarComponent component, OvrAvatar avatar)
|
||||
{
|
||||
OvrAvatar.ConvertTransform(component.transform, transform);
|
||||
|
||||
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.SkinnedMeshRender:
|
||||
((OvrAvatarSkinnedMeshRenderComponent)renderComponent).UpdateSkinnedMeshRender(this, avatar, renderPart);
|
||||
break;
|
||||
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS:
|
||||
((OvrAvatarSkinnedMeshRenderPBSComponent)renderComponent).UpdateSkinnedMeshRenderPBS(avatar, renderPart, renderComponent.mesh.sharedMaterial);
|
||||
break;
|
||||
case ovrAvatarRenderPartType.ProjectorRender:
|
||||
((OvrAvatarProjectorRenderComponent)renderComponent).UpdateProjectorRender(this, CAPI.ovrAvatarRenderPart_GetProjectorRender(renderPart));
|
||||
break;
|
||||
case ovrAvatarRenderPartType.SkinnedMeshRenderPBS_V2:
|
||||
((OvrAvatarSkinnedMeshPBSV2RenderComponent)renderComponent).UpdateSkinnedMeshRender(this, avatar, renderPart);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateActive(OvrAvatar avatar, ovrAvatarVisibilityFlags mask)
|
||||
{
|
||||
bool active = avatar.ShowFirstPerson && (mask & ovrAvatarVisibilityFlags.FirstPerson) != 0;
|
||||
active |= avatar.ShowThirdPerson && (mask & ovrAvatarVisibilityFlags.ThirdPerson) != 0;
|
||||
this.gameObject.SetActive(active);
|
||||
}
|
||||
|
||||
public void UpdateAvatarMaterial(Material mat, ovrAvatarMaterialState matState)
|
||||
{
|
||||
mat.SetColor("_BaseColor", matState.baseColor);
|
||||
mat.SetInt("_BaseMaskType", (int)matState.baseMaskType);
|
||||
mat.SetVector("_BaseMaskParameters", matState.baseMaskParameters);
|
||||
mat.SetVector("_BaseMaskAxis", matState.baseMaskAxis);
|
||||
|
||||
if (matState.alphaMaskTextureID != 0)
|
||||
{
|
||||
mat.SetTexture("_AlphaMask", GetLoadedTexture(matState.alphaMaskTextureID));
|
||||
mat.SetTextureScale("_AlphaMask", new Vector2(matState.alphaMaskScaleOffset.x, matState.alphaMaskScaleOffset.y));
|
||||
mat.SetTextureOffset("_AlphaMask", new Vector2(matState.alphaMaskScaleOffset.z, matState.alphaMaskScaleOffset.w));
|
||||
}
|
||||
|
||||
if (ClothingAlphaTexture != 0)
|
||||
{
|
||||
mat.EnableKeyword("VERTALPHA_ON");
|
||||
mat.SetTexture("_AlphaMask2", GetLoadedTexture(ClothingAlphaTexture));
|
||||
mat.SetTextureScale("_AlphaMask2", new Vector2(ClothingAlphaOffset.x, ClothingAlphaOffset.y));
|
||||
mat.SetTextureOffset("_AlphaMask2", new Vector2(ClothingAlphaOffset.z, ClothingAlphaOffset.w));
|
||||
}
|
||||
|
||||
if (matState.normalMapTextureID != 0)
|
||||
{
|
||||
mat.EnableKeyword("NORMAL_MAP_ON");
|
||||
mat.SetTexture("_NormalMap", GetLoadedTexture(matState.normalMapTextureID));
|
||||
mat.SetTextureScale("_NormalMap", new Vector2(matState.normalMapScaleOffset.x, matState.normalMapScaleOffset.y));
|
||||
mat.SetTextureOffset("_NormalMap", new Vector2(matState.normalMapScaleOffset.z, matState.normalMapScaleOffset.w));
|
||||
}
|
||||
if (matState.parallaxMapTextureID != 0)
|
||||
{
|
||||
mat.SetTexture("_ParallaxMap", GetLoadedTexture(matState.parallaxMapTextureID));
|
||||
mat.SetTextureScale("_ParallaxMap", new Vector2(matState.parallaxMapScaleOffset.x, matState.parallaxMapScaleOffset.y));
|
||||
mat.SetTextureOffset("_ParallaxMap", new Vector2(matState.parallaxMapScaleOffset.z, matState.parallaxMapScaleOffset.w));
|
||||
}
|
||||
if (matState.roughnessMapTextureID != 0)
|
||||
{
|
||||
mat.EnableKeyword("ROUGHNESS_ON");
|
||||
mat.SetTexture("_RoughnessMap", GetLoadedTexture(matState.roughnessMapTextureID));
|
||||
mat.SetTextureScale("_RoughnessMap", new Vector2(matState.roughnessMapScaleOffset.x, matState.roughnessMapScaleOffset.y));
|
||||
mat.SetTextureOffset("_RoughnessMap", new Vector2(matState.roughnessMapScaleOffset.z, matState.roughnessMapScaleOffset.w));
|
||||
}
|
||||
mat.EnableKeyword(LayerKeywords[matState.layerCount]);
|
||||
for (ulong layerIndex = 0; layerIndex < matState.layerCount; layerIndex++)
|
||||
{
|
||||
ovrAvatarMaterialLayerState layer = matState.layers[layerIndex];
|
||||
|
||||
mat.SetInt(LayerSampleModeParameters[layerIndex], (int)layer.sampleMode);
|
||||
mat.SetInt(LayerBlendModeParameters[layerIndex], (int)layer.blendMode);
|
||||
mat.SetInt(LayerMaskTypeParameters[layerIndex], (int)layer.maskType);
|
||||
mat.SetColor(LayerColorParameters[layerIndex], layer.layerColor);
|
||||
if (layer.sampleMode != ovrAvatarMaterialLayerSampleMode.Color)
|
||||
{
|
||||
string surfaceProperty = LayerSurfaceParameters[layerIndex];
|
||||
mat.SetTexture(surfaceProperty, GetLoadedTexture(layer.sampleTexture));
|
||||
mat.SetTextureScale(surfaceProperty, new Vector2(layer.sampleScaleOffset.x, layer.sampleScaleOffset.y));
|
||||
mat.SetTextureOffset(surfaceProperty, new Vector2(layer.sampleScaleOffset.z, layer.sampleScaleOffset.w));
|
||||
}
|
||||
|
||||
if (layer.sampleMode == ovrAvatarMaterialLayerSampleMode.Parallax)
|
||||
{
|
||||
mat.EnableKeyword("PARALLAX_ON");
|
||||
}
|
||||
|
||||
mat.SetColor(LayerSampleParametersParameters[layerIndex], layer.sampleParameters);
|
||||
mat.SetColor(LayerMaskParametersParameters[layerIndex], layer.maskParameters);
|
||||
mat.SetColor(LayerMaskAxisParameters[layerIndex], layer.maskAxis);
|
||||
}
|
||||
|
||||
materialStates[mat] = matState;
|
||||
}
|
||||
|
||||
public static Texture2D GetLoadedTexture(UInt64 assetId)
|
||||
{
|
||||
OvrAvatarAssetTexture tex = (OvrAvatarAssetTexture)OvrAvatarSDKManager.Instance.GetAsset(assetId);
|
||||
if (tex == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return tex.texture;
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarComponent.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarComponent.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d8af585c6ed18849905454f83194043
|
||||
timeCreated: 1479155378
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
103
Assets/Oculus/Avatar/Scripts/OvrAvatarDriver.cs
Normal file
103
Assets/Oculus/Avatar/Scripts/OvrAvatarDriver.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using Oculus.Avatar;
|
||||
|
||||
public abstract class OvrAvatarDriver : MonoBehaviour {
|
||||
|
||||
public enum PacketMode
|
||||
{
|
||||
SDK,
|
||||
Unity
|
||||
};
|
||||
|
||||
|
||||
public PacketMode Mode;
|
||||
protected PoseFrame CurrentPose;
|
||||
public PoseFrame GetCurrentPose() { return CurrentPose; }
|
||||
public abstract void UpdateTransforms(IntPtr sdkAvatar);
|
||||
|
||||
public struct ControllerPose
|
||||
{
|
||||
public ovrAvatarButton buttons;
|
||||
public ovrAvatarTouch touches;
|
||||
public Vector2 joystickPosition;
|
||||
public float indexTrigger;
|
||||
public float handTrigger;
|
||||
public bool isActive;
|
||||
|
||||
public static ControllerPose Interpolate(ControllerPose a, ControllerPose b, float t)
|
||||
{
|
||||
return new ControllerPose
|
||||
{
|
||||
buttons = t < 0.5f ? a.buttons : b.buttons,
|
||||
touches = t < 0.5f ? a.touches : b.touches,
|
||||
joystickPosition = Vector2.Lerp(a.joystickPosition, b.joystickPosition, t),
|
||||
indexTrigger = Mathf.Lerp(a.indexTrigger, b.indexTrigger, t),
|
||||
handTrigger = Mathf.Lerp(a.handTrigger, b.handTrigger, t),
|
||||
isActive = t < 0.5f ? a.isActive : b.isActive,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public struct PoseFrame
|
||||
{
|
||||
public Vector3 headPosition;
|
||||
public Quaternion headRotation;
|
||||
public Vector3 handLeftPosition;
|
||||
public Quaternion handLeftRotation;
|
||||
public Vector3 handRightPosition;
|
||||
public Quaternion handRightRotation;
|
||||
public float voiceAmplitude;
|
||||
|
||||
public ControllerPose controllerLeftPose;
|
||||
public ControllerPose controllerRightPose;
|
||||
|
||||
public static PoseFrame Interpolate(PoseFrame a, PoseFrame b, float t)
|
||||
{
|
||||
return new PoseFrame
|
||||
{
|
||||
headPosition = Vector3.Lerp(a.headPosition, b.headPosition, t),
|
||||
headRotation = Quaternion.Slerp(a.headRotation, b.headRotation, t),
|
||||
handLeftPosition = Vector3.Lerp(a.handLeftPosition, b.handLeftPosition, t),
|
||||
handLeftRotation = Quaternion.Slerp(a.handLeftRotation, b.handLeftRotation, t),
|
||||
handRightPosition = Vector3.Lerp(a.handRightPosition, b.handRightPosition, t),
|
||||
handRightRotation = Quaternion.Slerp(a.handRightRotation, b.handRightRotation, t),
|
||||
voiceAmplitude = Mathf.Lerp(a.voiceAmplitude, b.voiceAmplitude, t),
|
||||
controllerLeftPose = ControllerPose.Interpolate(a.controllerLeftPose, b.controllerLeftPose, t),
|
||||
controllerRightPose = ControllerPose.Interpolate(a.controllerRightPose, b.controllerRightPose, t),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
protected void UpdateTransformsFromPose(IntPtr sdkAvatar)
|
||||
{
|
||||
if (sdkAvatar != IntPtr.Zero)
|
||||
{
|
||||
ovrAvatarTransform bodyTransform = OvrAvatar.CreateOvrAvatarTransform(CurrentPose.headPosition, CurrentPose.headRotation);
|
||||
ovrAvatarHandInputState inputStateLeft = OvrAvatar.CreateInputState(OvrAvatar.CreateOvrAvatarTransform(CurrentPose.handLeftPosition, CurrentPose.handLeftRotation), CurrentPose.controllerLeftPose);
|
||||
ovrAvatarHandInputState inputStateRight = OvrAvatar.CreateInputState(OvrAvatar.CreateOvrAvatarTransform(CurrentPose.handRightPosition, CurrentPose.handRightRotation), CurrentPose.controllerRightPose);
|
||||
|
||||
CAPI.ovrAvatarPose_UpdateBody(sdkAvatar, bodyTransform);
|
||||
|
||||
if (GetIsTrackedRemote())
|
||||
{
|
||||
CAPI.ovrAvatarPose_UpdateSDK3DofHands(sdkAvatar, inputStateLeft, inputStateRight, GetRemoteControllerType());
|
||||
}
|
||||
else
|
||||
{
|
||||
CAPI.ovrAvatarPose_UpdateHands(sdkAvatar, inputStateLeft, inputStateRight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetIsTrackedRemote()
|
||||
{
|
||||
return OVRInput.IsControllerConnected(OVRInput.Controller.RTrackedRemote) || OVRInput.IsControllerConnected(OVRInput.Controller.LTrackedRemote);
|
||||
}
|
||||
|
||||
private ovrAvatarControllerType GetRemoteControllerType()
|
||||
{
|
||||
return OVRPlugin.productName == "Oculus Go" ? ovrAvatarControllerType.Go : ovrAvatarControllerType.Malibu;
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarDriver.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarDriver.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0bda905d6cc47640bc17f99e364a1b9
|
||||
timeCreated: 1464049373
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/Avatar/Scripts/OvrAvatarHand.cs
Normal file
8
Assets/Oculus/Avatar/Scripts/OvrAvatarHand.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
public class OvrAvatarHand : MonoBehaviour
|
||||
{
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarHand.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarHand.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e53b07ad62d980a4da9fffff0b05fd2e
|
||||
timeCreated: 1464054646
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
108
Assets/Oculus/Avatar/Scripts/OvrAvatarLocalDriver.cs
Normal file
108
Assets/Oculus/Avatar/Scripts/OvrAvatarLocalDriver.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Avatar;
|
||||
|
||||
public class OvrAvatarLocalDriver : OvrAvatarDriver {
|
||||
|
||||
ControllerPose GetMalibuControllerPose(OVRInput.Controller controller)
|
||||
{
|
||||
ovrAvatarButton buttons = 0;
|
||||
if (OVRInput.Get(OVRInput.Button.PrimaryIndexTrigger, controller)) buttons |= ovrAvatarButton.One;
|
||||
|
||||
return new ControllerPose
|
||||
{
|
||||
buttons = buttons,
|
||||
touches = OVRInput.Get(OVRInput.Touch.PrimaryTouchpad) ? ovrAvatarTouch.One : 0,
|
||||
joystickPosition = OVRInput.Get(OVRInput.Axis2D.PrimaryTouchpad, controller),
|
||||
indexTrigger = 0f,
|
||||
handTrigger = 0f,
|
||||
isActive = (OVRInput.GetActiveController() & controller) != 0,
|
||||
};
|
||||
}
|
||||
|
||||
float voiceAmplitude = 0.0f;
|
||||
ControllerPose GetControllerPose(OVRInput.Controller controller)
|
||||
{
|
||||
ovrAvatarButton buttons = 0;
|
||||
if (OVRInput.Get(OVRInput.Button.One, controller)) buttons |= ovrAvatarButton.One;
|
||||
if (OVRInput.Get(OVRInput.Button.Two, controller)) buttons |= ovrAvatarButton.Two;
|
||||
if (OVRInput.Get(OVRInput.Button.Start, controller)) buttons |= ovrAvatarButton.Three;
|
||||
if (OVRInput.Get(OVRInput.Button.PrimaryThumbstick, controller)) buttons |= ovrAvatarButton.Joystick;
|
||||
|
||||
ovrAvatarTouch touches = 0;
|
||||
if (OVRInput.Get(OVRInput.Touch.One, controller)) touches |= ovrAvatarTouch.One;
|
||||
if (OVRInput.Get(OVRInput.Touch.Two, controller)) touches |= ovrAvatarTouch.Two;
|
||||
if (OVRInput.Get(OVRInput.Touch.PrimaryThumbstick, controller)) touches |= ovrAvatarTouch.Joystick;
|
||||
if (OVRInput.Get(OVRInput.Touch.PrimaryThumbRest, controller)) touches |= ovrAvatarTouch.ThumbRest;
|
||||
if (OVRInput.Get(OVRInput.Touch.PrimaryIndexTrigger, controller)) touches |= ovrAvatarTouch.Index;
|
||||
if (!OVRInput.Get(OVRInput.NearTouch.PrimaryIndexTrigger, controller)) touches |= ovrAvatarTouch.Pointing;
|
||||
if (!OVRInput.Get(OVRInput.NearTouch.PrimaryThumbButtons, controller)) touches |= ovrAvatarTouch.ThumbUp;
|
||||
|
||||
return new ControllerPose
|
||||
{
|
||||
buttons = buttons,
|
||||
touches = touches,
|
||||
joystickPosition = OVRInput.Get(OVRInput.Axis2D.PrimaryThumbstick, controller),
|
||||
indexTrigger = OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger, controller),
|
||||
handTrigger = OVRInput.Get(OVRInput.Axis1D.PrimaryHandTrigger, controller),
|
||||
isActive = (OVRInput.GetActiveController() & controller) != 0,
|
||||
};
|
||||
}
|
||||
|
||||
private void CalculateCurrentPose()
|
||||
{
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
Vector3 headPos = UnityEngine.XR.InputTracking.GetLocalPosition(UnityEngine.XR.XRNode.CenterEye);
|
||||
#else
|
||||
Vector3 headPos = UnityEngine.VR.InputTracking.GetLocalPosition(UnityEngine.VR.VRNode.CenterEye);
|
||||
#endif
|
||||
|
||||
if (GetIsTrackedRemote())
|
||||
{
|
||||
CurrentPose = new PoseFrame
|
||||
{
|
||||
voiceAmplitude = voiceAmplitude,
|
||||
headPosition = headPos,
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
headRotation = UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.CenterEye),
|
||||
#else
|
||||
headRotation = UnityEngine.VR.InputTracking.GetLocalRotation(UnityEngine.VR.VRNode.CenterEye),
|
||||
#endif
|
||||
handLeftPosition = OVRInput.GetLocalControllerPosition(OVRInput.Controller.LTrackedRemote),
|
||||
handLeftRotation = OVRInput.GetLocalControllerRotation(OVRInput.Controller.LTrackedRemote),
|
||||
handRightPosition = OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTrackedRemote),
|
||||
handRightRotation = OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTrackedRemote),
|
||||
controllerLeftPose = GetMalibuControllerPose(OVRInput.Controller.LTrackedRemote),
|
||||
controllerRightPose = GetMalibuControllerPose(OVRInput.Controller.RTrackedRemote),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentPose = new PoseFrame
|
||||
{
|
||||
voiceAmplitude = voiceAmplitude,
|
||||
headPosition = headPos,
|
||||
#if UNITY_2017_2_OR_NEWER
|
||||
headRotation = UnityEngine.XR.InputTracking.GetLocalRotation(UnityEngine.XR.XRNode.CenterEye),
|
||||
#else
|
||||
headRotation = UnityEngine.VR.InputTracking.GetLocalRotation(UnityEngine.VR.VRNode.CenterEye),
|
||||
#endif
|
||||
handLeftPosition = OVRInput.GetLocalControllerPosition(OVRInput.Controller.LTouch),
|
||||
handLeftRotation = OVRInput.GetLocalControllerRotation(OVRInput.Controller.LTouch),
|
||||
handRightPosition = OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch),
|
||||
handRightRotation = OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch),
|
||||
controllerLeftPose = GetControllerPose(OVRInput.Controller.LTouch),
|
||||
controllerRightPose = GetControllerPose(OVRInput.Controller.RTouch),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void UpdateTransforms(IntPtr sdkAvatar)
|
||||
{
|
||||
CalculateCurrentPose();
|
||||
UpdateTransformsFromPose(sdkAvatar);
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarLocalDriver.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarLocalDriver.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac27124318cf8e84aa7350c2ac1cdb80
|
||||
timeCreated: 1464049705
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
38
Assets/Oculus/Avatar/Scripts/OvrAvatarLogger.cs
Normal file
38
Assets/Oculus/Avatar/Scripts/OvrAvatarLogger.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Oculus.Avatar
|
||||
{
|
||||
public static class AvatarLogger
|
||||
{
|
||||
public const string LogAvatar = "[Avatars] - ";
|
||||
public const string Tab = " ";
|
||||
|
||||
[System.Diagnostics.Conditional("ENABLE_AVATAR_LOGS"),
|
||||
System.Diagnostics.Conditional("ENABLE_AVATAR_LOG_BASIC")]
|
||||
public static void Log(string logMsg)
|
||||
{
|
||||
Debug.Log(LogAvatar + logMsg);
|
||||
}
|
||||
|
||||
[System.Diagnostics.Conditional("ENABLE_AVATAR_LOGS"),
|
||||
System.Diagnostics.Conditional("ENABLE_AVATAR_LOG_BASIC")]
|
||||
public static void Log(string logMsg, Object context)
|
||||
{
|
||||
Debug.Log(LogAvatar + logMsg , context);
|
||||
}
|
||||
|
||||
[System.Diagnostics.Conditional("ENABLE_AVATAR_LOGS"),
|
||||
System.Diagnostics.Conditional("ENABLE_AVATAR_LOG_WARNING")]
|
||||
public static void LogWarning(string logMsg)
|
||||
{
|
||||
Debug.LogWarning(LogAvatar + logMsg);
|
||||
}
|
||||
|
||||
[System.Diagnostics.Conditional("ENABLE_AVATAR_LOGS"),
|
||||
System.Diagnostics.Conditional("ENABLE_AVATAR_LOG_ERROR")]
|
||||
public static void LogError(string logMsg)
|
||||
{
|
||||
Debug.LogError(LogAvatar + logMsg);
|
||||
}
|
||||
};
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarLogger.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarLogger.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d391500bc1e8da42a41ef796dd22ed0
|
||||
timeCreated: 1519433181
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
354
Assets/Oculus/Avatar/Scripts/OvrAvatarMaterialManager.cs
Normal file
354
Assets/Oculus/Avatar/Scripts/OvrAvatarMaterialManager.cs
Normal file
@@ -0,0 +1,354 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using Oculus.Avatar;
|
||||
using System.Collections;
|
||||
|
||||
public class OvrAvatarMaterialManager : MonoBehaviour
|
||||
{
|
||||
// Set up in the Prefab, and meant to be indexed by LOD
|
||||
public Texture2D[] DiffuseFallbacks;
|
||||
public Texture2D[] NormalFallbacks;
|
||||
|
||||
private Renderer TargetRenderer;
|
||||
private AvatarTextureArrayProperties[] TextureArrays;
|
||||
|
||||
private OvrAvatarTextureCopyManager TextureCopyManager;
|
||||
|
||||
public enum TextureType
|
||||
{
|
||||
DiffuseTextures = 0,
|
||||
NormalMaps,
|
||||
RoughnessMaps,
|
||||
|
||||
Count
|
||||
}
|
||||
// Material properties required to render a single component
|
||||
[System.Serializable]
|
||||
public struct AvatarComponentMaterialProperties
|
||||
{
|
||||
public ovrAvatarBodyPartType TypeIndex;
|
||||
public Color Color;
|
||||
public Texture2D[] Textures;
|
||||
|
||||
[Range(0, 1)] public float DiffuseIntensity;
|
||||
[Range(0, 10)] public float RimIntensity;
|
||||
[Range(0, 1)] public float BacklightIntensity;
|
||||
[Range(0, 1)] public float ReflectionIntensity;
|
||||
}
|
||||
|
||||
// Texture arrays
|
||||
[System.Serializable]
|
||||
public struct AvatarTextureArrayProperties
|
||||
{
|
||||
public Texture2D[] Textures;
|
||||
public Texture2DArray TextureArray;
|
||||
}
|
||||
|
||||
// Material property arrays that are pushed to the shader
|
||||
[System.Serializable]
|
||||
public struct AvatarMaterialPropertyBlock
|
||||
{
|
||||
public Vector4[] Colors;
|
||||
public float[] DiffuseIntensities;
|
||||
public float[] RimIntensities;
|
||||
public float[] BacklightIntensities;
|
||||
public float[] ReflectionIntensities;
|
||||
}
|
||||
|
||||
private readonly string[] TextureTypeToShaderProperties =
|
||||
{
|
||||
"_MainTex", // TextureType.DiffuseTextures = 0
|
||||
"_NormalMap", // TextureType.NormalMaps
|
||||
"_RoughnessMap" // TextureType.RoughnessMaps
|
||||
};
|
||||
|
||||
public Color[] BodyColorTints;
|
||||
public List<ReflectionProbeBlendInfo> ReflectionProbes = new List<ReflectionProbeBlendInfo>();
|
||||
|
||||
// Container class for all the data relating to an avatar material description
|
||||
[System.Serializable]
|
||||
public class AvatarMaterialConfig
|
||||
{
|
||||
public AvatarComponentMaterialProperties[] ComponentMaterialProperties;
|
||||
public AvatarMaterialPropertyBlock MaterialPropertyBlock;
|
||||
}
|
||||
|
||||
// Local config that this manager instance will render
|
||||
public AvatarMaterialConfig LocalAvatarConfig;
|
||||
// Default avatar config used to initially populate the locally managed avatar config
|
||||
public AvatarMaterialConfig DefaultAvatarConfig;
|
||||
|
||||
// Property block for pushing to shader
|
||||
private AvatarMaterialPropertyBlock LocalAvatarMaterialPropertyBlock;
|
||||
|
||||
public static int RENDER_QUEUE = 3640;
|
||||
|
||||
// Shader properties
|
||||
public static string AVATAR_SHADER_COMBINED = "OvrAvatar/Avatar_Mobile_CombinedMesh";
|
||||
public static string AVATAR_SHADER_LOADER = "OvrAvatar/Avatar_Mobile_Loader";
|
||||
public static string AVATAR_SHADER_MAINTEX = "_MainTex";
|
||||
public static string AVATAR_SHADER_NORMALMAP = "_NormalMap";
|
||||
public static string AVATAR_SHADER_ROUGHNESSMAP = "_RoughnessMap";
|
||||
public static string AVATAR_SHADER_COLOR = "_BaseColor";
|
||||
public static string AVATAR_SHADER_DIFFUSEINTENSITY = "_DiffuseIntensity";
|
||||
public static string AVATAR_SHADER_RIMINTENSITY = "_RimIntensity";
|
||||
public static string AVATAR_SHADER_BACKLIGHTINTENSITY = "_BacklightIntensity";
|
||||
public static string AVATAR_SHADER_REFLECTIONINTENSITY = "_ReflectionIntensity";
|
||||
public static string AVATAR_SHADER_CUBEMAP = "_Cubemap";
|
||||
public static string AVATAR_SHADER_ALPHA = "_Alpha";
|
||||
public static string AVATAR_SHADER_LOADING_DIMMER = "_LoadingDimmer";
|
||||
|
||||
// Loading animation
|
||||
private const float LOADING_ANIMATION_AMPLITUDE = 0.5f;
|
||||
private const float LOADING_ANIMATION_PERIOD = 0.35f;
|
||||
private const float LOADING_ANIMATION_CURVE_SCALE = 0.25f;
|
||||
private const float LOADING_ANIMATION_DIMMER_MIN = 0.3f;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
TextureCopyManager = gameObject.AddComponent<OvrAvatarTextureCopyManager>();
|
||||
}
|
||||
|
||||
public void CreateTextureArrays()
|
||||
{
|
||||
const int componentCount = (int)ovrAvatarBodyPartType.Count;
|
||||
const int textureTypeCount = (int)TextureType.Count;
|
||||
|
||||
for (int index = 0; index < componentCount; index++)
|
||||
{
|
||||
LocalAvatarConfig.ComponentMaterialProperties[index].Textures = new Texture2D[textureTypeCount];
|
||||
DefaultAvatarConfig.ComponentMaterialProperties[index].Textures = new Texture2D[textureTypeCount];
|
||||
}
|
||||
|
||||
TextureArrays = new AvatarTextureArrayProperties[textureTypeCount];
|
||||
}
|
||||
|
||||
public void SetRenderer(Renderer renderer)
|
||||
{
|
||||
TargetRenderer = renderer;
|
||||
TargetRenderer.GetClosestReflectionProbes(ReflectionProbes);
|
||||
}
|
||||
|
||||
public void OnCombinedMeshReady()
|
||||
{
|
||||
InitTextureArrays();
|
||||
SetMaterialPropertyBlock();
|
||||
StartCoroutine(RunLoadingAnimation());
|
||||
}
|
||||
|
||||
// Prepare texture arrays and copy to GPU
|
||||
public void InitTextureArrays()
|
||||
{
|
||||
var localProps = LocalAvatarConfig.ComponentMaterialProperties[0];
|
||||
|
||||
for (int i = 0; i < TextureArrays.Length && i < localProps.Textures.Length; i++)
|
||||
{
|
||||
TextureArrays[i].TextureArray = new Texture2DArray(
|
||||
localProps.Textures[0].height, localProps.Textures[0].width,
|
||||
LocalAvatarConfig.ComponentMaterialProperties.Length,
|
||||
localProps.Textures[0].format,
|
||||
true,
|
||||
QualitySettings.activeColorSpace == ColorSpace.Gamma ? false : true
|
||||
) { filterMode = FilterMode.Trilinear };
|
||||
|
||||
TextureArrays[i].Textures
|
||||
= new Texture2D[LocalAvatarConfig.ComponentMaterialProperties.Length];
|
||||
|
||||
for (int j = 0; j < LocalAvatarConfig.ComponentMaterialProperties.Length; j++)
|
||||
{
|
||||
TextureArrays[i].Textures[j]
|
||||
= LocalAvatarConfig.ComponentMaterialProperties[j].Textures[i];
|
||||
}
|
||||
|
||||
ProcessTexturesWithMips(
|
||||
TextureArrays[i].Textures,
|
||||
localProps.Textures[i].height,
|
||||
TextureArrays[i].TextureArray);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessTexturesWithMips(
|
||||
Texture2D[] textures,
|
||||
int texArrayResolution,
|
||||
Texture2DArray texArray)
|
||||
{
|
||||
for (int i = 0; i < textures.Length; i++)
|
||||
{
|
||||
int currentMipSize = texArrayResolution;
|
||||
int correctNumberOfMips = textures[i].mipmapCount - 1;
|
||||
|
||||
// Add mips to copyTexture queue in low-high order from correctNumberOfMips..0
|
||||
for (int mipLevel = correctNumberOfMips; mipLevel >= 0; mipLevel--)
|
||||
{
|
||||
int mipSize = texArrayResolution / currentMipSize;
|
||||
TextureCopyManager.CopyTexture(
|
||||
textures[i],
|
||||
texArray,
|
||||
mipLevel,
|
||||
mipSize,
|
||||
i,
|
||||
true);
|
||||
|
||||
currentMipSize /= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetMaterialPropertyBlock()
|
||||
{
|
||||
if (TargetRenderer != null)
|
||||
{
|
||||
for (int i = 0; i < LocalAvatarConfig.ComponentMaterialProperties.Length; i++)
|
||||
{
|
||||
LocalAvatarConfig.MaterialPropertyBlock.Colors[i]
|
||||
= LocalAvatarConfig.ComponentMaterialProperties[i].Color;
|
||||
LocalAvatarConfig.MaterialPropertyBlock.DiffuseIntensities[i]
|
||||
= LocalAvatarConfig.ComponentMaterialProperties[i].DiffuseIntensity;
|
||||
LocalAvatarConfig.MaterialPropertyBlock.RimIntensities[i]
|
||||
= LocalAvatarConfig.ComponentMaterialProperties[i].RimIntensity;
|
||||
LocalAvatarConfig.MaterialPropertyBlock.BacklightIntensities[i]
|
||||
= LocalAvatarConfig.ComponentMaterialProperties[i].BacklightIntensity;
|
||||
LocalAvatarConfig.MaterialPropertyBlock.ReflectionIntensities[i]
|
||||
= LocalAvatarConfig.ComponentMaterialProperties[i].ReflectionIntensity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyMaterialPropertyBlock()
|
||||
{
|
||||
MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock();
|
||||
materialPropertyBlock.SetVectorArray(AVATAR_SHADER_COLOR,
|
||||
LocalAvatarConfig.MaterialPropertyBlock.Colors);
|
||||
materialPropertyBlock.SetFloatArray(AVATAR_SHADER_DIFFUSEINTENSITY,
|
||||
LocalAvatarConfig.MaterialPropertyBlock.DiffuseIntensities);
|
||||
materialPropertyBlock.SetFloatArray(AVATAR_SHADER_RIMINTENSITY,
|
||||
LocalAvatarConfig.MaterialPropertyBlock.RimIntensities);
|
||||
materialPropertyBlock.SetFloatArray(AVATAR_SHADER_BACKLIGHTINTENSITY,
|
||||
LocalAvatarConfig.MaterialPropertyBlock.BacklightIntensities);
|
||||
materialPropertyBlock.SetFloatArray(AVATAR_SHADER_REFLECTIONINTENSITY,
|
||||
LocalAvatarConfig.MaterialPropertyBlock.ReflectionIntensities);
|
||||
TargetRenderer.GetClosestReflectionProbes(ReflectionProbes);
|
||||
|
||||
if (ReflectionProbes != null && ReflectionProbes.Count > 0 && ReflectionProbes[0].probe.texture != null)
|
||||
{
|
||||
materialPropertyBlock.SetTexture(AVATAR_SHADER_CUBEMAP, ReflectionProbes[0].probe.texture);
|
||||
}
|
||||
|
||||
for (int i = 0; i < TextureArrays.Length; i++)
|
||||
{
|
||||
materialPropertyBlock.SetTexture(TextureTypeToShaderProperties[i],
|
||||
TextureArrays[(int)(TextureType)i].TextureArray);
|
||||
}
|
||||
|
||||
TargetRenderer.SetPropertyBlock(materialPropertyBlock);
|
||||
}
|
||||
|
||||
// Return a component type based on name
|
||||
public static ovrAvatarBodyPartType GetComponentType(string objectName)
|
||||
{
|
||||
if (objectName.Contains("0"))
|
||||
{
|
||||
return ovrAvatarBodyPartType.Body;
|
||||
}
|
||||
else if (objectName.Contains("1"))
|
||||
{
|
||||
return ovrAvatarBodyPartType.Clothing;
|
||||
}
|
||||
else if (objectName.Contains("2"))
|
||||
{
|
||||
return ovrAvatarBodyPartType.Eyewear;
|
||||
}
|
||||
else if (objectName.Contains("3"))
|
||||
{
|
||||
return ovrAvatarBodyPartType.Hair;
|
||||
}
|
||||
else if (objectName.Contains("4"))
|
||||
{
|
||||
return ovrAvatarBodyPartType.Beard;
|
||||
}
|
||||
|
||||
return ovrAvatarBodyPartType.Count;
|
||||
}
|
||||
|
||||
public void ValidateTextures()
|
||||
{
|
||||
var props = LocalAvatarConfig.ComponentMaterialProperties;
|
||||
|
||||
int[] heights = new int[(int)TextureType.Count];
|
||||
TextureFormat[] formats = new TextureFormat[(int)TextureType.Count];
|
||||
|
||||
for (var propIndex = 0; propIndex < props.Length; propIndex++)
|
||||
{
|
||||
for (var index = 0; index < props[propIndex].Textures.Length; index++)
|
||||
{
|
||||
if (props[propIndex].Textures[index] == null)
|
||||
{
|
||||
throw new System.Exception(
|
||||
props[propIndex].TypeIndex.ToString()
|
||||
+ "Invalid: "
|
||||
+ ((TextureType)index).ToString());
|
||||
}
|
||||
|
||||
heights[index] = props[propIndex].Textures[index].height;
|
||||
formats[index] = props[propIndex].Textures[index].format;
|
||||
}
|
||||
}
|
||||
|
||||
for (int textureIndex = 0; textureIndex < (int)TextureType.Count; textureIndex++)
|
||||
{
|
||||
for (var propIndex = 1; propIndex < props.Length; propIndex++)
|
||||
{
|
||||
if (props[propIndex - 1].Textures[textureIndex].height
|
||||
!= props[propIndex].Textures[textureIndex].height)
|
||||
{
|
||||
throw new System.Exception(
|
||||
props[propIndex].TypeIndex.ToString()
|
||||
+ " Mismatching Resolutions: "
|
||||
+ ((TextureType)textureIndex).ToString()
|
||||
+ " "
|
||||
+ props[propIndex - 1].Textures[textureIndex].height
|
||||
+ " vs "
|
||||
+ props[propIndex].Textures[textureIndex].height
|
||||
+ " Ensure you are using ASTC texture compression on Android or turn off CombineMeshes");
|
||||
}
|
||||
|
||||
if (props[propIndex - 1].Textures[textureIndex].format
|
||||
!= props[propIndex].Textures[textureIndex].format)
|
||||
{
|
||||
throw new System.Exception(
|
||||
props[propIndex].TypeIndex.ToString()
|
||||
+ " Mismatching Formats: "
|
||||
+ ((TextureType)textureIndex).ToString()
|
||||
+ " Ensure you are using ASTC texture compression on Android or turn off CombineMeshes");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loading animation on the Dimmer properyt
|
||||
// Smooth sine lerp every 0.3 seconds between 0.25 and 0.5
|
||||
private IEnumerator RunLoadingAnimation()
|
||||
{
|
||||
// Set the material to single component while the avatar loads
|
||||
int renderQueue = TargetRenderer.sharedMaterial.renderQueue;
|
||||
TargetRenderer.sharedMaterial.shader = Shader.Find(AVATAR_SHADER_LOADER);
|
||||
TargetRenderer.sharedMaterial.renderQueue = renderQueue;
|
||||
TargetRenderer.sharedMaterial.SetColor(AVATAR_SHADER_COLOR, Color.white);
|
||||
|
||||
while (TextureCopyManager.GetTextureCount() > 0)
|
||||
{
|
||||
float distance = (LOADING_ANIMATION_AMPLITUDE * Mathf.Sin(Time.timeSinceLevelLoad / LOADING_ANIMATION_PERIOD) +
|
||||
LOADING_ANIMATION_AMPLITUDE) * (LOADING_ANIMATION_CURVE_SCALE) + LOADING_ANIMATION_DIMMER_MIN;
|
||||
TargetRenderer.sharedMaterial.SetFloat(AVATAR_SHADER_LOADING_DIMMER, distance);
|
||||
yield return null;
|
||||
}
|
||||
// Restore render order and swap the combined material
|
||||
renderQueue = TargetRenderer.sharedMaterial.renderQueue;
|
||||
TargetRenderer.sharedMaterial.SetFloat(AVATAR_SHADER_LOADING_DIMMER, 1f);
|
||||
TargetRenderer.sharedMaterial.shader = Shader.Find(AVATAR_SHADER_COMBINED);
|
||||
TargetRenderer.sharedMaterial.renderQueue = renderQueue;
|
||||
|
||||
ApplyMaterialPropertyBlock();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a139d83bf6796734db220df8a5bfacbd
|
||||
timeCreated: 1518209612
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
180
Assets/Oculus/Avatar/Scripts/OvrAvatarMeshInstance.cs
Normal file
180
Assets/Oculus/Avatar/Scripts/OvrAvatarMeshInstance.cs
Normal file
@@ -0,0 +1,180 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using Oculus.Avatar;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class OvrAvatarMeshInstance : MonoBehaviour
|
||||
{
|
||||
HashSet<UInt64> AssetsToLoad;
|
||||
|
||||
public UInt64 MeshID = 0;
|
||||
UInt64 MaterialID = 0;
|
||||
UInt64 FadeTextureID = 0;
|
||||
public ovrAvatarBodyPartType MeshType;
|
||||
public ovrAvatarMaterialState MaterialState;
|
||||
MeshFilter Mesh;
|
||||
MeshRenderer MeshInstance;
|
||||
|
||||
public void AssetLoadedCallback(OvrAvatarAsset asset)
|
||||
{
|
||||
AssetsToLoad.Remove(asset.assetID);
|
||||
HandleAssetAvailable(asset);
|
||||
|
||||
if (AssetsToLoad.Count <= 0)
|
||||
{
|
||||
UpdateMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMeshAssets(UInt64 fadeTexture, UInt64 meshID, UInt64 materialID, ovrAvatarBodyPartType type)
|
||||
{
|
||||
MaterialID = materialID;
|
||||
MeshID = meshID;
|
||||
FadeTextureID = fadeTexture;
|
||||
MeshType = type;
|
||||
|
||||
AssetsToLoad = new HashSet<UInt64>();
|
||||
|
||||
RequestAsset(meshID);
|
||||
RequestAsset(materialID);
|
||||
RequestAsset(fadeTexture);
|
||||
}
|
||||
|
||||
private void HandleAssetAvailable(OvrAvatarAsset asset)
|
||||
{
|
||||
if (asset.assetID == MeshID)
|
||||
{
|
||||
Mesh = gameObject.AddComponent<MeshFilter>();
|
||||
MeshInstance = gameObject.AddComponent<MeshRenderer>();
|
||||
MeshInstance.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||
Mesh.sharedMesh = ((OvrAvatarAssetMesh)asset).mesh;
|
||||
|
||||
Material mat = new Material(Shader.Find("OvrAvatar/AvatarSurfaceShaderSelfOccluding"));
|
||||
MeshInstance.material = mat;
|
||||
}
|
||||
|
||||
if (asset.assetID == MaterialID)
|
||||
{
|
||||
MaterialState = ((OvrAvatarAssetMaterial)asset).material;
|
||||
MaterialState.alphaMaskTextureID = FadeTextureID;
|
||||
RequestMaterialTextures();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeMaterial(UInt64 assetID)
|
||||
{
|
||||
MaterialID = assetID;
|
||||
RequestAsset(MaterialID);
|
||||
}
|
||||
|
||||
private void RequestAsset(UInt64 assetID)
|
||||
{
|
||||
if (assetID == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OvrAvatarAsset asset = OvrAvatarSDKManager.Instance.GetAsset(assetID);
|
||||
if (asset == null)
|
||||
{
|
||||
OvrAvatarSDKManager.Instance.BeginLoadingAsset(assetID, ovrAvatarAssetLevelOfDetail.Medium, this.AssetLoadedCallback);
|
||||
AssetsToLoad.Add(assetID);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleAssetAvailable(asset);
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestMaterialTextures()
|
||||
{
|
||||
RequestAsset(MaterialState.normalMapTextureID);
|
||||
RequestAsset(MaterialState.parallaxMapTextureID);
|
||||
RequestAsset(MaterialState.roughnessMapTextureID);
|
||||
|
||||
for (var layerIndex = 0; layerIndex < MaterialState.layerCount; layerIndex++)
|
||||
{
|
||||
RequestAsset(MaterialState.layers[layerIndex].sampleTexture);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetActive(bool active)
|
||||
{
|
||||
gameObject.SetActive(active);
|
||||
|
||||
if (active)
|
||||
{
|
||||
UpdateMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateMaterial()
|
||||
{
|
||||
if (MeshInstance == null || MaterialID == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mat = MeshInstance.material;
|
||||
var matState = MaterialState;
|
||||
|
||||
mat.SetColor("_BaseColor", matState.baseColor);
|
||||
mat.SetInt("_BaseMaskType", (int)matState.baseMaskType);
|
||||
mat.SetVector("_BaseMaskParameters", matState.baseMaskParameters);
|
||||
mat.SetVector("_BaseMaskAxis", matState.baseMaskAxis);
|
||||
|
||||
if (matState.alphaMaskTextureID != 0)
|
||||
{
|
||||
mat.SetTexture("_AlphaMask", OvrAvatarComponent.GetLoadedTexture(matState.alphaMaskTextureID));
|
||||
mat.SetTextureScale("_AlphaMask", new Vector2(matState.alphaMaskScaleOffset.x, matState.alphaMaskScaleOffset.y));
|
||||
mat.SetTextureOffset("_AlphaMask", new Vector2(matState.alphaMaskScaleOffset.z, matState.alphaMaskScaleOffset.w));
|
||||
}
|
||||
|
||||
if (matState.normalMapTextureID != 0)
|
||||
{
|
||||
mat.EnableKeyword("NORMAL_MAP_ON");
|
||||
mat.SetTexture("_NormalMap", OvrAvatarComponent.GetLoadedTexture(matState.normalMapTextureID));
|
||||
mat.SetTextureScale("_NormalMap", new Vector2(matState.normalMapScaleOffset.x, matState.normalMapScaleOffset.y));
|
||||
mat.SetTextureOffset("_NormalMap", new Vector2(matState.normalMapScaleOffset.z, matState.normalMapScaleOffset.w));
|
||||
}
|
||||
if (matState.parallaxMapTextureID != 0)
|
||||
{
|
||||
mat.SetTexture("_ParallaxMap", OvrAvatarComponent.GetLoadedTexture(matState.parallaxMapTextureID));
|
||||
mat.SetTextureScale("_ParallaxMap", new Vector2(matState.parallaxMapScaleOffset.x, matState.parallaxMapScaleOffset.y));
|
||||
mat.SetTextureOffset("_ParallaxMap", new Vector2(matState.parallaxMapScaleOffset.z, matState.parallaxMapScaleOffset.w));
|
||||
}
|
||||
if (matState.roughnessMapTextureID != 0)
|
||||
{
|
||||
mat.EnableKeyword("ROUGHNESS_ON");
|
||||
mat.SetTexture("_RoughnessMap", OvrAvatarComponent.GetLoadedTexture(matState.roughnessMapTextureID));
|
||||
mat.SetTextureScale("_RoughnessMap", new Vector2(matState.roughnessMapScaleOffset.x, matState.roughnessMapScaleOffset.y));
|
||||
mat.SetTextureOffset("_RoughnessMap", new Vector2(matState.roughnessMapScaleOffset.z, matState.roughnessMapScaleOffset.w));
|
||||
}
|
||||
mat.EnableKeyword(OvrAvatarComponent.LayerKeywords[matState.layerCount]);
|
||||
for (ulong layerIndex = 0; layerIndex < matState.layerCount; layerIndex++)
|
||||
{
|
||||
ovrAvatarMaterialLayerState layer = matState.layers[layerIndex];
|
||||
|
||||
mat.SetInt(OvrAvatarComponent.LayerSampleModeParameters[layerIndex], (int)layer.sampleMode);
|
||||
mat.SetInt(OvrAvatarComponent.LayerBlendModeParameters[layerIndex], (int)layer.blendMode);
|
||||
mat.SetInt(OvrAvatarComponent.LayerMaskTypeParameters[layerIndex], (int)layer.maskType);
|
||||
mat.SetColor(OvrAvatarComponent.LayerColorParameters[layerIndex], layer.layerColor);
|
||||
if (layer.sampleMode != ovrAvatarMaterialLayerSampleMode.Color)
|
||||
{
|
||||
string surfaceProperty = OvrAvatarComponent.LayerSurfaceParameters[layerIndex];
|
||||
mat.SetTexture(surfaceProperty, OvrAvatarComponent.GetLoadedTexture(layer.sampleTexture));
|
||||
mat.SetTextureScale(surfaceProperty, new Vector2(layer.sampleScaleOffset.x, layer.sampleScaleOffset.y));
|
||||
mat.SetTextureOffset(surfaceProperty, new Vector2(layer.sampleScaleOffset.z, layer.sampleScaleOffset.w));
|
||||
}
|
||||
|
||||
if (layer.sampleMode == ovrAvatarMaterialLayerSampleMode.Parallax)
|
||||
{
|
||||
mat.EnableKeyword("PARALLAX_ON");
|
||||
}
|
||||
|
||||
mat.SetColor(OvrAvatarComponent.LayerSampleParametersParameters[layerIndex], layer.sampleParameters);
|
||||
mat.SetColor(OvrAvatarComponent.LayerMaskParametersParameters[layerIndex], layer.maskParameters);
|
||||
mat.SetColor(OvrAvatarComponent.LayerMaskAxisParameters[layerIndex], layer.maskAxis);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarMeshInstance.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarMeshInstance.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b826904b5b22c3d42b56ca245ec8a58b
|
||||
timeCreated: 1493063917
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
231
Assets/Oculus/Avatar/Scripts/OvrAvatarPacket.cs
Normal file
231
Assets/Oculus/Avatar/Scripts/OvrAvatarPacket.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
public class OvrAvatarPacket
|
||||
{
|
||||
// Used with SDK driven packet flow
|
||||
public IntPtr ovrNativePacket = IntPtr.Zero;
|
||||
|
||||
// ===============================================================
|
||||
// All code below used for unity only pose blending option.
|
||||
// ===============================================================
|
||||
List<float> frameTimes = new List<float>();
|
||||
List<OvrAvatarDriver.PoseFrame> frames = new List<OvrAvatarDriver.PoseFrame>();
|
||||
List<byte[]> encodedAudioPackets = new List<byte[]>();
|
||||
|
||||
public float Duration { get { return frameTimes[frameTimes.Count - 1]; } }
|
||||
public OvrAvatarDriver.PoseFrame FinalFrame { get { return frames[frames.Count - 1]; } }
|
||||
|
||||
public OvrAvatarPacket()
|
||||
{
|
||||
}
|
||||
|
||||
public OvrAvatarPacket(OvrAvatarDriver.PoseFrame initialPose)
|
||||
{
|
||||
frameTimes.Add(0.0f);
|
||||
frames.Add(initialPose);
|
||||
}
|
||||
|
||||
OvrAvatarPacket(List<float> frameTimes, List<OvrAvatarDriver.PoseFrame> frames, List<byte[]> audioPackets)
|
||||
{
|
||||
this.frameTimes = frameTimes;
|
||||
this.frames = frames;
|
||||
}
|
||||
|
||||
public void AddFrame(OvrAvatarDriver.PoseFrame frame, float deltaSeconds)
|
||||
{
|
||||
frameTimes.Add(Duration + deltaSeconds);
|
||||
frames.Add(frame);
|
||||
}
|
||||
|
||||
public OvrAvatarDriver.PoseFrame GetPoseFrame(float seconds)
|
||||
{
|
||||
if (frames.Count == 1)
|
||||
{
|
||||
return frames[0];
|
||||
}
|
||||
|
||||
// This can be replaced with a more efficient binary search
|
||||
int tailIndex = 1;
|
||||
while (tailIndex < frameTimes.Count && frameTimes[tailIndex] < seconds)
|
||||
{
|
||||
++tailIndex;
|
||||
}
|
||||
OvrAvatarDriver.PoseFrame a = frames[tailIndex - 1];
|
||||
OvrAvatarDriver.PoseFrame b = frames[tailIndex];
|
||||
float aTime = frameTimes[tailIndex - 1];
|
||||
float bTime = frameTimes[tailIndex];
|
||||
float t = (seconds - aTime) / (bTime - aTime);
|
||||
return OvrAvatarDriver.PoseFrame.Interpolate(a, b, t);
|
||||
}
|
||||
|
||||
public static OvrAvatarPacket Read(Stream stream)
|
||||
{
|
||||
BinaryReader reader = new BinaryReader(stream);
|
||||
|
||||
// Todo: bounds check frame count
|
||||
int frameCount = reader.ReadInt32();
|
||||
List<float> frameTimes = new List<float>(frameCount);
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
{
|
||||
frameTimes.Add(reader.ReadSingle());
|
||||
}
|
||||
List<OvrAvatarDriver.PoseFrame> frames = new List<OvrAvatarDriver.PoseFrame>(frameCount);
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
{
|
||||
frames.Add(reader.ReadPoseFrame());
|
||||
}
|
||||
|
||||
// Todo: bounds check audio packet count
|
||||
int audioPacketCount = reader.ReadInt32();
|
||||
List<byte[]> audioPackets = new List<byte[]>(audioPacketCount);
|
||||
for (int i = 0; i < audioPacketCount; ++i)
|
||||
{
|
||||
int audioPacketSize = reader.ReadInt32();
|
||||
byte[] audioPacket = reader.ReadBytes(audioPacketSize);
|
||||
audioPackets.Add(audioPacket);
|
||||
}
|
||||
|
||||
return new OvrAvatarPacket(frameTimes, frames, audioPackets);
|
||||
}
|
||||
|
||||
public void Write(Stream stream)
|
||||
{
|
||||
BinaryWriter writer = new BinaryWriter(stream);
|
||||
|
||||
// Write all of the frames
|
||||
int frameCount = frameTimes.Count;
|
||||
writer.Write(frameCount);
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
{
|
||||
writer.Write(frameTimes[i]);
|
||||
}
|
||||
for (int i = 0; i < frameCount; ++i)
|
||||
{
|
||||
OvrAvatarDriver.PoseFrame frame = frames[i];
|
||||
writer.Write(frame);
|
||||
}
|
||||
|
||||
// Write all of the encoded audio packets
|
||||
int audioPacketCount = encodedAudioPackets.Count;
|
||||
writer.Write(audioPacketCount);
|
||||
for (int i = 0; i < audioPacketCount; ++i)
|
||||
{
|
||||
byte[] packet = encodedAudioPackets[i];
|
||||
writer.Write(packet.Length);
|
||||
writer.Write(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class BinaryWriterExtensions
|
||||
{
|
||||
public static void Write(this BinaryWriter writer, OvrAvatarDriver.PoseFrame frame)
|
||||
{
|
||||
writer.Write(frame.headPosition);
|
||||
writer.Write(frame.headRotation);
|
||||
writer.Write(frame.handLeftPosition);
|
||||
writer.Write(frame.handLeftRotation);
|
||||
writer.Write(frame.handRightPosition);
|
||||
writer.Write(frame.handRightRotation);
|
||||
writer.Write(frame.voiceAmplitude);
|
||||
|
||||
writer.Write(frame.controllerLeftPose);
|
||||
writer.Write(frame.controllerRightPose);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter writer, Vector3 vec3)
|
||||
{
|
||||
writer.Write(vec3.x);
|
||||
writer.Write(vec3.y);
|
||||
writer.Write(vec3.z);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter writer, Vector2 vec2)
|
||||
{
|
||||
writer.Write(vec2.x);
|
||||
writer.Write(vec2.y);
|
||||
}
|
||||
|
||||
public static void Write(this BinaryWriter writer, Quaternion quat)
|
||||
{
|
||||
writer.Write(quat.x);
|
||||
writer.Write(quat.y);
|
||||
writer.Write(quat.z);
|
||||
writer.Write(quat.w);
|
||||
}
|
||||
public static void Write(this BinaryWriter writer, OvrAvatarDriver.ControllerPose pose)
|
||||
{
|
||||
writer.Write((uint)pose.buttons);
|
||||
writer.Write((uint)pose.touches);
|
||||
writer.Write(pose.joystickPosition);
|
||||
writer.Write(pose.indexTrigger);
|
||||
writer.Write(pose.handTrigger);
|
||||
writer.Write(pose.isActive);
|
||||
}
|
||||
}
|
||||
|
||||
static class BinaryReaderExtensions
|
||||
{
|
||||
public static OvrAvatarDriver.PoseFrame ReadPoseFrame(this BinaryReader reader)
|
||||
{
|
||||
return new OvrAvatarDriver.PoseFrame
|
||||
{
|
||||
headPosition = reader.ReadVector3(),
|
||||
headRotation = reader.ReadQuaternion(),
|
||||
handLeftPosition = reader.ReadVector3(),
|
||||
handLeftRotation = reader.ReadQuaternion(),
|
||||
handRightPosition = reader.ReadVector3(),
|
||||
handRightRotation = reader.ReadQuaternion(),
|
||||
voiceAmplitude = reader.ReadSingle(),
|
||||
|
||||
controllerLeftPose = reader.ReadControllerPose(),
|
||||
controllerRightPose = reader.ReadControllerPose(),
|
||||
};
|
||||
}
|
||||
|
||||
public static Vector2 ReadVector2(this BinaryReader reader)
|
||||
{
|
||||
return new Vector2
|
||||
{
|
||||
x = reader.ReadSingle(),
|
||||
y = reader.ReadSingle()
|
||||
};
|
||||
}
|
||||
|
||||
public static Vector3 ReadVector3(this BinaryReader reader)
|
||||
{
|
||||
return new Vector3
|
||||
{
|
||||
x = reader.ReadSingle(),
|
||||
y = reader.ReadSingle(),
|
||||
z = reader.ReadSingle()
|
||||
};
|
||||
}
|
||||
|
||||
public static Quaternion ReadQuaternion(this BinaryReader reader)
|
||||
{
|
||||
return new Quaternion
|
||||
{
|
||||
x = reader.ReadSingle(),
|
||||
y = reader.ReadSingle(),
|
||||
z = reader.ReadSingle(),
|
||||
w = reader.ReadSingle(),
|
||||
};
|
||||
}
|
||||
public static OvrAvatarDriver.ControllerPose ReadControllerPose(this BinaryReader reader)
|
||||
{
|
||||
return new OvrAvatarDriver.ControllerPose
|
||||
{
|
||||
buttons = (ovrAvatarButton)reader.ReadUInt32(),
|
||||
touches = (ovrAvatarTouch)reader.ReadUInt32(),
|
||||
joystickPosition = reader.ReadVector2(),
|
||||
indexTrigger = reader.ReadSingle(),
|
||||
handTrigger = reader.ReadSingle(),
|
||||
isActive = reader.ReadBoolean(),
|
||||
};
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarPacket.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarPacket.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b7dd866fbed2654e838d772129dc70c
|
||||
timeCreated: 1464197799
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class OvrAvatarProjectorRenderComponent : OvrAvatarRenderComponent {
|
||||
|
||||
Material material;
|
||||
|
||||
internal void InitializeProjectorRender(ovrAvatarRenderPart_ProjectorRender render, Shader shader, OvrAvatarRenderComponent target)
|
||||
{
|
||||
if (shader == null)
|
||||
{
|
||||
shader = Shader.Find("OvrAvatar/AvatarSurfaceShader");
|
||||
}
|
||||
|
||||
material = CreateAvatarMaterial(gameObject.name + "_projector", shader);
|
||||
material.EnableKeyword("PROJECTOR_ON");
|
||||
|
||||
Renderer renderer = target.GetComponent<Renderer>();
|
||||
if (renderer != null)
|
||||
{
|
||||
List<Material> materials = new List<Material>(renderer.sharedMaterials);
|
||||
materials.Add(material);
|
||||
renderer.sharedMaterials = materials.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
internal void UpdateProjectorRender(OvrAvatarComponent component, ovrAvatarRenderPart_ProjectorRender render)
|
||||
{
|
||||
OvrAvatar.ConvertTransform(render.localTransform, this.transform);
|
||||
material.SetMatrix("_ProjectorWorldToLocal", this.transform.worldToLocalMatrix);
|
||||
component.UpdateAvatarMaterial(material, render.materialState);
|
||||
|
||||
}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
Vector3 v000 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(-1.0f, -1.0f, -1.0f));
|
||||
Vector3 v100 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(+1.0f, -1.0f, -1.0f));
|
||||
Vector3 v010 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(-1.0f, +1.0f, -1.0f));
|
||||
Vector3 v110 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(+1.0f, +1.0f, -1.0f));
|
||||
Vector3 v001 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(-1.0f, -1.0f, +1.0f));
|
||||
Vector3 v101 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(+1.0f, -1.0f, +1.0f));
|
||||
Vector3 v011 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(-1.0f, +1.0f, +1.0f));
|
||||
Vector3 v111 = transform.localToWorldMatrix.MultiplyPoint(new Vector3(+1.0f, +1.0f, +1.0f));
|
||||
|
||||
Gizmos.color = Color.gray;
|
||||
|
||||
Gizmos.DrawLine(v000, v100);
|
||||
Gizmos.DrawLine(v000, v010);
|
||||
Gizmos.DrawLine(v010, v110);
|
||||
Gizmos.DrawLine(v100, v110);
|
||||
|
||||
Gizmos.DrawLine(v000, v001);
|
||||
Gizmos.DrawLine(v100, v101);
|
||||
Gizmos.DrawLine(v010, v011);
|
||||
Gizmos.DrawLine(v110, v111);
|
||||
|
||||
Gizmos.DrawLine(v001, v101);
|
||||
Gizmos.DrawLine(v001, v011);
|
||||
Gizmos.DrawLine(v011, v111);
|
||||
Gizmos.DrawLine(v101, v111);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f909beaa7f33f914b90f9addaedcae18
|
||||
timeCreated: 1479156352
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
121
Assets/Oculus/Avatar/Scripts/OvrAvatarRemoteDriver.cs
Normal file
121
Assets/Oculus/Avatar/Scripts/OvrAvatarRemoteDriver.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Oculus.Avatar;
|
||||
|
||||
public class OvrAvatarRemoteDriver : OvrAvatarDriver
|
||||
{
|
||||
Queue<OvrAvatarPacket> packetQueue = new Queue<OvrAvatarPacket>();
|
||||
|
||||
IntPtr CurrentSDKPacket = IntPtr.Zero;
|
||||
float CurrentPacketTime = 0f;
|
||||
|
||||
const int MinPacketQueue = 1;
|
||||
const int MaxPacketQueue = 4;
|
||||
|
||||
int CurrentSequence = -1;
|
||||
|
||||
// Used for legacy Unity only packet blending
|
||||
bool isStreaming = false;
|
||||
OvrAvatarPacket currentPacket = null;
|
||||
|
||||
public void QueuePacket(int sequence, OvrAvatarPacket packet)
|
||||
{
|
||||
if (sequence > CurrentSequence)
|
||||
{
|
||||
CurrentSequence = sequence;
|
||||
packetQueue.Enqueue(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateTransforms(IntPtr sdkAvatar)
|
||||
{
|
||||
switch(Mode)
|
||||
{
|
||||
case PacketMode.SDK:
|
||||
UpdateFromSDKPacket(sdkAvatar);
|
||||
break;
|
||||
case PacketMode.Unity:
|
||||
UpdateFromUnityPacket(sdkAvatar);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFromSDKPacket(IntPtr sdkAvatar)
|
||||
{
|
||||
|
||||
if (CurrentSDKPacket == IntPtr.Zero && packetQueue.Count >= MinPacketQueue)
|
||||
{
|
||||
CurrentSDKPacket = packetQueue.Dequeue().ovrNativePacket;
|
||||
}
|
||||
|
||||
if (CurrentSDKPacket != IntPtr.Zero)
|
||||
{
|
||||
float PacketDuration = CAPI.ovrAvatarPacket_GetDurationSeconds(CurrentSDKPacket);
|
||||
CAPI.ovrAvatar_UpdatePoseFromPacket(sdkAvatar, CurrentSDKPacket, Mathf.Min(PacketDuration, CurrentPacketTime));
|
||||
CurrentPacketTime += Time.deltaTime;
|
||||
|
||||
if (CurrentPacketTime > PacketDuration)
|
||||
{
|
||||
CAPI.ovrAvatarPacket_Free(CurrentSDKPacket);
|
||||
CurrentSDKPacket = IntPtr.Zero;
|
||||
CurrentPacketTime = CurrentPacketTime - PacketDuration;
|
||||
|
||||
//Throw away packets deemed too old.
|
||||
while (packetQueue.Count > MaxPacketQueue)
|
||||
{
|
||||
packetQueue.Dequeue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFromUnityPacket(IntPtr sdkAvatar)
|
||||
{
|
||||
// If we're not currently streaming, check to see if we've buffered enough
|
||||
if (!isStreaming && packetQueue.Count > MinPacketQueue)
|
||||
{
|
||||
currentPacket = packetQueue.Dequeue();
|
||||
isStreaming = true;
|
||||
}
|
||||
|
||||
// If we are streaming, update our pose
|
||||
if (isStreaming)
|
||||
{
|
||||
CurrentPacketTime += Time.deltaTime;
|
||||
|
||||
// If we've elapsed past our current packet, advance
|
||||
while (CurrentPacketTime > currentPacket.Duration)
|
||||
{
|
||||
|
||||
// If we're out of packets, stop streaming and
|
||||
// lock to the final frame
|
||||
if (packetQueue.Count == 0)
|
||||
{
|
||||
CurrentPose = currentPacket.FinalFrame;
|
||||
CurrentPacketTime = 0.0f;
|
||||
currentPacket = null;
|
||||
isStreaming = false;
|
||||
return;
|
||||
}
|
||||
|
||||
while (packetQueue.Count > MaxPacketQueue)
|
||||
{
|
||||
packetQueue.Dequeue();
|
||||
}
|
||||
|
||||
// Otherwise, dequeue the next packet
|
||||
CurrentPacketTime -= currentPacket.Duration;
|
||||
currentPacket = packetQueue.Dequeue();
|
||||
}
|
||||
|
||||
// Compute the pose based on our current time offset in the packet
|
||||
CurrentPose = currentPacket.GetPoseFrame(CurrentPacketTime);
|
||||
|
||||
UpdateTransformsFromPose(sdkAvatar);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarRemoteDriver.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarRemoteDriver.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c198a42a3843ca04fa633b60f428ff51
|
||||
timeCreated: 1464302604
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
109
Assets/Oculus/Avatar/Scripts/OvrAvatarRenderComponent.cs
Normal file
109
Assets/Oculus/Avatar/Scripts/OvrAvatarRenderComponent.cs
Normal file
@@ -0,0 +1,109 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Oculus.Avatar;
|
||||
|
||||
public class OvrAvatarRenderComponent : MonoBehaviour {
|
||||
|
||||
private bool firstSkinnedUpdate = true;
|
||||
public SkinnedMeshRenderer mesh;
|
||||
public Transform[] bones;
|
||||
|
||||
protected void UpdateActive(OvrAvatar avatar, ovrAvatarVisibilityFlags mask)
|
||||
{
|
||||
bool active = avatar.ShowFirstPerson && (mask & ovrAvatarVisibilityFlags.FirstPerson) != 0;
|
||||
active |= avatar.ShowThirdPerson && (mask & ovrAvatarVisibilityFlags.ThirdPerson) != 0;
|
||||
this.gameObject.SetActive(active);
|
||||
}
|
||||
|
||||
protected SkinnedMeshRenderer CreateSkinnedMesh(ulong assetID, ovrAvatarVisibilityFlags visibilityMask, int thirdPersonLayer, int firstPersonLayer, int sortingOrder)
|
||||
{
|
||||
OvrAvatarAssetMesh meshAsset = (OvrAvatarAssetMesh)OvrAvatarSDKManager.Instance.GetAsset(assetID);
|
||||
if (meshAsset == null)
|
||||
{
|
||||
throw new Exception("Couldn't find mesh for asset " + assetID);
|
||||
}
|
||||
if ((visibilityMask & ovrAvatarVisibilityFlags.ThirdPerson) != 0)
|
||||
{
|
||||
this.gameObject.layer = thirdPersonLayer;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.gameObject.layer = firstPersonLayer;
|
||||
}
|
||||
SkinnedMeshRenderer renderer = meshAsset.CreateSkinnedMeshRendererOnObject(gameObject);
|
||||
renderer.quality = SkinQuality.Bone4;
|
||||
renderer.sortingOrder = sortingOrder;
|
||||
renderer.updateWhenOffscreen = true;
|
||||
if ((visibilityMask & ovrAvatarVisibilityFlags.SelfOccluding) == 0)
|
||||
{
|
||||
renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
|
||||
}
|
||||
return renderer;
|
||||
}
|
||||
|
||||
protected void UpdateSkinnedMesh(OvrAvatar avatar, Transform[] bones, ovrAvatarTransform localTransform, ovrAvatarVisibilityFlags visibilityMask, IntPtr renderPart)
|
||||
{
|
||||
UpdateActive(avatar, visibilityMask);
|
||||
OvrAvatar.ConvertTransform(localTransform, this.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.SkinnedMeshRender:
|
||||
transform = CAPI.ovrAvatarSkinnedMeshRender_GetJointTransform(renderPart, i);
|
||||
break;
|
||||
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);
|
||||
}
|
||||
OvrAvatar.ConvertTransform(transform, targetBone);
|
||||
}
|
||||
}
|
||||
firstSkinnedUpdate = false;
|
||||
}
|
||||
|
||||
protected 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a9e8691abb99884880df5ecada5e4d8
|
||||
timeCreated: 1479155394
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1059
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKCAPI.cs
Normal file
1059
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKCAPI.cs
Normal file
File diff suppressed because it is too large
Load Diff
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKCAPI.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKCAPI.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0348026b48363904bb332b53a21c35b2
|
||||
timeCreated: 1474928508
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
243
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKManager.cs
Normal file
243
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKManager.cs
Normal file
@@ -0,0 +1,243 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using Oculus.Avatar;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public delegate void specificationCallback(IntPtr specification);
|
||||
public delegate void assetLoadedCallback(OvrAvatarAsset asset);
|
||||
public delegate void combinedMeshLoadedCallback(IntPtr asset);
|
||||
|
||||
public class OvrAvatarSDKManager : MonoBehaviour
|
||||
{
|
||||
private static OvrAvatarSDKManager _instance;
|
||||
private Dictionary<UInt64, HashSet<specificationCallback>> specificationCallbacks;
|
||||
private Dictionary<UInt64, HashSet<assetLoadedCallback>> assetLoadedCallbacks;
|
||||
private Dictionary<IntPtr, combinedMeshLoadedCallback> combinedMeshLoadedCallbacks;
|
||||
private Dictionary<UInt64, OvrAvatarAsset> assetCache;
|
||||
|
||||
public static OvrAvatarSDKManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = GameObject.FindObjectOfType<OvrAvatarSDKManager>();
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject manager = new GameObject("OvrAvatarSDKManager");
|
||||
_instance = manager.AddComponent<OvrAvatarSDKManager>();
|
||||
_instance.Initialize();
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
string appId = OvrAvatarSettings.GearAppID;
|
||||
if (appId == "")
|
||||
{
|
||||
AvatarLogger.Log("No Gear VR App ID has been provided. Go to Oculus Avatar > Edit Configuration to supply one", OvrAvatarSettings.Instance);
|
||||
appId = "0";
|
||||
}
|
||||
|
||||
CAPI.ovrAvatar_InitializeAndroidUnity(appId);
|
||||
#else
|
||||
string appId = OvrAvatarSettings.AppID;
|
||||
if (appId == "")
|
||||
{
|
||||
AvatarLogger.Log("No Oculus Rift App ID has been provided. Go to Oculus Avatar > Edit Configuration to supply one", OvrAvatarSettings.Instance);
|
||||
appId = "0";
|
||||
}
|
||||
|
||||
CAPI.ovrAvatar_Initialize(appId);
|
||||
#endif
|
||||
specificationCallbacks = new Dictionary<UInt64, HashSet<specificationCallback>>();
|
||||
assetLoadedCallbacks = new Dictionary<UInt64, HashSet<assetLoadedCallback>>();
|
||||
combinedMeshLoadedCallbacks = new Dictionary<IntPtr, combinedMeshLoadedCallback>();
|
||||
assetCache = new Dictionary<ulong, OvrAvatarAsset>();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
CAPI.ovrAvatar_Shutdown();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update () {
|
||||
IntPtr message = CAPI.ovrAvatarMessage_Pop();
|
||||
if (message == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ovrAvatarMessageType messageType = CAPI.ovrAvatarMessage_GetType(message);
|
||||
switch (messageType)
|
||||
{
|
||||
case ovrAvatarMessageType.AssetLoaded:
|
||||
{
|
||||
ovrAvatarMessage_AssetLoaded assetMessage = CAPI.ovrAvatarMessage_GetAssetLoaded(message);
|
||||
IntPtr asset = assetMessage.asset;
|
||||
UInt64 assetID = assetMessage.assetID;
|
||||
ovrAvatarAssetType assetType = CAPI.ovrAvatarAsset_GetType(asset);
|
||||
OvrAvatarAsset assetData;
|
||||
IntPtr avatarOwner = IntPtr.Zero;
|
||||
|
||||
switch (assetType)
|
||||
{
|
||||
case ovrAvatarAssetType.Mesh:
|
||||
assetData = new OvrAvatarAssetMesh(assetID, asset, ovrAvatarAssetType.Mesh);
|
||||
break;
|
||||
case ovrAvatarAssetType.Texture:
|
||||
assetData = new OvrAvatarAssetTexture(assetID, asset);
|
||||
break;
|
||||
case ovrAvatarAssetType.Material:
|
||||
assetData = new OvrAvatarAssetMaterial(assetID, asset);
|
||||
break;
|
||||
case ovrAvatarAssetType.CombinedMesh:
|
||||
avatarOwner = CAPI.ovrAvatarAsset_GetAvatar(asset);
|
||||
assetData = new OvrAvatarAssetMesh(assetID, asset, ovrAvatarAssetType.CombinedMesh);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(string.Format("Unsupported asset type format {0}", assetType.ToString()));
|
||||
}
|
||||
|
||||
HashSet<assetLoadedCallback> callbackSet;
|
||||
if (assetType == ovrAvatarAssetType.CombinedMesh)
|
||||
{
|
||||
if (!assetCache.ContainsKey(assetID))
|
||||
{
|
||||
assetCache.Add(assetID, assetData);
|
||||
}
|
||||
|
||||
combinedMeshLoadedCallback callback;
|
||||
if (combinedMeshLoadedCallbacks.TryGetValue(avatarOwner, out callback))
|
||||
{
|
||||
callback(asset);
|
||||
combinedMeshLoadedCallbacks.Remove(avatarOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
AvatarLogger.LogWarning("Loaded a combined mesh with no owner: " + assetMessage.assetID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (assetLoadedCallbacks.TryGetValue(assetMessage.assetID, out callbackSet))
|
||||
{
|
||||
assetCache.Add(assetID, assetData);
|
||||
|
||||
foreach (var callback in callbackSet)
|
||||
{
|
||||
callback(assetData);
|
||||
}
|
||||
|
||||
assetLoadedCallbacks.Remove(assetMessage.assetID);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ovrAvatarMessageType.AvatarSpecification:
|
||||
{
|
||||
ovrAvatarMessage_AvatarSpecification spec = CAPI.ovrAvatarMessage_GetAvatarSpecification(message);
|
||||
HashSet<specificationCallback> callbackSet;
|
||||
if (specificationCallbacks.TryGetValue(spec.oculusUserID, out callbackSet))
|
||||
{
|
||||
foreach (var callback in callbackSet)
|
||||
{
|
||||
callback(spec.avatarSpec);
|
||||
}
|
||||
|
||||
specificationCallbacks.Remove(spec.oculusUserID);
|
||||
}
|
||||
else
|
||||
{
|
||||
AvatarLogger.LogWarning("Error, got an avatar specification callback from a user id we don't have a record for: " + spec.oculusUserID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new NotImplementedException("Unhandled ovrAvatarMessageType: " + messageType);
|
||||
}
|
||||
CAPI.ovrAvatarMessage_Free(message);
|
||||
}
|
||||
|
||||
public void RequestAvatarSpecification(
|
||||
UInt64 userId,
|
||||
specificationCallback callback,
|
||||
bool useCombinedMesh,
|
||||
ovrAvatarAssetLevelOfDetail lod,
|
||||
bool forceMobileTextureFormat)
|
||||
{
|
||||
CAPI.ovrAvatar_SetForceASTCTextures(forceMobileTextureFormat);
|
||||
|
||||
HashSet<specificationCallback> callbackSet;
|
||||
if (!specificationCallbacks.TryGetValue(userId, out callbackSet))
|
||||
{
|
||||
callbackSet = new HashSet<specificationCallback>();
|
||||
specificationCallbacks.Add(userId, callbackSet);
|
||||
|
||||
IntPtr specRequest = CAPI.ovrAvatarSpecificationRequest_Create(userId);
|
||||
CAPI.ovrAvatarSpecificationRequest_SetLookAndFeelVersion(specRequest, ovrAvatarLookAndFeelVersion.Two);
|
||||
CAPI.ovrAvatarSpecificationRequest_SetFallbackLookAndFeelVersion(specRequest, ovrAvatarLookAndFeelVersion.One);
|
||||
CAPI.ovrAvatarSpecificationRequest_SetLevelOfDetail(specRequest, lod);
|
||||
CAPI.ovrAvatarSpecificationRequest_SetCombineMeshes(specRequest, useCombinedMesh);
|
||||
CAPI.ovrAvatar_RequestAvatarSpecificationFromSpecRequest(specRequest);
|
||||
CAPI.ovrAvatarSpecificationRequest_Destroy(specRequest);
|
||||
}
|
||||
|
||||
callbackSet.Add(callback);
|
||||
}
|
||||
|
||||
public void BeginLoadingAsset(
|
||||
UInt64 assetId,
|
||||
ovrAvatarAssetLevelOfDetail lod,
|
||||
assetLoadedCallback callback)
|
||||
{
|
||||
HashSet<assetLoadedCallback> callbackSet;
|
||||
if (!assetLoadedCallbacks.TryGetValue(assetId, out callbackSet))
|
||||
{
|
||||
callbackSet = new HashSet<assetLoadedCallback>();
|
||||
assetLoadedCallbacks.Add(assetId, callbackSet);
|
||||
}
|
||||
|
||||
AvatarLogger.Log("Loading Asset ID: " + assetId);
|
||||
|
||||
CAPI.ovrAvatarAsset_BeginLoadingLOD(assetId, lod);
|
||||
callbackSet.Add(callback);
|
||||
}
|
||||
|
||||
public void RegisterCombinedMeshCallback(
|
||||
IntPtr sdkAvatar,
|
||||
combinedMeshLoadedCallback callback)
|
||||
{
|
||||
combinedMeshLoadedCallback currentCallback;
|
||||
if (!combinedMeshLoadedCallbacks.TryGetValue(sdkAvatar, out currentCallback))
|
||||
{
|
||||
combinedMeshLoadedCallbacks.Add(sdkAvatar, callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Adding second combind mesh callback for same avatar");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public OvrAvatarAsset GetAsset(UInt64 assetId)
|
||||
{
|
||||
OvrAvatarAsset asset;
|
||||
if (assetCache.TryGetValue(assetId, out asset))
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKManager.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSDKManager.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ba08ec2733a3a54fbc9490f0f4ab2f0
|
||||
timeCreated: 1475011862
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
65
Assets/Oculus/Avatar/Scripts/OvrAvatarSettings.cs
Normal file
65
Assets/Oculus/Avatar/Scripts/OvrAvatarSettings.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[UnityEditor.InitializeOnLoad]
|
||||
#endif
|
||||
public sealed class OvrAvatarSettings : ScriptableObject {
|
||||
public static string AppID
|
||||
{
|
||||
get { return Instance.ovrAppID; }
|
||||
set { Instance.ovrAppID = value; }
|
||||
}
|
||||
|
||||
public static string GearAppID
|
||||
{
|
||||
get { return Instance.ovrGearAppID; }
|
||||
set { Instance.ovrGearAppID = value; }
|
||||
}
|
||||
|
||||
private static OvrAvatarSettings instance;
|
||||
public static OvrAvatarSettings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = Resources.Load<OvrAvatarSettings>("OvrAvatarSettings");
|
||||
|
||||
// This can happen if the developer never input their App Id into the Unity Editor
|
||||
// Use a dummy object with defaults for the getters so we don't have a null pointer exception
|
||||
if (instance == null)
|
||||
{
|
||||
instance = ScriptableObject.CreateInstance<OvrAvatarSettings>();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// Only in the editor should we save it to disk
|
||||
string properPath = System.IO.Path.Combine(UnityEngine.Application.dataPath, "Resources");
|
||||
if (!System.IO.Directory.Exists(properPath))
|
||||
{
|
||||
UnityEditor.AssetDatabase.CreateFolder("Assets", "Resources");
|
||||
}
|
||||
|
||||
string fullPath = System.IO.Path.Combine(
|
||||
System.IO.Path.Combine("Assets", "Resources"),
|
||||
"OvrAvatarSettings.asset"
|
||||
);
|
||||
UnityEditor.AssetDatabase.CreateAsset(instance, fullPath);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
instance = value;
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private string ovrAppID = "";
|
||||
|
||||
[SerializeField]
|
||||
private string ovrGearAppID = "";
|
||||
}
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSettings.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSettings.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70c2f484f132c044097f03d65cac3b24
|
||||
timeCreated: 1478024706
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
44
Assets/Oculus/Avatar/Scripts/OvrAvatarSettingsEditor.cs
Normal file
44
Assets/Oculus/Avatar/Scripts/OvrAvatarSettingsEditor.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEditor;
|
||||
|
||||
[CustomEditor(typeof(OvrAvatarSettings))]
|
||||
public class OvrAvatarSettingsEditor : Editor {
|
||||
GUIContent appIDLabel = new GUIContent("Oculus Rift App Id [?]",
|
||||
"This AppID will be used for OvrAvatar registration.");
|
||||
|
||||
GUIContent gearAppIDLabel = new GUIContent("Gear VR App Id [?]",
|
||||
"This AppID will be used for OvrAvatar registration when building to the Android target.");
|
||||
|
||||
[UnityEditor.MenuItem("Oculus Avatars/Edit Configuration")]
|
||||
public static void Edit()
|
||||
{
|
||||
var settings = OvrAvatarSettings.Instance;
|
||||
UnityEditor.Selection.activeObject = settings;
|
||||
}
|
||||
|
||||
private static string MakeTextBox(GUIContent label, string variable) {
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUILayout.LabelField(label);
|
||||
GUI.changed = false;
|
||||
var result = EditorGUILayout.TextField(variable);
|
||||
if (GUI.changed)
|
||||
{
|
||||
EditorUtility.SetDirty(OvrAvatarSettings.Instance);
|
||||
GUI.changed = false;
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
return result;
|
||||
}
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.BeginVertical();
|
||||
OvrAvatarSettings.AppID =
|
||||
OvrAvatarSettingsEditor.MakeTextBox(appIDLabel, OvrAvatarSettings.AppID);
|
||||
OvrAvatarSettings.GearAppID =
|
||||
OvrAvatarSettingsEditor.MakeTextBox(gearAppIDLabel, OvrAvatarSettings.GearAppID);
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSettingsEditor.cs.meta
Normal file
12
Assets/Oculus/Avatar/Scripts/OvrAvatarSettingsEditor.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1511f2aaa4ab15e4b8a0ac1a805a402b
|
||||
timeCreated: 1478024800
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using Oculus.Avatar;
|
||||
|
||||
public class OvrAvatarSkinnedMeshRenderComponent : OvrAvatarRenderComponent
|
||||
{
|
||||
Shader surface;
|
||||
Shader surfaceSelfOccluding;
|
||||
bool previouslyActive = false;
|
||||
|
||||
internal void Initialize(ovrAvatarRenderPart_SkinnedMeshRender skinnedMeshRender, Shader surface, Shader surfaceSelfOccluding, int thirdPersonLayer, int firstPersonLayer, int sortOrder)
|
||||
{
|
||||
this.surfaceSelfOccluding = surfaceSelfOccluding != null ? surfaceSelfOccluding : Shader.Find("OvrAvatar/AvatarSurfaceShaderSelfOccluding");
|
||||
this.surface = surface != null ? surface : Shader.Find("OvrAvatar/AvatarSurfaceShader");
|
||||
this.mesh = CreateSkinnedMesh(skinnedMeshRender.meshAssetID, skinnedMeshRender.visibilityMask, thirdPersonLayer, firstPersonLayer, sortOrder);
|
||||
bones = mesh.bones;
|
||||
UpdateMeshMaterial(skinnedMeshRender.visibilityMask, mesh);
|
||||
}
|
||||
|
||||
public void UpdateSkinnedMeshRender(OvrAvatarComponent component, OvrAvatar avatar, IntPtr renderPart)
|
||||
{
|
||||
ovrAvatarVisibilityFlags visibilityMask = CAPI.ovrAvatarSkinnedMeshRender_GetVisibilityMask(renderPart);
|
||||
ovrAvatarTransform localTransform = CAPI.ovrAvatarSkinnedMeshRender_GetTransform(renderPart);
|
||||
UpdateSkinnedMesh(avatar, bones, localTransform, visibilityMask, renderPart);
|
||||
|
||||
UpdateMeshMaterial(visibilityMask, mesh);
|
||||
bool isActive = this.gameObject.activeSelf;
|
||||
|
||||
if( mesh != null )
|
||||
{
|
||||
bool changedMaterial = CAPI.ovrAvatarSkinnedMeshRender_MaterialStateChanged(renderPart);
|
||||
if (changedMaterial || (!previouslyActive && isActive))
|
||||
{
|
||||
ovrAvatarMaterialState materialState = CAPI.ovrAvatarSkinnedMeshRender_GetMaterialState(renderPart);
|
||||
component.UpdateAvatarMaterial(mesh.sharedMaterial, materialState);
|
||||
}
|
||||
}
|
||||
previouslyActive = isActive;
|
||||
}
|
||||
|
||||
private void UpdateMeshMaterial(ovrAvatarVisibilityFlags visibilityMask, SkinnedMeshRenderer rootMesh)
|
||||
{
|
||||
Shader shader = (visibilityMask & ovrAvatarVisibilityFlags.SelfOccluding) != 0 ? surfaceSelfOccluding : surface;
|
||||
if (rootMesh.sharedMaterial == null || rootMesh.sharedMaterial.shader != shader)
|
||||
{
|
||||
rootMesh.sharedMaterial = CreateAvatarMaterial(gameObject.name + "_material", shader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4efdf8bc42b8b8843aff4ca38233f362
|
||||
timeCreated: 1479156282
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using Oculus.Avatar;
|
||||
|
||||
public class OvrAvatarSkinnedMeshRenderPBSComponent : OvrAvatarRenderComponent {
|
||||
|
||||
internal void Initialize(ovrAvatarRenderPart_SkinnedMeshRenderPBS skinnedMeshRenderPBS, Shader shader, int thirdPersonLayer, int firstPersonLayer, int sortOrder)
|
||||
{
|
||||
if (shader == null)
|
||||
{
|
||||
shader = Shader.Find("OvrAvatar/AvatarSurfaceShaderPBS");
|
||||
}
|
||||
mesh = CreateSkinnedMesh(skinnedMeshRenderPBS.meshAssetID, skinnedMeshRenderPBS.visibilityMask, thirdPersonLayer, firstPersonLayer, sortOrder);
|
||||
mesh.sharedMaterial = CreateAvatarMaterial(gameObject.name + "_material", shader);
|
||||
bones = mesh.bones;
|
||||
}
|
||||
|
||||
internal void UpdateSkinnedMeshRenderPBS(OvrAvatar avatar, IntPtr renderPart, Material mat)
|
||||
{
|
||||
ovrAvatarVisibilityFlags visibilityMask = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetVisibilityMask(renderPart);
|
||||
ovrAvatarTransform localTransform = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetTransform(renderPart);
|
||||
UpdateSkinnedMesh(avatar, bones, localTransform, visibilityMask, renderPart);
|
||||
|
||||
UInt64 albedoTextureID = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetAlbedoTextureAssetID(renderPart);
|
||||
UInt64 surfaceTextureID = CAPI.ovrAvatarSkinnedMeshRenderPBS_GetSurfaceTextureAssetID(renderPart);
|
||||
mat.SetTexture("_Albedo", OvrAvatarComponent.GetLoadedTexture(albedoTextureID));
|
||||
mat.SetTexture("_Surface", OvrAvatarComponent.GetLoadedTexture(surfaceTextureID));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69cc01a6441317c4c8a6e24d979cc1b0
|
||||
timeCreated: 1479158964
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,189 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Security.Policy;
|
||||
using Oculus.Avatar;
|
||||
|
||||
public class OvrAvatarSkinnedMeshPBSV2RenderComponent : OvrAvatarRenderComponent
|
||||
{
|
||||
public OvrAvatarMaterialManager AvatarMaterialManager;
|
||||
bool PreviouslyActive = false;
|
||||
bool IsCombinedMaterial = false;
|
||||
|
||||
internal void Initialize(
|
||||
IntPtr renderPart,
|
||||
ovrAvatarRenderPart_SkinnedMeshRenderPBS_V2 skinnedMeshRender,
|
||||
OvrAvatarMaterialManager materialManager,
|
||||
int thirdPersonLayer,
|
||||
int firstPersonLayer,
|
||||
int sortOrder,
|
||||
bool isCombinedMaterial,
|
||||
ovrAvatarAssetLevelOfDetail lod)
|
||||
{
|
||||
AvatarMaterialManager = materialManager;
|
||||
IsCombinedMaterial = isCombinedMaterial;
|
||||
|
||||
mesh = CreateSkinnedMesh(
|
||||
skinnedMeshRender.meshAssetID,
|
||||
skinnedMeshRender.visibilityMask,
|
||||
thirdPersonLayer,
|
||||
firstPersonLayer,
|
||||
sortOrder);
|
||||
|
||||
#if UNITY_ANDROID
|
||||
var singleComponentShader = "OvrAvatar/Avatar_Mobile_SingleComponent";
|
||||
#else
|
||||
var singleComponentShader = "OvrAvatar/Avatar_PC_SingleComponent";
|
||||
#endif
|
||||
|
||||
var shader = IsCombinedMaterial
|
||||
? Shader.Find("OvrAvatar/Avatar_Mobile_CombinedMesh")
|
||||
: Shader.Find(singleComponentShader);
|
||||
|
||||
AvatarLogger.Log("Shader is: " + shader.name);
|
||||
|
||||
mesh.sharedMaterial = CreateAvatarMaterial(gameObject.name + "_material", shader);
|
||||
mesh.sharedMaterial.renderQueue = OvrAvatarMaterialManager.RENDER_QUEUE;
|
||||
|
||||
bones = mesh.bones;
|
||||
|
||||
if (IsCombinedMaterial)
|
||||
{
|
||||
AvatarMaterialManager.SetRenderer(mesh);
|
||||
InitializeCombinedMaterial(renderPart, (int)lod - 1);
|
||||
AvatarMaterialManager.OnCombinedMeshReady();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateSkinnedMeshRender(
|
||||
OvrAvatarComponent component,
|
||||
OvrAvatar avatar,
|
||||
IntPtr renderPart)
|
||||
{
|
||||
ovrAvatarVisibilityFlags visibilityMask
|
||||
= CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetVisibilityMask(renderPart);
|
||||
|
||||
ovrAvatarTransform localTransform
|
||||
= CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetTransform(renderPart);
|
||||
|
||||
UpdateSkinnedMesh(avatar, bones, localTransform, visibilityMask, renderPart);
|
||||
|
||||
bool isActive = gameObject.activeSelf;
|
||||
|
||||
if (mesh != null && !PreviouslyActive && isActive)
|
||||
{
|
||||
if (!IsCombinedMaterial)
|
||||
{
|
||||
InitializeSingleComponentMaterial(renderPart, (int)avatar.LevelOfDetail - 1);
|
||||
}
|
||||
}
|
||||
|
||||
PreviouslyActive = isActive;
|
||||
}
|
||||
|
||||
private void InitializeSingleComponentMaterial(IntPtr renderPart, int lodIndex)
|
||||
{
|
||||
ovrAvatarPBSMaterialState materialState =
|
||||
CAPI.ovrAvatarSkinnedMeshRenderPBSV2_GetPBSMaterialState(renderPart);
|
||||
|
||||
int componentType = (int)OvrAvatarMaterialManager.GetComponentType(gameObject.name);
|
||||
|
||||
var defaultProperties = AvatarMaterialManager.DefaultAvatarConfig.ComponentMaterialProperties;
|
||||
|
||||
var diffuseTexture = OvrAvatarComponent.GetLoadedTexture(materialState.albedoTextureID);
|
||||
var normalTexture = OvrAvatarComponent.GetLoadedTexture(materialState.normalTextureID);
|
||||
var metallicTexture = OvrAvatarComponent.GetLoadedTexture(materialState.metallicnessTextureID);
|
||||
|
||||
if (diffuseTexture == null)
|
||||
{
|
||||
diffuseTexture = AvatarMaterialManager.DiffuseFallbacks[lodIndex];
|
||||
}
|
||||
|
||||
if (normalTexture == null)
|
||||
{
|
||||
normalTexture = AvatarMaterialManager.NormalFallbacks[lodIndex];
|
||||
}
|
||||
|
||||
if (metallicTexture == null)
|
||||
{
|
||||
metallicTexture = AvatarMaterialManager.DiffuseFallbacks[lodIndex];
|
||||
}
|
||||
|
||||
mesh.sharedMaterial.SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_MAINTEX, diffuseTexture);
|
||||
mesh.sharedMaterial.SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_NORMALMAP, normalTexture);
|
||||
mesh.sharedMaterial.SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_ROUGHNESSMAP, metallicTexture);
|
||||
|
||||
mesh.sharedMaterial.SetVector(OvrAvatarMaterialManager.AVATAR_SHADER_COLOR,
|
||||
materialState.albedoMultiplier);
|
||||
|
||||
mesh.sharedMaterial.SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_DIFFUSEINTENSITY,
|
||||
defaultProperties[componentType].DiffuseIntensity);
|
||||
|
||||
mesh.sharedMaterial.SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_RIMINTENSITY,
|
||||
defaultProperties[componentType].RimIntensity);
|
||||
|
||||
mesh.sharedMaterial.SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_BACKLIGHTINTENSITY,
|
||||
defaultProperties[componentType].BacklightIntensity);
|
||||
|
||||
mesh.sharedMaterial.SetFloat(OvrAvatarMaterialManager.AVATAR_SHADER_REFLECTIONINTENSITY,
|
||||
defaultProperties[componentType].ReflectionIntensity);
|
||||
|
||||
mesh.GetClosestReflectionProbes(AvatarMaterialManager.ReflectionProbes);
|
||||
if (AvatarMaterialManager.ReflectionProbes != null &&
|
||||
AvatarMaterialManager.ReflectionProbes.Count > 0)
|
||||
{
|
||||
mesh.sharedMaterial.SetTexture(OvrAvatarMaterialManager.AVATAR_SHADER_CUBEMAP,
|
||||
AvatarMaterialManager.ReflectionProbes[0].probe.texture);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
mesh.sharedMaterial.EnableKeyword("FIX_NORMAL_ON");
|
||||
#endif
|
||||
mesh.sharedMaterial.EnableKeyword("PBR_LIGHTING_ON");
|
||||
}
|
||||
|
||||
private void InitializeCombinedMaterial(IntPtr renderPart, int lodIndex)
|
||||
{
|
||||
ovrAvatarPBSMaterialState[] materialStates = CAPI.ovrAvatar_GetBodyPBSMaterialStates(renderPart);
|
||||
|
||||
if (materialStates.Length == (int)ovrAvatarBodyPartType.Count)
|
||||
{
|
||||
AvatarMaterialManager.CreateTextureArrays();
|
||||
|
||||
AvatarMaterialManager.LocalAvatarConfig = AvatarMaterialManager.DefaultAvatarConfig;
|
||||
var localProperties = AvatarMaterialManager.LocalAvatarConfig.ComponentMaterialProperties;
|
||||
|
||||
AvatarLogger.Log("InitializeCombinedMaterial - Loading Material States");
|
||||
|
||||
for (int i = 0; i < materialStates.Length; i++)
|
||||
{
|
||||
localProperties[i].TypeIndex = (ovrAvatarBodyPartType)i;
|
||||
localProperties[i].Color = materialStates[i].albedoMultiplier;
|
||||
|
||||
var diffuse = OvrAvatarComponent.GetLoadedTexture(materialStates[i].albedoTextureID);
|
||||
var normal = OvrAvatarComponent.GetLoadedTexture(materialStates[i].normalTextureID);
|
||||
var roughness = OvrAvatarComponent.GetLoadedTexture(materialStates[i].metallicnessTextureID);
|
||||
|
||||
localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.DiffuseTextures]
|
||||
= diffuse == null ? AvatarMaterialManager.DiffuseFallbacks[lodIndex] : diffuse;
|
||||
|
||||
localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.NormalMaps]
|
||||
= normal == null ? AvatarMaterialManager.NormalFallbacks[lodIndex] : normal;
|
||||
|
||||
localProperties[i].Textures[(int)OvrAvatarMaterialManager.TextureType.RoughnessMaps]
|
||||
= roughness == null ? AvatarMaterialManager.DiffuseFallbacks[lodIndex] : roughness;
|
||||
|
||||
AvatarLogger.Log(localProperties[i].TypeIndex.ToString());
|
||||
AvatarLogger.Log(AvatarLogger.Tab + "Diffuse: " + materialStates[i].albedoTextureID);
|
||||
AvatarLogger.Log(AvatarLogger.Tab + "Normal: " + materialStates[i].normalTextureID);
|
||||
AvatarLogger.Log(AvatarLogger.Tab + "Metallic: " + materialStates[i].metallicnessTextureID);
|
||||
}
|
||||
|
||||
AvatarMaterialManager.ValidateTextures();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
mesh.sharedMaterial.EnableKeyword("FIX_NORMAL_ON");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c45906825d398024fbe09e47cc72de24
|
||||
timeCreated: 1511398456
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
130
Assets/Oculus/Avatar/Scripts/OvrAvatarTextureCopyManager.cs
Normal file
130
Assets/Oculus/Avatar/Scripts/OvrAvatarTextureCopyManager.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class OvrAvatarTextureCopyManager : MonoBehaviour
|
||||
{
|
||||
private const int TEXTURES_TO_COPY_QUEUE_CAPACITY = 256;
|
||||
|
||||
struct CopyTextureParams
|
||||
{
|
||||
public Texture Src;
|
||||
public Texture Dst;
|
||||
public int Mip;
|
||||
public int SrcSize;
|
||||
public int DstElement;
|
||||
|
||||
public CopyTextureParams(
|
||||
Texture src,
|
||||
Texture dst,
|
||||
int mip,
|
||||
int srcSize,
|
||||
int dstElement)
|
||||
{
|
||||
Src = src;
|
||||
Dst = dst;
|
||||
Mip = mip;
|
||||
SrcSize = srcSize;
|
||||
DstElement = dstElement;
|
||||
}
|
||||
}
|
||||
|
||||
private Queue<CopyTextureParams> texturesToCopy;
|
||||
|
||||
public OvrAvatarTextureCopyManager()
|
||||
{
|
||||
texturesToCopy = new Queue<CopyTextureParams>(TEXTURES_TO_COPY_QUEUE_CAPACITY);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (texturesToCopy.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CopyTextureParams copyTextureParams;
|
||||
|
||||
lock (texturesToCopy)
|
||||
{
|
||||
copyTextureParams = texturesToCopy.Dequeue();
|
||||
}
|
||||
|
||||
StartCoroutine(CopyTextureCoroutine(copyTextureParams));
|
||||
}
|
||||
|
||||
public int GetTextureCount()
|
||||
{
|
||||
return texturesToCopy.Count;
|
||||
}
|
||||
|
||||
public void CopyTexture(
|
||||
Texture src,
|
||||
Texture dst,
|
||||
int mipLevel,
|
||||
int mipSize,
|
||||
int dstElement,
|
||||
bool useQueue = true)
|
||||
{
|
||||
bool queued = false;
|
||||
var copyTextureParams = new CopyTextureParams(src, dst, mipLevel, mipSize, dstElement);
|
||||
|
||||
if (useQueue)
|
||||
{
|
||||
lock (texturesToCopy)
|
||||
{
|
||||
if (texturesToCopy.Count < TEXTURES_TO_COPY_QUEUE_CAPACITY)
|
||||
{
|
||||
texturesToCopy.Enqueue(copyTextureParams);
|
||||
queued = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyTexture(copyTextureParams);
|
||||
}
|
||||
|
||||
if (!queued)
|
||||
{
|
||||
CopyTexture(copyTextureParams);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator CopyTextureCoroutine(CopyTextureParams copyTextureParams)
|
||||
{
|
||||
// Wait until frame rendering is done
|
||||
yield return new WaitForEndOfFrame();
|
||||
|
||||
Graphics.CopyTexture(
|
||||
copyTextureParams.Src,
|
||||
0,
|
||||
copyTextureParams.Mip,
|
||||
0,
|
||||
0,
|
||||
copyTextureParams.SrcSize,
|
||||
copyTextureParams.SrcSize,
|
||||
copyTextureParams.Dst,
|
||||
copyTextureParams.DstElement,
|
||||
copyTextureParams.Mip,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
|
||||
private void CopyTexture(CopyTextureParams copyTextureParams)
|
||||
{
|
||||
Graphics.CopyTexture(
|
||||
copyTextureParams.Src,
|
||||
0,
|
||||
copyTextureParams.Mip,
|
||||
0,
|
||||
0,
|
||||
copyTextureParams.SrcSize,
|
||||
copyTextureParams.SrcSize,
|
||||
copyTextureParams.Dst,
|
||||
copyTextureParams.DstElement,
|
||||
copyTextureParams.Mip,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb5b00817cd46d645ac8b607693c37ce
|
||||
timeCreated: 1519680044
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Assets/Oculus/Avatar/Scripts/OvrAvatarTouchController.cs
Normal file
7
Assets/Oculus/Avatar/Scripts/OvrAvatarTouchController.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class OvrAvatarTouchController : MonoBehaviour
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77e19ec58d4a9e844970103e5bd8946a
|
||||
timeCreated: 1464050556
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user