Move third party assets to ThirdParty folder

This commit is contained in:
2024-08-08 11:26:28 +02:00
parent 386f303057
commit bd91af6f98
10340 changed files with 100 additions and 175 deletions

View File

@@ -0,0 +1,82 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AddAvatarToSceneMenu.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UnityEditor;
using UnityEngine;
namespace UltimateXR.Editor.Avatar
{
/// <summary>
/// Utility class with menu items to add built-in UltimateXR avatars to the scene.
/// </summary>
public static class AddAvatarToSceneMenu
{
#region Public Methods
[MenuItem(UxrConstants.Editor.MenuPathAddAvatar + "Small Hands Avatar (BRP)", priority = UxrConstants.Editor.PriorityMenuPathAvatar)]
public static void AddSmallHandsAvatarBrp()
{
AddAvatar(SmallHandsAvatarBrpAssetGuid);
}
[MenuItem(UxrConstants.Editor.MenuPathAddAvatar + "Small Hands Avatar (URP)", priority = UxrConstants.Editor.PriorityMenuPathAvatar + 1)]
public static void AddSmallHandsAvatarUrp()
{
AddAvatar(SmallHandsAvatarUrpAssetGuid);
}
[MenuItem(UxrConstants.Editor.MenuPathAddAvatar + "Big Hands Avatar (BRP)", priority = UxrConstants.Editor.PriorityMenuPathAvatar + 2)]
public static void AddBigHandsAvatarBrp()
{
AddAvatar(BigHandsAvatarBrpAssetGuid);
}
[MenuItem(UxrConstants.Editor.MenuPathAddAvatar + "Big Hands Avatar (URP)", priority = UxrConstants.Editor.PriorityMenuPathAvatar + 3)]
public static void AddBigHandsAvatarUrp()
{
AddAvatar(BigHandsAvatarUrpAssetGuid);
}
[MenuItem(UxrConstants.Editor.MenuPathAddAvatar + "Cyborg Avatar (BRP)", priority = UxrConstants.Editor.PriorityMenuPathAvatar + 4)]
public static void AddCyborgAvatarBrp()
{
AddAvatar(CyborgAvatarBrpAssetGuid);
}
[MenuItem(UxrConstants.Editor.MenuPathAddAvatar + "Cyborg Avatar (URP)", priority = UxrConstants.Editor.PriorityMenuPathAvatar + 5)]
public static void AddCyborgAvatarUrp()
{
AddAvatar(CyborgAvatarUrpAssetGuid);
}
#endregion
#region Private Types & Data
private static void AddAvatar(string assetGuid)
{
GameObject avatarAsset = AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(assetGuid));
if (avatarAsset != null)
{
GameObject newInstance = PrefabUtility.InstantiatePrefab(avatarAsset) as GameObject;
newInstance.transform.position = Vector3.zero;
newInstance.transform.rotation = Quaternion.identity;
newInstance.name = avatarAsset.name;
Selection.activeGameObject = newInstance;
}
}
private const string SmallHandsAvatarBrpAssetGuid = "c311edb378c22084c9abc1d944113176";
private const string SmallHandsAvatarUrpAssetGuid = "7195d091dac462e4db9ba0793d9a6727";
private const string BigHandsAvatarBrpAssetGuid = "e7c39828446955c4eb062c0ef1f5eb71";
private const string BigHandsAvatarUrpAssetGuid = "dc011efb41f2d4a419389aefb4b4270d";
private const string CyborgAvatarBrpAssetGuid = "d12ff67997e4a1547890dc7efeb1b11c";
private const string CyborgAvatarUrpAssetGuid = "e7468ec6b7af89c4d94d451ec3c1807b";
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e087a265e2b755f4ba843e1c6295c466
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,172 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3105755673493717711
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6660199555974101477}
m_Layer: 0
m_Name: BigHandGizmoLeft
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6660199555974101477
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3105755673493717711}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3934064300957786961}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &3535928094376264890
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 6660199555974101477}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -6709857489335223893, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5747895058768455926, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_Name
value: Wrist
objectReference: {fileID: 0}
- target: {fileID: -5654198184702395596, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
- target: {fileID: 919132149155446097, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_Name
value: Hand
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3823570585033785298, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3823570585033785298, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3823570585033785298, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3823570585033785298, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3823570585033785298, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4542265952940996083, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
--- !u!4 &3934064300957786961 stripped
Transform:
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 3cc1bfa741063664e8b13a63afcd062f, type: 3}
m_PrefabInstance: {fileID: 3535928094376264890}
m_PrefabAsset: {fileID: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 93019d606e943b7429d29c694143ad6e
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,184 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4805418415246262332
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8582211912875862288}
m_Layer: 0
m_Name: BigHandGizmoRight
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8582211912875862288
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4805418415246262332}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 550750527984811268}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &12967445033245423
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 8582211912875862288}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8646571443531358356, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
- target: {fileID: -7327828634711335260, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
- target: {fileID: -5193524538114237147, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_Name
value: Hand
objectReference: {fileID: 0}
- target: {fileID: 6665695938027609144, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_Name
value: Wrist
objectReference: {fileID: 0}
- target: {fileID: 8731801213580401448, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8731801213580401448, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8731801213580401448, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8731801213580401448, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8857101846222818459, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
--- !u!4 &550750527984811268 stripped
Transform:
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 1de94829f1eb3df4e97553bc8bb8135c, type: 3}
m_PrefabInstance: {fileID: 12967445033245423}
m_PrefabAsset: {fileID: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d45d3edc285cfd64a86fddd771e13f47
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 470a2f8a41647a14a98eec5954b6b218
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,303 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrStandardAvatarControllerEditor.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Linq;
using UltimateXR.Animation.IK;
using UltimateXR.Avatar;
using UltimateXR.Avatar.Controllers;
using UltimateXR.Avatar.Rig;
using UltimateXR.Editor.Animation.IK;
using UltimateXR.Extensions.System.Collections;
using UltimateXR.Extensions.Unity;
using UltimateXR.Manipulation.HandPoses;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
namespace UltimateXR.Editor.Avatar.Controllers
{
/// <summary>
/// Custom inspector for the <see cref="UxrStandardAvatarController" /> component.
/// </summary>
[CustomEditor(typeof(UxrStandardAvatarController))]
public sealed class UxrStandardAvatarControllerEditor : UnityEditor.Editor
{
#region Public Types & Data
public const string PropAllowHandTracking = "_allowHandTracking";
public const string PropUseArmIK = "_useArmIK";
public const string PropArmIKElbowAperture = "_armIKElbowAperture";
public const string PropArmIKOverExtendMode = "_armIKOverExtendMode";
public const string PropUseBodyIK = "_useBodyIK";
public const string PropBodyIKSettings = "_bodyIKSettings";
//public const string PropUseLegIK = "_useLegIK";
public const string PropListControllerEvents = "_listControllerEvents";
#endregion
#region Unity
/// <summary>
/// Caches the serialized properties and initializes data.
/// </summary>
private void OnEnable()
{
UxrStandardAvatarController selectedController = (UxrStandardAvatarController)serializedObject.targetObject;
UxrAvatar avatar = selectedController.Avatar;
_propAllowHandTracking = serializedObject.FindProperty(PropAllowHandTracking);
_propUseArmIK = serializedObject.FindProperty(PropUseArmIK);
_propArmIKElbowAperture = serializedObject.FindProperty(PropArmIKElbowAperture);
_propArmIKOverExtendMode = serializedObject.FindProperty(PropArmIKOverExtendMode);
_propUseBodyIK = serializedObject.FindProperty(PropUseBodyIK);
_propBodyIKSettings = serializedObject.FindProperty(PropBodyIKSettings);
//_propUseLegIK = serializedObject.FindProperty(PropUseLegIK);
_propListControllerEvents = serializedObject.FindProperty(PropListControllerEvents);
if (_propListControllerEvents != null)
{
_reorderableEventList = CreateReorderableList(serializedObject, _propListControllerEvents, DrawControllerEventCallback);
}
// Get avatar info
_reorderableEventList.elementHeightCallback = index =>
{
if (index >= selectedController.ControllerEvents.Count)
{
return 0;
}
UxrHandPoseAsset handPoseAsset = avatar.GetHandPose(selectedController.ControllerEvents[index].PoseName);
return EditorGUIUtility.singleLineHeight * 3.5f + (handPoseAsset && handPoseAsset.PoseType == UxrHandPoseType.Blend ? EditorGUIUtility.singleLineHeight : 0.0f);
};
}
/// <summary>
/// Called by Unity to draw the inspector for the selected component(s).
/// </summary>
public override void OnInspectorGUI()
{
serializedObject.Update();
UxrAvatar avatar = ((UxrStandardAvatarController)serializedObject.targetObject).GetComponent<UxrAvatar>();
// Handle UI
EditorGUILayout.Space();
EditorGUILayout.Space();
_foldoutGeneral = UxrEditorUtils.FoldoutStylish("General", _foldoutGeneral);
if (_foldoutGeneral)
{
EditorGUILayout.PropertyField(_propAllowHandTracking, ContentAllowHandTracking);
}
if (avatar.AvatarRigType == UxrAvatarRigType.HalfOrFullBody)
{
_foldoutIK = UxrEditorUtils.FoldoutStylish("Inverse Kinematics", _foldoutIK);
if (_foldoutIK)
{
EditorGUILayout.PropertyField(_propUseArmIK, ContentUseArmIK);
if (!avatar.AvatarRig.HasArmData())
{
EditorGUILayout.HelpBox($"To use arm IK, the {nameof(UxrAvatar)} component needs arm references in the Avatar Rig section", MessageType.Warning);
}
else
{
if (_propUseArmIK.boolValue)
{
EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
EditorGUILayout.Slider(_propArmIKElbowAperture, 0.0f, 1.0f, ContentArmIKElbowAperture);
if (EditorGUI.EndChangeCheck() && Application.isPlaying)
{
UxrIKSolver.GetComponents(avatar, true).OfType<UxrArmIKSolver>().ForEach(s => s.RelaxedElbowAperture = _propArmIKElbowAperture.floatValue);
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(_propArmIKOverExtendMode, ContentArmIKOverExtendMode);
if (EditorGUI.EndChangeCheck() && Application.isPlaying)
{
UxrIKSolver.GetComponents(avatar, true).OfType<UxrArmIKSolver>().ForEach(s => s.OverExtendMode = (UxrArmOverExtendMode)_propArmIKOverExtendMode.enumValueIndex);
}
EditorGUI.indentLevel--;
}
}
bool hasUpperBodyReferences = avatar.AvatarRig.HasAnyUpperBodyIKReference();
EditorGUILayout.PropertyField(_propUseBodyIK, ContentUseBodyIK);
if (!hasUpperBodyReferences)
{
EditorGUILayout.HelpBox($"To use body IK, the {nameof(UxrAvatar)} component needs upper body references in the Avatar Rig section", MessageType.Warning);
}
GUI.enabled = hasUpperBodyReferences;
if (_propUseBodyIK.boolValue && hasUpperBodyReferences)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(_propBodyIKSettings, ContentBodyIKSettings);
EditorGUI.indentLevel--;
}
GUI.enabled = false;
//EditorGUILayout.PropertyField(_propUseLegIK);
EditorGUILayout.Toggle(ContentUseLegIK, false);
GUI.enabled = true;
}
}
_foldoutHandEvents = UxrEditorUtils.FoldoutStylish("Special Hand Pose Events", _foldoutHandEvents);
if (_foldoutHandEvents)
{
EditorGUILayout.LabelField("Hand poses based on controller input events:", EditorStyles.boldLabel);
if (string.IsNullOrEmpty(avatar.PrefabGuid) || !avatar.GetAllHandPoses().Any())
{
EditorGUILayout.HelpBox($"To start using this functionality add hand poses to the {nameof(UxrAvatar)} component first.", MessageType.Info);
}
else
{
_reorderableEventList?.DoLayoutList();
}
}
serializedObject.ApplyModifiedProperties();
}
/// <summary>
/// Called by Unity to draw gizmos. It's used to display some visual aids when the avatar has a
/// <see cref="UxrAvatarRigType.HalfOrFullBody" /> configuration.
/// </summary>
private void OnSceneGUI()
{
UxrStandardAvatarController standardAvatarController = (UxrStandardAvatarController)serializedObject.targetObject;
UxrAvatar avatar = standardAvatarController.Avatar;
if (standardAvatarController && standardAvatarController.UseBodyIK && avatar && avatar.AvatarRigType == UxrAvatarRigType.HalfOrFullBody)
{
Transform avatarTransform = avatar.transform;
float neckBaseHeight = _propBodyIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyNeckBaseHeight).floatValue;
float neckForwardOffset = _propBodyIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyNeckForwardOffset).floatValue;
float eyesBaseHeight = _propBodyIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyEyesBaseHeight).floatValue;
float eyesForwardOffset = _propBodyIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyEyesForwardOffset).floatValue;
float neckRadius = 0.08f;
float eyesSeparation = 0.065f;
float eyesRadius = 0.01f;
if (avatar.AvatarRig.Head.Neck == null)
{
Handles.DrawSolidDisc(avatarTransform.position + avatarTransform.GetScaledVector(0.0f, neckBaseHeight, neckForwardOffset), avatarTransform.up, neckRadius);
}
Handles.DrawSolidDisc(avatarTransform.position + avatarTransform.GetScaledVector(-eyesSeparation * 0.5f, eyesBaseHeight, eyesForwardOffset), avatarTransform.forward, eyesRadius);
Handles.DrawSolidDisc(avatarTransform.position + avatarTransform.GetScaledVector(eyesSeparation * 0.5f, eyesBaseHeight, eyesForwardOffset), avatarTransform.forward, eyesRadius);
}
}
#endregion
#region Private Methods
/// <summary>
/// Creates a reorderable list for the given controller events.
/// </summary>
/// <param name="serializedObject">Serialized object representing the selected component(s)</param>
/// <param name="propertyListControllerEvents">The serialized property with the controller events</param>
/// <param name="drawCallback">A callback to draw the list</param>
/// <returns></returns>
private static ReorderableList CreateReorderableList(SerializedObject serializedObject, SerializedProperty propertyListControllerEvents, ReorderableList.ElementCallbackDelegate drawCallback)
{
ReorderableList reorderableEventList = new ReorderableList(serializedObject, propertyListControllerEvents, true, true, true, true);
reorderableEventList.drawHeaderCallback = rect => { EditorGUI.LabelField(rect, "Drag elements to reorder them by priority from top to bottom"); };
reorderableEventList.drawElementCallback = drawCallback;
return reorderableEventList;
}
/// <summary>
/// Helper method that draws an event entry in the inspector.
/// </summary>
/// <param name="rect">The rect where to draw the element</param>
/// <param name="index">The element index in the list</param>
/// <param name="isActive">Whether the element is active</param>
/// <param name="isFocused">Whether the element is focused</param>
private void DrawControllerEventCallback(Rect rect, int index, bool isActive, bool isFocused)
{
UxrStandardAvatarController selectedController = (UxrStandardAvatarController)serializedObject.targetObject;
UxrAvatar avatar = selectedController.Avatar;
SerializedProperty element = _reorderableEventList.serializedProperty.GetArrayElementAtIndex(index);
int nLineIndex = 0;
Rect GetCurrentRect()
{
return new Rect(rect.x, rect.y + EditorGUIUtility.singleLineHeight * nLineIndex, rect.width, EditorGUIUtility.singleLineHeight);
}
// Animation type
EditorGUI.PropertyField(GetCurrentRect(), element.FindPropertyRelative("_animationType"), new GUIContent("Animation type"));
nLineIndex++;
// Controller button mask
int buttons = EditorGUI.MaskField(GetCurrentRect(), new GUIContent("Controller button(s)"), element.FindPropertyRelative("_buttons").intValue, UxrEditorUtils.GetControllerButtonNames().ToArray());
element.FindPropertyRelative("_buttons").intValue = buttons;
nLineIndex++;
// List animator parameters
UxrEditorUtils.HandPoseDropdown(GetCurrentRect(), new GUIContent("Hand Pose"), avatar, element.FindPropertyRelative("_handPose"), out UxrHandPoseAsset selectedHandPose);
nLineIndex++;
if (selectedHandPose && selectedHandPose.PoseType == UxrHandPoseType.Blend)
{
element.FindPropertyRelative("_poseBlendValue").floatValue = EditorGUI.Slider(GetCurrentRect(), new GUIContent("Pose Blend"), element.FindPropertyRelative("_poseBlendValue").floatValue, 0.0f, 1.0f);
}
}
#endregion
#region Private Types & Data
private GUIContent ContentAllowHandTracking { get; } = new GUIContent("Allow Hand Tracking", "Switches to hand-tracking to update the avatar hands when available");
private GUIContent ContentUseArmIK { get; } = new GUIContent("Use Arm IK", "Whether to try to naturally orient the arms using the position of the hands");
private GUIContent ContentArmIKElbowAperture { get; } = new GUIContent("Elbow Neutral Aperture", "Controls how close the elbows will be to the body when arms are computed using inverse kinematics");
private GUIContent ContentArmIKOverExtendMode { get; } = new GUIContent("Arm Over-Extend", "Controls what to do when the user extends the hands over the avatar's arm reach");
private GUIContent ContentUseBodyIK { get; } = new GUIContent("Use Body IK", "Whether to try to naturally orient the avatar body using the positions of the head and hand");
private GUIContent ContentBodyIKSettings { get; } = new GUIContent("Body IK Settings");
private GUIContent ContentUseLegIK { get; } = new GUIContent("Use Leg IK (TBD)", "");
private SerializedProperty _propAllowHandTracking;
private SerializedProperty _propUseArmIK;
private SerializedProperty _propArmIKElbowAperture;
private SerializedProperty _propArmIKOverExtendMode;
private SerializedProperty _propUseBodyIK;
private SerializedProperty _propBodyIKSettings;
//private SerializedProperty _propUseLegIK;
private SerializedProperty _propListControllerEvents;
private bool _foldoutGeneral = true;
private bool _foldoutIK = true;
private bool _foldoutHandEvents = true;
private ReorderableList _reorderableEventList;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6b019ea387b41a1438953b9ff201213b
timeCreated: 1501659089
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,123 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-837949187144976569
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 4
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: GizmoMat
m_Shader: {fileID: 4800000, guid: 937ba134f74480c4687ca81e9780b6f9, type: 3}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _AlphaClip: 0
- _Blend: 0
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _Surface: 0
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 0.0087973215, g: 0.6792453, b: 0, a: 0.47058824}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: efed6a9e4d429f64fb8335d6c1b71f6b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,188 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3105755673493717711
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6660199555974101477}
m_Layer: 0
m_Name: SmallHandGizmoLeft
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6660199555974101477
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3105755673493717711}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8739749207329967463}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &9134261997500295820
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 6660199555974101477}
m_Modifications:
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -6709857489335223893, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5654198184702395596, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
- target: {fileID: -3386177114557159912, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -3386177114557159912, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -3386177114557159912, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -3386177114557159912, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -3386177114557159912, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -1276430613889393907, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_Name
value: Wrist
objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_Name
value: Hand
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3291163720618517394, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3352927432503674278, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4542265952940996083, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
--- !u!4 &8739749207329967463 stripped
Transform:
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: 7521758fa660fff47b173d40956b49fb, type: 3}
m_PrefabInstance: {fileID: 9134261997500295820}
m_PrefabAsset: {fileID: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 672e7f52fe868134a80bf396141fe261
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,188 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4805418415246262332
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8582211912875862288}
m_Layer: 0
m_Name: SmallHandGizmoRight
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8582211912875862288
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4805418415246262332}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7394772466370446829}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &6995562589688488454
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 8582211912875862288}
m_Modifications:
- target: {fileID: -8695551014827756411, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_Name
value: Wrist
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_RootOrder
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -8646571443531358356, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
- target: {fileID: -7327828634711335260, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_Materials.Array.data[0]
value:
objectReference: {fileID: 2100000, guid: efed6a9e4d429f64fb8335d6c1b71f6b, type: 2}
- target: {fileID: -5193524538114237147, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -5193524538114237147, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: -147837933818791889, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 919132149155446097, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_Name
value: Hand
objectReference: {fileID: 0}
- target: {fileID: 5426830260529530398, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5426830260529530398, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5426830260529530398, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5426830260529530398, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5426830260529530398, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8857101846222818459, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
--- !u!4 &7394772466370446829 stripped
Transform:
m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: cb9671829f1949c46a89cad7c5fa47dd, type: 3}
m_PrefabInstance: {fileID: 6995562589688488454}
m_PrefabAsset: {fileID: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0a1c1014903295a408b755f1fed2863e
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,855 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrAvatarEditor.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using UltimateXR.Animation.IK;
using UltimateXR.Avatar;
using UltimateXR.Avatar.Controllers;
using UltimateXR.Avatar.Rig;
using UltimateXR.Core;
using UltimateXR.Devices;
using UltimateXR.Editor.Animation.IK;
using UltimateXR.Editor.Avatar.Controllers;
using UltimateXR.Editor.Manipulation.HandPoses;
using UltimateXR.Extensions.System.Collections;
using UltimateXR.Extensions.Unity;
using UltimateXR.Manipulation.HandPoses;
using UltimateXR.Networking;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace UltimateXR.Editor.Avatar
{
/// <summary>
/// Custom editor for <see cref="UxrAvatar" />.
/// </summary>
[CustomEditor(typeof(UxrAvatar))]
public class UxrAvatarEditor : UnityEditor.Editor
{
#region Public Types & Data
public const string PropertyParentPrefab = "_parentPrefab";
public const string PropertyPrefabGuid = "_prefabGuid";
public const string PropertyHandPoses = "_handPoses";
public const string PropertyDefaultHandPose = "_defaultHandPose";
#endregion
#region Unity
/// <summary>
/// Caches serialized properties and initializes the avatar rig expandable field.
/// </summary>
private void OnEnable()
{
_propertyPrefabGuid = serializedObject.FindProperty(PropertyPrefabGuid);
_propertyParentPrefab = serializedObject.FindProperty(PropertyParentPrefab);
_propertyAvatarMode = serializedObject.FindProperty("_avatarMode");
_propertyRenderMode = serializedObject.FindProperty("_renderMode");
_propertyShowControllerHands = serializedObject.FindProperty("_showControllerHands");
_propertyAvatarRenderers = serializedObject.FindProperty("_avatarRenderers");
_propertyRigType = serializedObject.FindProperty("_rigType");
_propertyRigExpandedInitialized = serializedObject.FindProperty("_rigExpandedInitialized");
_propertyRigFoldout = serializedObject.FindProperty("_rigFoldout");
_propertyRig = serializedObject.FindProperty("_rig");
_propertyHandPosesFoldout = serializedObject.FindProperty("_handPosesFoldout");
_propertyHandPoses = serializedObject.FindProperty(PropertyHandPoses);
// Expand rig when created, only once.
if (_propertyRigExpandedInitialized.boolValue == false)
{
_propertyRigExpandedInitialized.boolValue = true;
_propertyRig.isExpanded = true;
serializedObject.ApplyModifiedProperties();
}
}
/// <summary>
/// Draws the custom inspector and handles events.
/// </summary>
public override void OnInspectorGUI()
{
serializedObject.Update();
UxrAvatar avatar = (UxrAvatar)serializedObject.targetObject;
if (avatar == null)
{
return;
}
GameObject prefab = null;
GameObject parentPrefab = null;
bool isPrefabStageSelected = false;
if (avatar.gameObject.IsPrefabRoot())
{
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null && prefabStage.prefabContentsRoot == avatar.gameObject)
{
// Get prefab from prefab window which is open
prefab = AssetDatabase.LoadAssetAtPath<GameObject>(prefabStage.assetPath);
isPrefabStageSelected = true;
}
else
{
prefab = avatar.gameObject;
}
}
else
{
UxrEditorUtils.GetInParentPrefab(avatar.gameObject, out prefab);
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage == null || prefabStage.prefabContentsRoot != avatar.gameObject)
{
// It's not open in prefab window.
// Fix for avatar prefabs nested in another higher-level prefab
while (prefab != null && prefab.gameObject.transform.parent != null)
{
UxrEditorUtils.GetInParentPrefab(prefab.gameObject, out prefab);
}
}
}
if (prefab != null)
{
UxrEditorUtils.GetInParentPrefab(prefab.gameObject, out parentPrefab);
}
UxrAvatar avatarPrefab = prefab != null ? prefab.GetComponent<UxrAvatar>() : null;
string avatarPrefabGuid = prefab != null ? AssetDatabase.GUIDFromAssetPath(AssetDatabase.GetAssetPath(prefab)).ToString() : null;
UxrAvatar avatarParentPrefab = parentPrefab != null ? parentPrefab.GetComponent<UxrAvatar>() : null;
if (!Application.isPlaying)
{
// Check if we need to get and store the prefab information:
SerializedObject targetAvatarPrefabObject = avatarPrefab != null ? new SerializedObject(avatarPrefab) : null;
SerializedProperty propertyPrefabGuid = targetAvatarPrefabObject?.FindProperty(PropertyPrefabGuid);
SerializedProperty propertyParentPrefab = targetAvatarPrefabObject?.FindProperty(PropertyParentPrefab);
if (propertyPrefabGuid != null && !string.IsNullOrEmpty(avatarPrefabGuid) && propertyPrefabGuid.stringValue != avatarPrefabGuid)
{
// Prefab information not added yet: add.
propertyPrefabGuid.stringValue = avatarPrefabGuid;
targetAvatarPrefabObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
}
if (propertyParentPrefab != null && !ReferenceEquals(propertyParentPrefab.objectReferenceValue, parentPrefab))
{
// Parent prefab information not added yet: add.
propertyParentPrefab.objectReferenceValue = parentPrefab;
targetAvatarPrefabObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
}
// Force instances getting parent prefab from their source prefab
if (prefab != null && avatar.gameObject != prefab && propertyParentPrefab != null && _propertyParentPrefab.prefabOverride && !isPrefabStageSelected)
{
_propertyParentPrefab.prefabOverride = false;
}
if (targetAvatarPrefabObject == null && (_propertyPrefabGuid.stringValue != string.Empty || _propertyParentPrefab.objectReferenceValue != null))
{
// Prefab information unlinked. Probably used "unpack prefab" functionality in Unity. Set references to null.
_propertyPrefabGuid.stringValue = string.Empty;
_propertyParentPrefab.objectReferenceValue = null;
}
SerializedProperty propertyHandPoses = targetAvatarPrefabObject?.FindProperty(PropertyHandPoses);
if (propertyHandPoses != null)
{
// Check if we need to eliminate empty hand poses, references deleted without using the editor.
int deletedCount = 0;
for (int i = 0; i < propertyHandPoses.arraySize; ++i)
{
if (propertyHandPoses.GetArrayElementAtIndex(i).objectReferenceValue == null)
{
propertyHandPoses.DeleteArrayElementAtIndex(i);
deletedCount++;
i--;
}
}
if (deletedCount > 0)
{
targetAvatarPrefabObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
}
// Check if we need to eliminate duplicated hand poses generated through prefab variants.
if (avatarPrefab != null && avatarParentPrefab != null)
{
IEnumerable<UxrHandPoseAsset> netHandPoses = avatarPrefab.GetHandPoses().Where(handPose => avatarParentPrefab.GetHandPoses().All(handPose2 => handPose != handPose2));
if (netHandPoses.Count() != propertyHandPoses.arraySize)
{
UxrEditorUtils.AssignSerializedPropertyArray(propertyHandPoses, netHandPoses);
targetAvatarPrefabObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
}
}
}
}
if (!avatar.gameObject.IsPrefabRoot())
{
// Assistant
Camera camera = avatar.GetComponentInChildren<Camera>();
Scene currentScene = avatar.gameObject.scene;
if (!UxrEditorUtils.PathIsInUltimateXR(currentScene.path) && prefab != null && UxrEditorUtils.PathIsInUltimateXR(AssetDatabase.GetAssetPath(prefab)))
{
EditorGUILayout.HelpBox(NeedsPrefabVariant, MessageType.Warning);
if (GUILayout.Button(ContentFix, GUILayout.Width(FixButtonWidth)))
{
if (UxrEditorUtils.CreateAvatarPrefab(avatar, "Save prefab variant", avatar.gameObject.name + "Variant", out prefab, out GameObject newInstance))
{
if (newInstance == null)
{
EditorUtility.DisplayDialog(UxrConstants.Editor.Error, "The prefab variant was created but it could not be instantiated in the scene. Try doing it manually.", UxrConstants.Editor.Ok);
}
else
{
Selection.activeGameObject = newInstance.gameObject;
avatar = newInstance.GetComponent<UxrAvatar>();
avatar.name = prefab.name;
}
// If in prefab stage, save
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null && avatar.transform.parent != null)
{
// @TODO: Should save in innermost parent prefab, but currently the only way I found to force a save is using MarkSceneDirty
EditorSceneManager.MarkSceneDirty(prefabStage.scene);
}
return;
}
}
}
else if (camera == null)
{
camera = FindObjectOfType<Camera>();
if (camera == null || camera.SafeGetComponentInParent<UxrAvatar>() != null)
{
EditorGUILayout.HelpBox(NeedsCameraNewHelp, MessageType.Warning);
if (GUILayout.Button(ContentFix, GUILayout.Width(FixButtonWidth)))
{
GameObject cameraController = new GameObject("Camera Controller");
cameraController.transform.SetPositionAndRotation(avatar.transform.position, avatar.transform.rotation);
cameraController.transform.parent = avatar.transform;
cameraController.transform.SetAsFirstSibling();
Undo.RegisterCreatedObjectUndo(cameraController, "Create Camera Controller");
GameObject cameraObject = new GameObject("Camera");
cameraObject.transform.SetPositionAndRotation(cameraController.transform.position, cameraController.transform.rotation);
cameraObject.transform.parent = cameraController.transform;
cameraObject.tag = "MainCamera";
Undo.RegisterCreatedObjectUndo(cameraObject, "Create Camera");
Camera newCamera = cameraObject.AddComponent<Camera>();
newCamera.nearClipPlane = 0.01f;
cameraObject.AddComponent<AudioListener>();
}
}
else
{
EditorGUILayout.HelpBox(NeedsCameraReparentHelp, MessageType.Warning);
if (camera.transform.parent == null)
{
if (GUILayout.Button(ContentFix, GUILayout.Width(FixButtonWidth)))
{
GameObject cameraController = new GameObject("Camera Controller");
cameraController.transform.SetPositionAndRotation(avatar.transform.position, avatar.transform.rotation);
cameraController.transform.parent = avatar.transform;
cameraController.transform.SetAsFirstSibling();
Undo.RegisterCreatedObjectUndo(cameraController, "Create Camera Controller");
Undo.RecordObject(camera, "Set Camera Near");
camera.nearClipPlane = 0.01f;
Undo.RecordObject(camera.transform, "Move Camera");
camera.transform.SetPositionAndRotation(cameraController.transform.position, cameraController.transform.rotation);
Undo.SetTransformParent(camera.transform, cameraController.transform, "Re-parent Camera");
}
}
}
}
else
{
if (camera.transform.parent == avatar.transform)
{
EditorGUILayout.HelpBox(NeedsCameraParentHelp, MessageType.Warning);
if (GUILayout.Button(ContentFix, GUILayout.Width(FixButtonWidth)))
{
GameObject cameraController = new GameObject("Camera Controller");
cameraController.transform.SetPositionAndRotation(camera.transform.position, camera.transform.rotation);
cameraController.transform.parent = avatar.transform;
cameraController.transform.SetAsFirstSibling();
Undo.RegisterCreatedObjectUndo(cameraController, "Create Camera Controller");
Undo.SetTransformParent(camera.transform, cameraController.transform, "Re-parent Camera");
Undo.RecordObject(camera, "Set Camera Near");
camera.nearClipPlane = 0.01f;
}
}
else
{
UxrAvatarController avatarController = avatar.GetComponentInChildren<UxrAvatarController>();
if (avatarController == null)
{
EditorGUILayout.HelpBox(NeedsAvatarControllerHelp, MessageType.Warning);
if (GUILayout.Button(ContentFix, GUILayout.Width(FixButtonWidth)))
{
UxrStandardAvatarController standardAvatarController = avatar.gameObject.AddComponent<UxrStandardAvatarController>();
Undo.RegisterCreatedObjectUndo(standardAvatarController, "Create Avatar Controller");
}
}
else if (!avatar.AvatarRig.HasFullHandData())
{
EditorGUILayout.HelpBox(NeedsFingerSetup, MessageType.Warning);
if (GUILayout.Button(ContentFix, GUILayout.Width(FixButtonWidth)))
{
avatar.TryToInferMissingRigElements();
if (avatar.AvatarRig.HasAnyUpperBodyIKReference())
{
// Make avatar full-body if it has any upper body reference
_propertyRigType.enumValueIndex = (int)UxrAvatarRigType.HalfOrFullBody;
}
RefreshRigSerializedProperty(avatar);
if (!avatar.AvatarRig.HasFullHandData())
{
EditorUtility.DisplayDialog("Missing data", "Could not try to figure out all hand and finger bone references. Try setting them up manually under the Avatar rig section.", UxrConstants.Editor.Ok);
}
}
}
else
{
UxrTrackingDevice avatarTracking = avatar.GetComponentInChildren<UxrTrackingDevice>();
if (avatarTracking == null)
{
EditorGUILayout.HelpBox(NeedsIntegrationHelp, MessageType.Warning);
EditorGUILayout.BeginHorizontal();
string integrationPrefabGuid = null;
if (GUILayout.Button(ContentBigHandsIntegration, GUILayout.Width(FixButtonWidth)))
{
integrationPrefabGuid = BigHandsIntegrationGuid;
}
if (GUILayout.Button(ContentSmallHandsIntegration, GUILayout.Width(FixButtonWidth)))
{
integrationPrefabGuid = SmallHandsIntegrationGuid;
}
if (integrationPrefabGuid != null)
{
// Add hand integration and try to place on avatar hands
GameObject handsIntegrationAsset = AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(integrationPrefabGuid));
if (handsIntegrationAsset != null)
{
GameObject handsIntegration = PrefabUtility.InstantiatePrefab(handsIntegrationAsset, avatar.transform) as GameObject;
if (handsIntegration)
{
handsIntegration.name = handsIntegrationAsset.name;
Undo.RegisterCreatedObjectUndo(handsIntegration, "Add Hands Integration");
handsIntegration.GetComponentsInChildren<UxrHandIntegration>().ForEach(i => i.TryToMatchHand());
}
}
}
EditorGUILayout.EndHorizontal();
}
else if (avatar.GetComponent<IUxrNetworkAvatar>() != null)
{
EditorGUILayout.HelpBox(IsMultiplayerPrefab, MessageType.Warning);
}
else
{
EditorGUILayout.HelpBox("Avatar is ready to rock!", MessageType.Info);
}
}
}
}
}
EditorGUILayout.Space();
// Rest of inspector
_foldoutGeneral = UxrEditorUtils.FoldoutStylish("General parameters:", _foldoutGeneral);
if (_foldoutGeneral)
{
GUI.enabled = false;
EditorGUILayout.ObjectField(ContentPrefab, prefab, typeof(GameObject), false);
EditorGUILayout.PropertyField(_propertyParentPrefab, ContentParentPrefab);
GUI.enabled = true;
EditorGUILayout.PropertyField(_propertyAvatarMode, ContentAvatarMode);
}
// Renderers
_foldoutRendering = UxrEditorUtils.FoldoutStylish("Avatar rendering:", _foldoutRendering);
if (_foldoutRendering)
{
_propertyRenderMode.intValue = EditorGUILayout.MaskField(ContentRenderMode, _propertyRenderMode.intValue, UxrEditorUtils.GetAvatarRenderModeNames().SplitCamelCase().ToArray());
EditorGUILayout.PropertyField(_propertyShowControllerHands, ContentShowControllerHands);
EditorGUILayout.PropertyField(_propertyAvatarRenderers, ContentAvatarRenderers, true);
}
// Rig
_propertyRigFoldout.boolValue = UxrEditorUtils.FoldoutStylish("Avatar rig:", _propertyRigFoldout.boolValue);
if (_propertyRigFoldout.boolValue)
{
if (_propertyRigType.enumValueIndex == (int)UxrAvatarRigType.HandsOnly)
{
EditorGUILayout.PropertyField(_propertyRigType, ContentRigType);
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(ContentTryToFillGuessing, GUILayout.Width(ButtonWidth)))
{
avatar.TryToInferMissingRigElements();
RefreshRigSerializedProperty(avatar);
}
if (GUILayout.Button(ContentClearRig, GUILayout.Width(ButtonWidth)))
{
avatar.ClearRigElements();
RefreshRigSerializedProperty(avatar);
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(_propertyRig.FindPropertyRelative("_head").FindPropertyRelative("_head"), ContentHead);
EditorGUILayout.PropertyField(_propertyRig.FindPropertyRelative("_leftArm").FindPropertyRelative("_hand"), ContentLeftHand);
EditorGUILayout.PropertyField(_propertyRig.FindPropertyRelative("_rightArm").FindPropertyRelative("_hand"), ContentRightHand);
}
else if (_propertyRigType.enumValueIndex == (int)UxrAvatarRigType.HalfOrFullBody)
{
EditorGUILayout.PropertyField(_propertyRigType, ContentRigType);
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(ContentAutoFillFromAnimator, GUILayout.Width(ButtonWidth)))
{
if (!avatar.SetupRigElementsFromAnimator())
{
EditorUtility.DisplayDialog("Animator data is missing", "Could not find any Animator component with humanoid data. Please use a model with a humanoid avatar to use autofill.", UxrConstants.Editor.Ok);
}
else
{
RefreshRigSerializedProperty(avatar);
}
}
if (GUILayout.Button(ContentTryToFillGuessing, GUILayout.Width(ButtonWidth)))
{
avatar.TryToInferMissingRigElements();
RefreshRigSerializedProperty(avatar);
}
if (GUILayout.Button(ContentClearRig, GUILayout.Width(ButtonWidth)))
{
avatar.ClearRigElements();
RefreshRigSerializedProperty(avatar);
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(_propertyRig, ContentRig);
}
}
// Hand poses
bool createPrefab = false;
_propertyHandPosesFoldout.boolValue = UxrEditorUtils.FoldoutStylish("Hand poses:", _propertyHandPosesFoldout.boolValue);
if (_propertyHandPosesFoldout.boolValue)
{
if (string.IsNullOrEmpty(avatar.PrefabGuid))
{
GUILayout.Label("Avatar requires a prefab in order to use hand poses.");
if (UxrEditorUtils.CenteredButton(ContentCreatePrefab))
{
// Create prefab at the end.
createPrefab = true;
}
}
else if (!avatar.GetAllHandPoses().Any())
{
GUILayout.Label("No hand poses available. Use the Hand Pose Editor to add hand poses.");
}
else
{
foreach (UxrAvatar avatarChainPrefab in avatar.GetPrefabChain())
{
IEnumerable<UxrHandPoseAsset> handPoses = avatarChainPrefab.GetHandPoses();
if (handPoses.Any())
{
EditorGUILayout.BeginHorizontal();
if (avatarChainPrefab != avatarPrefab)
{
GUILayout.Label($"{handPoses.Count()} inherited from {avatarChainPrefab.name}:");
if (GUILayout.Button(ContentSelectPrefab))
{
Selection.activeObject = AssetDatabase.LoadAssetAtPath<UxrAvatar>(AssetDatabase.GetAssetPath(avatarChainPrefab));
}
}
else
{
GUILayout.Label($"{handPoses.Count()} in {avatarChainPrefab.name}:");
}
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
EditorGUI.indentLevel++;
foreach (UxrHandPoseAsset pose in handPoses)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField($"{pose.name}: ", $"Type: {pose.PoseType.ToString()}");
if (GUILayout.Button(ContentSelectPoseAsset))
{
Selection.activeObject = AssetDatabase.LoadAssetAtPath<UxrHandPoseAsset>(AssetDatabase.GetAssetPath(pose));
}
if (!avatar.IsInPrefab())
{
if (!avatar.IsHandPoseOverriden(pose) && GUILayout.Button(ContentOpenPose))
{
UxrHandPoseEditorWindow.Open(avatar, pose);
}
}
EditorGUILayout.EndHorizontal();
}
EditorGUI.indentLevel--;
}
}
// EditorGUILayout.PropertyField(serializedObject.FindProperty("_handPoses"));
}
if (!string.IsNullOrEmpty(avatar.PrefabGuid) && !avatar.IsInPrefab() && !UxrHandPoseEditorWindow.IsVisible && UxrEditorUtils.CenteredButton(ContentOpenHandPoseEditor, -1))
{
UxrHandPoseEditorWindow.Open(avatar);
}
}
serializedObject.ApplyModifiedProperties();
if (createPrefab)
{
if (UxrEditorUtils.CreateAvatarPrefab(avatar, "Save prefab", avatar.gameObject.name, out prefab, out GameObject newInstance))
{
if (newInstance == null)
{
EditorUtility.DisplayDialog(UxrConstants.Editor.Error, "The prefab was created but it could not be instantiated in the scene. Try doing it manually.", UxrConstants.Editor.Ok);
}
else
{
Selection.activeGameObject = newInstance.gameObject;
}
}
}
}
/// <summary>
/// Draws visual guides on the avatar.
/// </summary>
private void OnSceneGUI()
{
UxrAvatar avatar = (UxrAvatar)serializedObject.targetObject;
if (avatar == null)
{
return;
}
/*
// Draw finger tips and finger print positions
Color handlesColor = Handles.color;
Handles.matrix = Matrix4x4.identity;
foreach (UxrAvatarArmInfo arm in avatar.AvatarRigInfo.Arms)
{
foreach (UxrAvatarFingerInfo finger in arm.Fingers)
{
Handles.color = ColorExt.ColorAlpha(Color.blue, UxrEditorUtils.HandlesAlpha);
Handles.DrawSolidDisc(finger.TipPosition, finger.TipDirection, 0.004f);
Handles.color = ColorExt.ColorAlpha(Color.green, UxrEditorUtils.HandlesAlpha);
Handles.DrawSolidDisc(finger.FingerPrintPosition, finger.FingerPrintDirection, 0.004f);
}
}
Handles.color = handlesColor;
*/
}
#endregion
#region Private Methods
/// <summary>
/// Refreshes the rig information.
/// </summary>
/// <param name="avatar">Avatar whose rig to refresh</param>
private void RefreshRigSerializedProperty(UxrAvatar avatar)
{
// Head
serializedObject.FindProperty("_rig._head._leftEye").objectReferenceValue = avatar.AvatarRig.Head.LeftEye;
serializedObject.FindProperty("_rig._head._rightEye").objectReferenceValue = avatar.AvatarRig.Head.RightEye;
serializedObject.FindProperty("_rig._head._jaw").objectReferenceValue = avatar.AvatarRig.Head.Jaw;
serializedObject.FindProperty("_rig._head._head").objectReferenceValue = avatar.AvatarRig.Head.Head;
serializedObject.FindProperty("_rig._head._neck").objectReferenceValue = avatar.AvatarRig.Head.Neck;
// Body
serializedObject.FindProperty("_rig._upperChest").objectReferenceValue = avatar.AvatarRig.UpperChest;
serializedObject.FindProperty("_rig._chest").objectReferenceValue = avatar.AvatarRig.Chest;
serializedObject.FindProperty("_rig._spine").objectReferenceValue = avatar.AvatarRig.Spine;
serializedObject.FindProperty("_rig._hips").objectReferenceValue = avatar.AvatarRig.Hips;
// Left arm
serializedObject.FindProperty("_rig._leftArm._clavicle").objectReferenceValue = avatar.AvatarRig.LeftArm.Clavicle;
serializedObject.FindProperty("_rig._leftArm._upperArm").objectReferenceValue = avatar.AvatarRig.LeftArm.UpperArm;
serializedObject.FindProperty("_rig._leftArm._forearm").objectReferenceValue = avatar.AvatarRig.LeftArm.Forearm;
serializedObject.FindProperty("_rig._leftArm._hand._wrist").objectReferenceValue = avatar.LeftHandBone;
serializedObject.FindProperty("_rig._leftArm._hand._thumb._metacarpal").objectReferenceValue = avatar.LeftHand.Thumb.Metacarpal;
serializedObject.FindProperty("_rig._leftArm._hand._thumb._proximal").objectReferenceValue = avatar.LeftHand.Thumb.Proximal;
serializedObject.FindProperty("_rig._leftArm._hand._thumb._intermediate").objectReferenceValue = avatar.LeftHand.Thumb.Intermediate;
serializedObject.FindProperty("_rig._leftArm._hand._thumb._distal").objectReferenceValue = avatar.LeftHand.Thumb.Distal;
serializedObject.FindProperty("_rig._leftArm._hand._index._metacarpal").objectReferenceValue = avatar.LeftHand.Index.Metacarpal;
serializedObject.FindProperty("_rig._leftArm._hand._index._proximal").objectReferenceValue = avatar.LeftHand.Index.Proximal;
serializedObject.FindProperty("_rig._leftArm._hand._index._intermediate").objectReferenceValue = avatar.LeftHand.Index.Intermediate;
serializedObject.FindProperty("_rig._leftArm._hand._index._distal").objectReferenceValue = avatar.LeftHand.Index.Distal;
serializedObject.FindProperty("_rig._leftArm._hand._middle._metacarpal").objectReferenceValue = avatar.LeftHand.Middle.Metacarpal;
serializedObject.FindProperty("_rig._leftArm._hand._middle._proximal").objectReferenceValue = avatar.LeftHand.Middle.Proximal;
serializedObject.FindProperty("_rig._leftArm._hand._middle._intermediate").objectReferenceValue = avatar.LeftHand.Middle.Intermediate;
serializedObject.FindProperty("_rig._leftArm._hand._middle._distal").objectReferenceValue = avatar.LeftHand.Middle.Distal;
serializedObject.FindProperty("_rig._leftArm._hand._ring._metacarpal").objectReferenceValue = avatar.LeftHand.Ring.Metacarpal;
serializedObject.FindProperty("_rig._leftArm._hand._ring._proximal").objectReferenceValue = avatar.LeftHand.Ring.Proximal;
serializedObject.FindProperty("_rig._leftArm._hand._ring._intermediate").objectReferenceValue = avatar.LeftHand.Ring.Intermediate;
serializedObject.FindProperty("_rig._leftArm._hand._ring._distal").objectReferenceValue = avatar.LeftHand.Ring.Distal;
serializedObject.FindProperty("_rig._leftArm._hand._little._metacarpal").objectReferenceValue = avatar.LeftHand.Little.Metacarpal;
serializedObject.FindProperty("_rig._leftArm._hand._little._proximal").objectReferenceValue = avatar.LeftHand.Little.Proximal;
serializedObject.FindProperty("_rig._leftArm._hand._little._intermediate").objectReferenceValue = avatar.LeftHand.Little.Intermediate;
serializedObject.FindProperty("_rig._leftArm._hand._little._distal").objectReferenceValue = avatar.LeftHand.Little.Distal;
// Right arm
serializedObject.FindProperty("_rig._rightArm._clavicle").objectReferenceValue = avatar.AvatarRig.RightArm.Clavicle;
serializedObject.FindProperty("_rig._rightArm._upperArm").objectReferenceValue = avatar.AvatarRig.RightArm.UpperArm;
serializedObject.FindProperty("_rig._rightArm._forearm").objectReferenceValue = avatar.AvatarRig.RightArm.Forearm;
serializedObject.FindProperty("_rig._rightArm._hand._wrist").objectReferenceValue = avatar.RightHandBone;
serializedObject.FindProperty("_rig._rightArm._hand._thumb._metacarpal").objectReferenceValue = avatar.RightHand.Thumb.Metacarpal;
serializedObject.FindProperty("_rig._rightArm._hand._thumb._proximal").objectReferenceValue = avatar.RightHand.Thumb.Proximal;
serializedObject.FindProperty("_rig._rightArm._hand._thumb._intermediate").objectReferenceValue = avatar.RightHand.Thumb.Intermediate;
serializedObject.FindProperty("_rig._rightArm._hand._thumb._distal").objectReferenceValue = avatar.RightHand.Thumb.Distal;
serializedObject.FindProperty("_rig._rightArm._hand._index._metacarpal").objectReferenceValue = avatar.RightHand.Index.Metacarpal;
serializedObject.FindProperty("_rig._rightArm._hand._index._proximal").objectReferenceValue = avatar.RightHand.Index.Proximal;
serializedObject.FindProperty("_rig._rightArm._hand._index._intermediate").objectReferenceValue = avatar.RightHand.Index.Intermediate;
serializedObject.FindProperty("_rig._rightArm._hand._index._distal").objectReferenceValue = avatar.RightHand.Index.Distal;
serializedObject.FindProperty("_rig._rightArm._hand._middle._metacarpal").objectReferenceValue = avatar.RightHand.Middle.Metacarpal;
serializedObject.FindProperty("_rig._rightArm._hand._middle._proximal").objectReferenceValue = avatar.RightHand.Middle.Proximal;
serializedObject.FindProperty("_rig._rightArm._hand._middle._intermediate").objectReferenceValue = avatar.RightHand.Middle.Intermediate;
serializedObject.FindProperty("_rig._rightArm._hand._middle._distal").objectReferenceValue = avatar.RightHand.Middle.Distal;
serializedObject.FindProperty("_rig._rightArm._hand._ring._metacarpal").objectReferenceValue = avatar.RightHand.Ring.Metacarpal;
serializedObject.FindProperty("_rig._rightArm._hand._ring._proximal").objectReferenceValue = avatar.RightHand.Ring.Proximal;
serializedObject.FindProperty("_rig._rightArm._hand._ring._intermediate").objectReferenceValue = avatar.RightHand.Ring.Intermediate;
serializedObject.FindProperty("_rig._rightArm._hand._ring._distal").objectReferenceValue = avatar.RightHand.Ring.Distal;
serializedObject.FindProperty("_rig._rightArm._hand._little._metacarpal").objectReferenceValue = avatar.RightHand.Little.Metacarpal;
serializedObject.FindProperty("_rig._rightArm._hand._little._proximal").objectReferenceValue = avatar.RightHand.Little.Proximal;
serializedObject.FindProperty("_rig._rightArm._hand._little._intermediate").objectReferenceValue = avatar.RightHand.Little.Intermediate;
serializedObject.FindProperty("_rig._rightArm._hand._little._distal").objectReferenceValue = avatar.RightHand.Little.Distal;
// Left leg
serializedObject.FindProperty("_rig._leftLeg._upperLeg").objectReferenceValue = avatar.AvatarRig.LeftLeg.UpperLeg;
serializedObject.FindProperty("_rig._leftLeg._lowerLeg").objectReferenceValue = avatar.AvatarRig.LeftLeg.LowerLeg;
serializedObject.FindProperty("_rig._leftLeg._foot").objectReferenceValue = avatar.AvatarRig.LeftLeg.Foot;
serializedObject.FindProperty("_rig._leftLeg._toes").objectReferenceValue = avatar.AvatarRig.LeftLeg.Toes;
// Right leg
serializedObject.FindProperty("_rig._rightLeg._upperLeg").objectReferenceValue = avatar.AvatarRig.RightLeg.UpperLeg;
serializedObject.FindProperty("_rig._rightLeg._lowerLeg").objectReferenceValue = avatar.AvatarRig.RightLeg.LowerLeg;
serializedObject.FindProperty("_rig._rightLeg._foot").objectReferenceValue = avatar.AvatarRig.RightLeg.Foot;
serializedObject.FindProperty("_rig._rightLeg._toes").objectReferenceValue = avatar.AvatarRig.RightLeg.Toes;
// Clear torsion nodes if they exist
if (avatar.AvatarRig.LeftArm.Forearm == null && avatar.AvatarRig.RightArm.Forearm == null)
{
avatar.GetComponentsInChildren<UxrWristTorsionIKSolver>().ForEach(Undo.DestroyObjectImmediate);
}
// Update standard avatar controller info
UxrAvatarController avatarController = avatar.GetComponent<UxrAvatarController>();
if (avatarController is UxrStandardAvatarController standardAvatarController)
{
SerializedObject serializedAvatarController = new SerializedObject(standardAvatarController);
SerializedProperty propIKSettings = serializedAvatarController.FindProperty(UxrStandardAvatarControllerEditor.PropBodyIKSettings);
serializedAvatarController.Update();
// Try to set eye base height and forward offset
if (avatar.AvatarRig.Head.LeftEye && avatar.AvatarRig.Head.RightEye)
{
Vector3 eyeLeft = avatar.transform.InverseTransformPoint(avatar.AvatarRig.Head.LeftEye.position);
Vector3 eyeRight = avatar.transform.InverseTransformPoint(avatar.AvatarRig.Head.RightEye.position);
propIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyEyesBaseHeight).floatValue = (avatar.AvatarRig.Head.LeftEye.position.y + avatar.AvatarRig.Head.RightEye.position.y) * 0.5f - avatar.transform.position.y;
propIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyEyesForwardOffset).floatValue = (eyeLeft.z + eyeRight.z) * 0.5f + 0.02f;
}
else if (avatar.AvatarRig.Head.Head != null)
{
propIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyEyesBaseHeight).floatValue = (avatar.AvatarRig.Head.Head.position.y - avatar.transform.position.y) + 0.1f;
propIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyEyesForwardOffset).floatValue = 0.15f;
}
// If a neck wasn't found, try to set neck base height and forward setting using the head node
if (avatar.AvatarRig.Head.Neck == null && avatar.AvatarRig.Head.Head != null)
{
propIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyNeckBaseHeight).floatValue = (avatar.AvatarRig.Head.Head.position.y - avatar.transform.position.y) - 0.1f;
propIKSettings.FindPropertyRelative(UxrIKBodySettingsDrawer.PropertyNeckForwardOffset).floatValue = 0.0f;
}
serializedAvatarController.ApplyModifiedProperties();
}
}
#endregion
#region Private Types & Data
private GUIContent ContentFix { get; } = new GUIContent("Fix", "Fixes the issue above automatically");
private GUIContent ContentBigHandsIntegration { get; } = new GUIContent("Use Big hands", "Adds the BigHandsIntegration prefab to the avatar, which includes functionality to use tracking/input devices and also interact with the environment using manipulation, locomotion etc.");
private GUIContent ContentSmallHandsIntegration { get; } = new GUIContent("Use Small hands", "Adds the SmallHandsIntegration prefab to the avatar, which includes functionality to use tracking/input devices and also interact with the environment using manipulation, locomotion etc.");
private GUIContent ContentCreatePrefab { get; } = new GUIContent("Create Prefab", "Creates a prefab for this avatar");
private GUIContent ContentAutoFillFromAnimator { get; } = new GUIContent("Autofill from Animator", "");
private GUIContent ContentTryToFillGuessing { get; } = new GUIContent("Try to fill", "");
private GUIContent ContentClearRig { get; } = new GUIContent("Clear", "");
private GUIContent ContentSelectPrefab { get; } = new GUIContent("Select prefab", "");
private GUIContent ContentSelectPoseAsset { get; } = new GUIContent("Select", "");
private GUIContent ContentOpenPose { get; } = new GUIContent("Open", "");
private GUIContent ContentOpenHandPoseEditor { get; } = new GUIContent("Open Hand Pose Editor...", "");
private GUIContent ContentHead { get; } = new GUIContent("Head (optional)", "");
private GUIContent ContentLeftHand { get; } = new GUIContent("Left Hand", "");
private GUIContent ContentRightHand { get; } = new GUIContent("Right Hand", "");
private GUIContent ContentPrefab { get; } = new GUIContent("Prefab", "");
private GUIContent ContentParentPrefab { get; } = new GUIContent("Parent Prefab", "");
private GUIContent ContentAvatarMode { get; } = new GUIContent("Avatar Mode", "Local Avatars are updated automatically using the headset and controllers, while UpdateExternally avatars are not updated and act as puppets that should be updated manually. They are useful in multiplayer applications for the remote avatars.");
private GUIContent ContentRenderMode { get; } = new GUIContent("Render Mode", "Controls the way the avatar will be rendered. Avatar mode is the default but for tutorials, menus and other cases rendering the controllers may be more convenient");
private GUIContent ContentShowControllerHands { get; } = new GUIContent("Show Controller Hands", "If the render mode is set to render the controllers, will the hands that come with them also be rendered? Set it to false to render the controllers only. Set it to true if you want some fancy hands with IK on top of them");
private GUIContent ContentAvatarRenderers { get; } = new GUIContent("Avatar Renderers", "The list of renderers that make up the avatar when rendered in-game. This is used to switch between rendering the avatar or the controllers or both");
private GUIContent ContentRigType { get; } = new GUIContent("Rig Type", "");
private GUIContent ContentRig { get; } = new GUIContent("Rig", "");
private const int ButtonWidth = 140;
private const int FixButtonWidth = 120;
private const string NeedsPrefabVariant = "It is recommended to create a prefab variant in your project instead of using an UltimateXR prefab directly. When UltimateXR is updated, all the prefabs could be overwritten and changes would be lost. Using a prefab variant in your project allows to keep all changes and still get the improvements included in the updates.";
private const string NeedsCameraNewHelp = "The avatar has no Camera in its hierarchy. It needs a Camera to render the view in VR";
private const string NeedsCameraReparentHelp = "The scene camera needs to be placed in the avatar hierarchy to render the view correctly in VR";
private const string NeedsCameraParentHelp = "In order to be able to reposition the camera at runtime please parent the camera to a child of the avatar root GameObject instead of being a child directly. We will call this the Camera Controller.";
private const string NeedsAvatarControllerHelp = "The avatar needs an UxrAvatarController component that will take care of updating all its components. You can add an UxrStandardAvatarController component or provide your own for advanced custom avatar handling.";
private const string NeedsFingerSetup = "The avatar rig has no hand or finger bone references assigned yet. They are required to use hand poses and set up hand integrations.";
private const string NeedsIntegrationHelp = "The avatar has no support for tracking/input devices yet. You can use one of the below integrations to leverage this work for you. The hand size will only determine the type of hands that will be shown when the input controllers are visualized instead of the avatar hands.";
private const string IsMultiplayerPrefab = "This avatar is a prefab intended for multiplayer. Multiplayer prefabs are spawned at runtime, either by the user or with the help of UxrNetworkManager, and should not be pre-instantiated in the scene. Please consider removing this avatar from the scene.";
private const string BigHandsIntegrationGuid = "2f7a5d0166ab0d041bed38f7cc6affef";
private const string SmallHandsIntegrationGuid = "dde1cc2a360069149a781772e8410006";
private SerializedProperty _propertyPrefabGuid;
private SerializedProperty _propertyParentPrefab;
private SerializedProperty _propertyAvatarMode;
private SerializedProperty _propertyRenderMode;
private SerializedProperty _propertyShowControllerHands;
private SerializedProperty _propertyAvatarRenderers;
private SerializedProperty _propertyRigType;
private SerializedProperty _propertyRigExpandedInitialized;
private SerializedProperty _propertyRigFoldout;
private SerializedProperty _propertyRig;
private SerializedProperty _propertyHandPosesFoldout;
private SerializedProperty _propertyHandPoses;
private bool _foldoutGeneral = true;
private bool _foldoutRendering = true;
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ab9e5d4f31d7c054b87190a33a3cabb6
timeCreated: 1501659089
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,108 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrAvatarEditorExt.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using UltimateXR.Avatar;
using UnityEditor;
using UnityEngine;
namespace UltimateXR.Editor.Avatar
{
/// <summary>
/// <see cref="UxrAvatar" /> extensions available only for editor scripts.
/// </summary>
public static class UxrAvatarEditorExt
{
#region Public Methods
/// <summary>
/// Gets an <see cref="UxrAvatar" />'s prefab, based on the Guid stored.
/// </summary>
/// <param name="self">Avatar to get the source prefab of</param>
/// <returns>Prefab or null if it could not be found</returns>
public static GameObject GetPrefab(this UxrAvatar self)
{
return AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(self.PrefabGuid));
}
/// <summary>
/// Gets an <see cref="UxrAvatar" /> prefab's <see cref="UxrAvatar" /> component, based on the Guid stored.
/// </summary>
/// <param name="self">Avatar to get the source prefab of</param>
/// <returns>Prefab or null if it could not be found</returns>
public static UxrAvatar GetAvatarPrefab(this UxrAvatar self)
{
return GetFromGuid(self.PrefabGuid);
}
/// <summary>
/// Gets a prefab's GUID.
/// </summary>
/// <param name="gameObject">Prefab to get the GUID of</param>
/// <returns>GUID or empty string if it could not be found</returns>
public static string GetGuid(GameObject gameObject)
{
return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(gameObject));
}
/// <summary>
/// Gets an <see cref="UxrAvatar" /> prefab, based on an asset GUID.
/// </summary>
/// <param name="avatarPrefabGuid">Asset GUID</param>
/// <returns>Prefab or null if it could not be found</returns>
public static UxrAvatar GetFromGuid(string avatarPrefabGuid)
{
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(avatarPrefabGuid));
return prefab != null ? prefab.GetComponent<UxrAvatar>() : null;
}
/// <summary>
/// Gets the avatar prefab chain. This is the source prefab followed by all parent prefabs up to the root parent
/// prefab.
/// </summary>
/// <returns>
/// Upwards prefab chain. If the avatar is a prefab itself, it will be the first item in the list.
/// </returns>
public static IEnumerable<UxrAvatar> GetPrefabChain(this UxrAvatar self)
{
UxrAvatar avatarPrefab = self.GetAvatarPrefab();
if (avatarPrefab != null)
{
yield return avatarPrefab;
}
UxrAvatar current = self.ParentAvatarPrefab;
while (current != null)
{
yield return current;
current = current.ParentAvatarPrefab;
}
}
/// <summary>
/// Checks whether the avatar is or comes from the given prefab.
/// </summary>
/// <param name="self">Avatar</param>
/// <param name="prefab">Prefab</param>
/// <returns>Whether the avatar is or comes from the given prefab</returns>
public static bool IsInPrefabChain(this UxrAvatar self, GameObject prefab)
{
foreach (UxrAvatar avatarPrefab in self.GetPrefabChain())
{
if (avatarPrefab != null && avatarPrefab.gameObject == prefab)
{
return true;
}
}
return false;
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1e99978505dd0ec4faf3fb7e0fb22a76
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,23 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHandIntegrationEditor.RenderPipeline.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace UltimateXR.Editor.Avatar
{
public partial class UxrHandIntegrationEditor
{
#region Private Types & Data
/// <summary>
/// Enumerates the supported render pipeline material variations.
/// </summary>
private enum RenderPipeline
{
Brp = 0,
Urp
}
#endregion
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ffadeb7d00884d79bc722da4e20739aa
timeCreated: 1653306477

View File

@@ -0,0 +1,530 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrHandIntegrationEditor.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UltimateXR.Avatar;
using UltimateXR.Core;
using UltimateXR.Devices.Visualization;
using UltimateXR.Extensions.System.Collections;
using UltimateXR.Extensions.System.IO;
using UltimateXR.Extensions.Unity;
using UltimateXR.Manipulation;
using UnityEditor;
using UnityEngine;
namespace UltimateXR.Editor.Avatar
{
/// <summary>
/// Custom editor for <see cref="UxrHandIntegration" />.
/// </summary>
[CustomEditor(typeof(UxrHandIntegration))]
public partial class UxrHandIntegrationEditor : UnityEditor.Editor
{
#region Unity
/// <summary>
/// Caches the serialized properties, the different variations and creates the temporal hand gizmo.
/// </summary>
private void OnEnable()
{
_propertyGizmoHandSize = serializedObject.FindProperty("_gizmoHandSize");
_propertyHandSide = serializedObject.FindProperty("_handSide");
_propertyObjectVariationName = serializedObject.FindProperty("_objectVariationName");
_propertyMaterialVariationName = serializedObject.FindProperty("_materialVariationName");
_propertySelectedRenderPipeline = serializedObject.FindProperty("_selectedRenderPipeline");
_handIntegration = serializedObject.targetObject as UxrHandIntegration;
_objectVariationNames = GetCommonObjectVariationNames();
_materialVariationNames = GetCommonMaterialVariationNames(_propertyObjectVariationName.name);
GetControllerPipelineRenderers(out _renderers, out _renderPipelineVariations, out _renderPipelineVariationStrings, out _selectedRenderPipelineIndex);
serializedObject.Update();
_propertySelectedRenderPipeline.intValue = _selectedRenderPipelineIndex;
serializedObject.ApplyModifiedProperties();
UxrGrabber[] grabbers = _handIntegration.GetComponentsInChildren<UxrGrabber>();
foreach (UxrGrabber grabber in grabbers)
{
if (grabber.HandRenderer == null)
{
// Do nothing, we just try to force to get the hand renderer reference if it doesn't exist or is inactive
}
}
CreateTemporalObjects();
}
/// <summary>
/// Destroys the temporal hand gizmo.
/// </summary>
private void OnDisable()
{
DestroyTemporalObjects();
}
/// <inheritdoc />
public override void OnInspectorGUI()
{
serializedObject.Update();
bool variationChanged = false;
bool renderPipelineChanged = false;
// Gizmo hand size (read-only so that it can only be changed in debug mode).
GUI.enabled = false;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(_propertyGizmoHandSize, ContentGizmoHandSize);
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
RegenerateTemporalObjects();
}
GUI.enabled = true;
// Hand side
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(_propertyHandSide, ContentHandSide);
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
RegenerateTemporalObjects();
}
// Select object variation
if (_objectVariationNames.Count > 0)
{
EditorGUI.BeginChangeCheck();
int handIndex = EditorGUILayout.Popup(ContentObjectVariationName, _objectVariationNames.IndexOf(_propertyObjectVariationName.stringValue), UxrEditorUtils.ToGUIContentArray(_objectVariationNames));
if (EditorGUI.EndChangeCheck())
{
variationChanged = true;
_propertyObjectVariationName.stringValue = _objectVariationNames[handIndex];
serializedObject.ApplyModifiedProperties();
}
_materialVariationNames = GetCommonMaterialVariationNames(_propertyObjectVariationName.stringValue);
}
// Select material variation
if (_materialVariationNames.Count > 0)
{
EditorGUI.BeginChangeCheck();
int materialIndex = EditorGUILayout.Popup(ContentMaterialVariationName, _materialVariationNames.IndexOf(_propertyMaterialVariationName.stringValue), UxrEditorUtils.ToGUIContentArray(_materialVariationNames));
if (EditorGUI.EndChangeCheck())
{
variationChanged = true;
_propertyMaterialVariationName.stringValue = _materialVariationNames[materialIndex];
}
}
// Select Render Pipeline variation
if (_renderPipelineVariations.Count > 1)
{
EditorGUI.BeginChangeCheck();
_propertySelectedRenderPipeline.intValue = EditorGUILayout.Popup(ContentRenderPipeline, _propertySelectedRenderPipeline.intValue, UxrEditorUtils.ToGUIContentArray(_renderPipelineVariationStrings));
if (EditorGUI.EndChangeCheck())
{
renderPipelineChanged = true;
_selectedRenderPipelineIndex = _propertySelectedRenderPipeline.intValue;
}
}
serializedObject.ApplyModifiedProperties();
// Enable new variation
if (variationChanged)
{
EnableCurrentVariation(_propertyObjectVariationName.stringValue, _propertyMaterialVariationName.stringValue);
}
if (renderPipelineChanged)
{
EnableCurrentRenderPipeline(_renderers, _renderPipelineVariations[_selectedRenderPipelineIndex]);
}
// Alignment to avatar hand
EditorGUILayout.Space();
if (UxrEditorUtils.CenteredButton(new GUIContent("Align to avatar")))
{
Undo.RegisterCompleteObjectUndo(_handIntegration.transform, "Align hand integration");
if (!_handIntegration.TryToMatchHand())
{
EditorUtility.DisplayDialog("Missing required bone references", $"The hand integration could not find an {nameof(UxrAvatar)} component up in the hierarchy or the {nameof(UxrAvatar)} is missing finger bone references in the rig section. The finger bones are required to try to align the hand integration with the avatar's hand.", UxrConstants.Editor.Ok);
}
}
// Check Undo/Redo/Revert:
if (_propertyGizmoHandSize.enumValueIndex != (int)_gizmoHandSize)
{
RegenerateTemporalObjects();
}
if (_propertySelectedRenderPipeline.intValue != _selectedRenderPipelineIndex)
{
_selectedRenderPipelineIndex = _propertySelectedRenderPipeline.intValue;
EnableCurrentRenderPipeline(_renderers, _renderPipelineVariations[_selectedRenderPipelineIndex]);
}
}
#endregion
#region Event Trigger Methods
/// <summary>
/// Called when there is an undo/redo.
/// </summary>
private void OnUndoRedo()
{
RegenerateTemporalObjects();
}
#endregion
#region Private Methods
/// <summary>
/// Gets all the common object variation names among the available <see cref="UxrControllerHand" /> components hanging
/// from the object.
/// </summary>
/// <returns>Common available object variation names</returns>
private IReadOnlyList<string> GetCommonObjectVariationNames()
{
List<string> objectVariationNames = new List<string>();
if (_handIntegration)
{
_controllerHands = _handIntegration.GetComponentsInChildren<UxrControllerHand>(true);
bool isFirst = true;
foreach (UxrControllerHand hand in _controllerHands)
{
objectVariationNames = isFirst ? hand.Variations.Select(v => v.Name).ToList() : objectVariationNames.Intersect(hand.Variations.Select(v => v.Name)).ToList();
isFirst = false;
}
}
return objectVariationNames;
}
/// <summary>
/// Gets all the common material variation names among the available <see cref="UxrControllerHand" /> components
/// hanging from the object, for a given object variation.
/// </summary>
/// <returns>Common available material variation names for the given object variation</returns>
private IReadOnlyList<string> GetCommonMaterialVariationNames(string objectVariationName)
{
List<string> materialVariationNames = new List<string>();
if (_handIntegration)
{
_controllerHands = _handIntegration.GetComponentsInChildren<UxrControllerHand>(true);
bool isFirst = true;
foreach (UxrControllerHand hand in _controllerHands)
{
foreach (UxrControllerHand.ObjectVariation objectVariation in hand.Variations)
{
if (objectVariation.Name == objectVariationName)
{
materialVariationNames = isFirst ? objectVariation.MaterialVariations.Select(v => v.Name).ToList() : materialVariationNames.Intersect(objectVariation.MaterialVariations.Select(v => v.Name)).ToList();
isFirst = false;
}
}
}
}
return materialVariationNames;
}
/// <summary>
/// Retrieves the available renderers that are part of controllers, the list of available material render pipeline
/// variations and the currently selected render pipeline.
/// </summary>
/// <param name="renderers">Returns the renderers that are part of controllers, if any</param>
/// <param name="renderPipelineVariations">Returns the available material render pipeline variations, if any</param>
/// <param name="renderPipelineVariationStrings">
/// Returns the UI strings that <paramref name="renderPipelineVariations" />
/// should be mapped with
/// </param>
/// <param name="selectedRenderPipelineIndex">
/// Returns the index in <paramref name="renderPipelineVariations" /> of the
/// render pipeline that was found to be currently enabled
/// </param>
private void GetControllerPipelineRenderers(out List<Renderer> renderers, out List<RenderPipeline> renderPipelineVariations, out List<string> renderPipelineVariationStrings, out int selectedRenderPipelineIndex)
{
renderers = new List<Renderer>();
renderPipelineVariations = new List<RenderPipeline>();
renderPipelineVariationStrings = new List<string>();
selectedRenderPipelineIndex = -1;
if (_handIntegration)
{
foreach (Renderer renderer in _handIntegration.GetComponentsInChildren<Renderer>(true))
{
foreach (Material material in renderer.sharedMaterials.Where(material => material != null))
{
if (material.name.Contains(MaterialUrp))
{
renderers.Add(renderer);
if (!renderPipelineVariations.Contains(RenderPipeline.Urp))
{
renderPipelineVariations.Add(RenderPipeline.Urp);
renderPipelineVariationStrings.Add(UrpUI);
}
selectedRenderPipelineIndex = renderPipelineVariations.IndexOf(RenderPipeline.Urp);
if (!renderPipelineVariations.Contains(RenderPipeline.Brp) && GetRenderPipelineVariant(material, RenderPipeline.Brp))
{
renderPipelineVariations.Add(RenderPipeline.Brp);
renderPipelineVariationStrings.Add(BrpUI);
}
}
else if (material.name.Contains(MaterialBrp))
{
renderers.Add(renderer);
if (!renderPipelineVariations.Contains(RenderPipeline.Brp))
{
renderPipelineVariations.Add(RenderPipeline.Brp);
renderPipelineVariationStrings.Add(BrpUI);
}
selectedRenderPipelineIndex = renderPipelineVariations.IndexOf(RenderPipeline.Brp);
if (!renderPipelineVariations.Contains(RenderPipeline.Urp) && GetRenderPipelineVariant(material, RenderPipeline.Urp))
{
renderPipelineVariations.Add(RenderPipeline.Urp);
renderPipelineVariationStrings.Add(UrpUI);
}
}
}
}
}
}
/// <summary>
/// Gets the given material variation if it exists.
/// </summary>
/// <param name="material">Material to get the variation of</param>
/// <param name="renderPipeline">Render pipeline to get the variation for</param>
/// <returns>The material variation for the given render pipeline if it exists</returns>
private Material GetRenderPipelineVariant(Material material, RenderPipeline renderPipeline)
{
string materialName = material.name;
string directory = Path.GetDirectoryName(AssetDatabase.GetAssetPath(material));
if (directory == null)
{
return null;
}
if (renderPipeline == RenderPipeline.Brp)
{
if (materialName.Contains(MaterialUrp))
{
return AssetDatabase.LoadAssetAtPath<Material>(PathExt.Combine(directory, materialName.Replace(MaterialUrp, MaterialBrp)) + ".mat");
}
}
else if (renderPipeline == RenderPipeline.Urp)
{
if (materialName.Contains(MaterialBrp))
{
return AssetDatabase.LoadAssetAtPath<Material>(PathExt.Combine(directory, materialName.Replace(MaterialBrp, MaterialUrp)) + ".mat");
}
}
return null;
}
/// <summary>
/// Enables the current object/material variation.
/// </summary>
/// <param name="objectVariationName">Object variation name</param>
/// <param name="materialVariationName">Material variation name</param>
private void EnableCurrentVariation(string objectVariationName, string materialVariationName)
{
if (_handIntegration)
{
foreach (UxrControllerHand hand in _handIntegration.GetComponentsInChildren<UxrControllerHand>(true))
{
// First pass: Disable all, because the selected variation may share a GameObject with another variation
foreach (UxrControllerHand.ObjectVariation objectVariation in hand.Variations)
{
objectVariation.GameObject.SetActive(false);
}
// Second pass: Enable selected one and assign material
UxrControllerHand.ObjectVariation selectedObjectVariation = hand.Variations.FirstOrDefault(v => v.Name == objectVariationName);
if (selectedObjectVariation != null)
{
selectedObjectVariation.GameObject.SetActive(true);
UxrControllerHand.ObjectVariation.MaterialVariation selectedMaterialVariation = selectedObjectVariation.MaterialVariations.FirstOrDefault(v => v.Name == materialVariationName);
if (selectedMaterialVariation != null)
{
foreach (Renderer renderer in selectedObjectVariation.GameObject.GetComponentsInChildren<Renderer>(true))
{
renderer.sharedMaterial = selectedMaterialVariation.Material;
}
}
}
}
}
}
/// <summary>
/// Enables the materials for the given render pipeline.
/// </summary>
/// <param name="renderers">List of renderers whose materials to process</param>
/// <param name="renderPipeline">Render pipeline to enable</param>
private void EnableCurrentRenderPipeline(IReadOnlyList<Renderer> renderers, RenderPipeline renderPipeline)
{
foreach (Renderer renderer in renderers)
{
Material[] sharedMaterials = renderer.sharedMaterials;
for (int i = 0; i < sharedMaterials.Length; ++i)
{
Material materialVariation = GetRenderPipelineVariant(sharedMaterials[i], renderPipeline);
if (materialVariation != null)
{
sharedMaterials[i] = materialVariation;
}
}
renderer.sharedMaterials = sharedMaterials;
}
}
/// <summary>
/// Regenerates the hand gizmo.
/// </summary>
private void RegenerateTemporalObjects()
{
DestroyTemporalObjects();
CreateTemporalObjects();
}
/// <summary>
/// Creates the hand gizmo.
/// </summary>
private void CreateTemporalObjects()
{
string handAssetGuid = null;
if (_propertyGizmoHandSize.enumValueIndex == (int)UxrHandIntegration.GizmoHandSize.Big)
{
handAssetGuid = _handIntegration.HandSide == UxrHandSide.Left ? LeftBigHandAssetGuid : RightBigHandAssetGuid;
_gizmoHandSize = UxrHandIntegration.GizmoHandSize.Big;
}
else if (_propertyGizmoHandSize.enumValueIndex == (int)UxrHandIntegration.GizmoHandSize.Small)
{
handAssetGuid = _handIntegration.HandSide == UxrHandSide.Left ? LeftSmallHandAssetGuid : RightSmallHandAssetGuid;
_gizmoHandSize = UxrHandIntegration.GizmoHandSize.Small;
}
if (!string.IsNullOrEmpty(handAssetGuid))
{
GameObject handAsset = AssetDatabase.LoadAssetAtPath<GameObject>(AssetDatabase.GUIDToAssetPath(handAssetGuid));
if (handAsset == null)
{
return;
}
_handGizmoRoot = Instantiate(handAsset);
_handGizmoRoot.hideFlags = HideFlags.HideAndDontSave;
_handGizmoRenderer = _handGizmoRoot.GetComponentInChildren<Renderer>();
if (_handGizmoRoot != null)
{
_handGizmoRoot.transform.SetParent(_handIntegration.transform);
_handGizmoRoot.transform.SetPositionAndRotation(_handIntegration.transform);
}
else
{
Debug.LogWarning("Hand gizmo could not be loaded");
}
}
}
/// <summary>
/// Destroys the hand gizmo.
/// </summary>
private void DestroyTemporalObjects()
{
if (_handGizmoRoot != null)
{
DestroyImmediate(_handGizmoRoot);
}
_handGizmoRoot = null;
_handGizmoRenderer = null;
}
#endregion
#region Private Types & Data
private GUIContent ContentGizmoHandSize => new GUIContent("Gizmo Hand Size", "The hand size ");
private GUIContent ContentHandSide => new GUIContent("Hand Side");
private GUIContent ContentObjectVariationName => new GUIContent("Hand", "The type of hand that is shown with the controller");
private GUIContent ContentMaterialVariationName => new GUIContent("Material", "The hand material");
private GUIContent ContentRenderPipeline => new GUIContent("Render Pipeline", "The render pipeline that will be used, so that the correct materials are loaded");
private const string LeftBigHandAssetGuid = "93019d606e943b7429d29c694143ad6e";
private const string RightBigHandAssetGuid = "d45d3edc285cfd64a86fddd771e13f47";
private const string LeftSmallHandAssetGuid = "672e7f52fe868134a80bf396141fe261";
private const string RightSmallHandAssetGuid = "0a1c1014903295a408b755f1fed2863e";
private const string MaterialBrp = "_BRP";
private const string MaterialUrp = "_URP";
private const string BrpUI = "Built-in Render Pipeline";
private const string UrpUI = "Universal Render Pipeline";
private SerializedProperty _propertyGizmoHandSize;
private SerializedProperty _propertyHandSide;
private SerializedProperty _propertyObjectVariationName;
private SerializedProperty _propertyMaterialVariationName;
private SerializedProperty _propertySelectedRenderPipeline;
private UxrHandIntegration _handIntegration;
private UxrHandIntegration.GizmoHandSize _gizmoHandSize;
private GameObject _handGizmoRoot;
private Renderer _handGizmoRenderer;
private IReadOnlyList<UxrControllerHand> _controllerHands;
private IReadOnlyList<string> _objectVariationNames;
private IReadOnlyList<string> _materialVariationNames;
private List<RenderPipeline> _renderPipelineVariations;
private List<string> _renderPipelineVariationStrings;
private List<Renderer> _renderers;
private int _selectedRenderPipelineIndex;
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 39a38dfa3b85bb9429b657870ef60ce6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: