Add ultimate xr
This commit is contained in:
8
Assets/Oculus/VR.meta
Normal file
8
Assets/Oculus/VR.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c388bdb8dcd2b684382fbbf4dc62e95d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/VR/Editor.meta
Normal file
8
Assets/Oculus/VR/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d0685b72279fee45991da69ca8c4ae4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Oculus/VR/Editor/Tools.meta
Normal file
8
Assets/Oculus/VR/Editor/Tools.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 82c0fd52bd0b3434ea34d88b4ee4c0df
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Assets/Oculus/VR/Editor/Tools/ovr-platform-util.exe
Normal file
BIN
Assets/Oculus/VR/Editor/Tools/ovr-platform-util.exe
Normal file
Binary file not shown.
7
Assets/Oculus/VR/Editor/Tools/ovr-platform-util.exe.meta
Normal file
7
Assets/Oculus/VR/Editor/Tools/ovr-platform-util.exe.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f4dd5a3030be6e489716719133eb2d4
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
18
Assets/Resources/MetaXRAcousticSettings.asset
Normal file
18
Assets/Resources/MetaXRAcousticSettings.asset
Normal file
@@ -0,0 +1,18 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
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: 2b76bcf034ab49e4a8cd30239a716460, type: 3}
|
||||
m_Name: MetaXRAcousticSettings
|
||||
m_EditorClassIdentifier:
|
||||
acousticModel: -1
|
||||
diffractionEnabled: 1
|
||||
excludeTags: []
|
||||
mapBakeWriteGeo: 1
|
||||
8
Assets/Resources/MetaXRAcousticSettings.asset.meta
Normal file
8
Assets/Resources/MetaXRAcousticSettings.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3579d5f0ab93c84790043c6a63ea6d6
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/Resources/MetaXRAudioSettings.asset
Normal file
15
Assets/Resources/MetaXRAudioSettings.asset
Normal file
@@ -0,0 +1,15 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
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: f3fe6e38ac2d4c22b04340d6eda2a47e, type: 3}
|
||||
m_Name: MetaXRAudioSettings
|
||||
m_EditorClassIdentifier:
|
||||
voiceLimit: 64
|
||||
8
Assets/Resources/MetaXRAudioSettings.asset.meta
Normal file
8
Assets/Resources/MetaXRAudioSettings.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ee2ac7946102ff4b80c9a643c0bfdae
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -12,11 +12,77 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: cd7bb81df5b74b34dadbf531f381a26b, type: 3}
|
||||
m_Name: OVRPlatformToolSettings
|
||||
m_EditorClassIdentifier:
|
||||
riftRedistPackages: []
|
||||
riftRedistPackages:
|
||||
- include: 0
|
||||
name: ' .NET Framework 3.5'
|
||||
id: ' 606493776156948 '
|
||||
- include: 0
|
||||
name: ' .NET Framework 4.0'
|
||||
id: ' 133610290311340 '
|
||||
- include: 0
|
||||
name: ' .NET Framework 4.5.1'
|
||||
id: ' 1617306711884127 '
|
||||
- include: 0
|
||||
name: ' .NET Framework 4.7.1'
|
||||
id: ' 1667821599930345 '
|
||||
- include: 0
|
||||
name: ' DirectX (June 2010)'
|
||||
id: ' 822786567843179 '
|
||||
- include: 0
|
||||
name: ' OpenAL 1.1'
|
||||
id: ' 1147517301974655 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2005'
|
||||
id: ' 1604897159783747 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2008'
|
||||
id: ' 118440348500045 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2010'
|
||||
id: ' 532320330249657 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2010 x86'
|
||||
id: ' 1008652072555515 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2012'
|
||||
id: ' 1683508698536289 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2012 x86'
|
||||
id: ' 1002692246447245 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2013'
|
||||
id: ' 1675031999409058 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2013 x86'
|
||||
id: ' 910524935693407 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2015 Update 3'
|
||||
id: ' 1183534128364060 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2015 x86 Update 3'
|
||||
id: ' 1113033105419344 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2017'
|
||||
id: ' 1315322525257173 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2017 x86'
|
||||
id: ' 1064693870299984 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2019'
|
||||
id: ' 2657209094360789 '
|
||||
- include: 0
|
||||
name: ' Visual C++ 2019 x86'
|
||||
id: ' 2556834837738356 '
|
||||
- include: 0
|
||||
name: ' Vulkan Runtime 1.0.65.1'
|
||||
id: ' 1824471960899274 '
|
||||
- include: 0
|
||||
name: ' Vulkan Runtime 1.1.73.0'
|
||||
id: ' 1941020095932382 '
|
||||
languagePackDirectory:
|
||||
assetConfigs:
|
||||
- configList: []
|
||||
- configList: []
|
||||
- configList: []
|
||||
targetPlatform: 3
|
||||
targetPlatform: 2
|
||||
runOvrLint: 1
|
||||
|
||||
8
Assets/UltimateXR.meta
Normal file
8
Assets/UltimateXR.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5458015ef545b34e96f7b9037a3218a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
60
Assets/UltimateXR/.gitignore
vendored
Normal file
60
Assets/UltimateXR/.gitignore
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
# This .gitignore file should be placed at the root of your Unity project directory
|
||||
#
|
||||
# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
|
||||
#
|
||||
/[Ll]ibrary/
|
||||
/[Tt]emp/
|
||||
/[Oo]bj/
|
||||
/[Bb]uild/
|
||||
/[Bb]uilds/
|
||||
/[Ll]ogs/
|
||||
/[Mm]emoryCaptures/
|
||||
|
||||
# Asset meta data should only be ignored when the corresponding asset is also ignored
|
||||
!/[Aa]ssets/**/*.meta
|
||||
|
||||
# Uncomment this line if you wish to ignore the asset store tools plugin
|
||||
# /[Aa]ssets/AssetStoreTools*
|
||||
|
||||
# Autogenerated Jetbrains Rider plugin
|
||||
[Aa]ssets/Plugins/Editor/JetBrains*
|
||||
|
||||
# Visual Studio cache directory
|
||||
.vs/
|
||||
|
||||
# Gradle cache directory
|
||||
.gradle/
|
||||
|
||||
# Autogenerated VS/MD/Consulo solution and project files
|
||||
ExportedObj/
|
||||
.consulo/
|
||||
*.csproj
|
||||
*.unityproj
|
||||
*.sln
|
||||
*.suo
|
||||
*.tmp
|
||||
*.user
|
||||
*.userprefs
|
||||
*.pidb
|
||||
*.booproj
|
||||
*.svd
|
||||
*.pdb
|
||||
*.mdb
|
||||
*.opendb
|
||||
*.VC.db
|
||||
|
||||
# Unity3D generated meta files
|
||||
*.pidb.meta
|
||||
*.pdb.meta
|
||||
*.mdb.meta
|
||||
|
||||
# Unity3D generated file on crash reports
|
||||
sysinfo.txt
|
||||
|
||||
# Builds
|
||||
*.apk
|
||||
*.unitypackage
|
||||
|
||||
# Crashlytics generated file
|
||||
crashlytics-build.properties
|
||||
|
||||
519
Assets/UltimateXR/CHANGELOG.md
Normal file
519
Assets/UltimateXR/CHANGELOG.md
Normal file
@@ -0,0 +1,519 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to UltimateXR will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
TODO: Write update guide:
|
||||
-UxrApplyConstrainEventArgs new properties.
|
||||
-Rename CheckAndApplyLockHands() to KeepGripsInPlace()
|
||||
-Removed UxrGrabbableObject.PlaceOnAnchor
|
||||
-SDK constants moved from UxrManager to UxrConstants.
|
||||
-Component synchronization in UxrManager now uses IUxrStateSync instead of
|
||||
UxrComponent.
|
||||
-UxrComponent.TryGetComponentById now is UxrUniqueIdImplementer.TryGetComponentById().
|
||||
-UxrManager.ExecuteStateChange is now called ExecuteStateSyncEvent.
|
||||
-Avatar prefab that is set up using UxrNetworkManager inspector, now is changed
|
||||
to "Update Externally" mode so that it is instantiated using external mode by default.
|
||||
Then it will switch to local if the avatar spawned is the local avatar.
|
||||
|
||||
### Added
|
||||
|
||||
- Add native multiplayer support and connectors for various network SDKs
|
||||
(Photon Fusion, Unity NetCode, Mirror) and voice communication SDKs
|
||||
(Photon Voice, Dissonance). More connectors will be added soon.
|
||||
- Add UxrNetworkManager and UxrInstanceManager to provice sync capabilities.
|
||||
- Update SDK Manager window with new tabs for SDK types, including new multiplayer.
|
||||
- Add new GlobalSettings accessible using the Tools->UltimateXR Unity menu.
|
||||
- Add new unique ID functionality to UXR components. All components that inherit
|
||||
from UxrComponent will have a unique ID that can be used with
|
||||
UxrUniqueIdImplementer.TryGetComponentById().
|
||||
- Add new Unique ID generation tool to generate unique IDs for projects build with
|
||||
earlier versions of UltimateXR.
|
||||
- Add IUxrUniqueId, IUxrStateSync and IUxrStateSave interfaces to UxrComponent to
|
||||
facilitate multiplayer synchronization, serialization, state saves and replay
|
||||
functionality in all UltimateXR components.
|
||||
- Add UxrUniqueIdImplementer, UxrStateSaveImplementer and UxrStateSyncImplementer
|
||||
to leverage the interface implementation in custom user classes that cannot
|
||||
inherit from UxrComponent due to multiple inheritance limitation.
|
||||
- Add functionality to UxrManager to save and load the scene state using
|
||||
SaveStateChanges() and LoadStateChanges().
|
||||
- Add functionality to UxrManager to have a single point of entry to all component
|
||||
state changes that require synchronization:
|
||||
ComponentStateChanged event and ExecuteStateChange() method.
|
||||
- Add serialization/deserialization methods to all UxrComponent derived classes.
|
||||
- Add serialization/deserialization methods to all UxrSyncEventArgs.
|
||||
- Create UxrVarType to enumerate all supported var types that can be synchronized.
|
||||
- Add ToString() to all UxrSyncEventArgs to help data logging.
|
||||
- Add new property Options to UxrSyncEventArgs to tell whether the event should
|
||||
be synchronized in different environments such as networks or replays.
|
||||
- Add new BinaryWriter and BinaryReader extensions with functionality to
|
||||
serialize/deserialize Unity and UltimateXR data, as well as well-known
|
||||
C# types.
|
||||
- Add new UxrBinarySerializer with binary serialization and deserialization support.
|
||||
- Add new UxrSyncObject component to identify objects that don't have any
|
||||
UxrComponent added, so that they have a unique ID. Also to sync the Transform
|
||||
of a GameObject if it's required and no other component does it already.
|
||||
- Add new interpolators to Math namespace to interpolate different types of
|
||||
variables using optional smooth and step options.
|
||||
- Add support to solve manipulations on objects using an unlimited amount of
|
||||
grabs to support multi-user shared interaction.
|
||||
- Add support to grab grabbable parent objects through grabbable children.
|
||||
- Add support for dummy grabbable parents. Dummy grabbable parents are grabbable
|
||||
objects that can be manipulating only through the children, but still have
|
||||
position/rotation constraints.
|
||||
- Add new functionality ForceSnapPosition and ForceSnapRotation to
|
||||
UxrPlacementOptions to force snap even if the grabbable object isn't set up
|
||||
that way.
|
||||
- Add new functionality in UxrGrabManager to move grabbable objects considering
|
||||
constraints: SetLocalPositionUsingConstraints(), SetLocalRotationUsingConstraints(),
|
||||
SetLocalPositionAndRotationUsingConstraints(), SetPositionUsingConstraints(),
|
||||
SetRotationUsingConstraints() and SetPositionAndRotationUsingConstraints().
|
||||
- Add new UxrAutoSlideInObject/Anchor components to provide built-in functionality
|
||||
like how the battery in the example scene can be inserted/removed smoothly
|
||||
from the generators.
|
||||
- Add new UxrGrabbableResizable component to provide functionality to create
|
||||
objects that can be scaled by grabbing them from both sides.
|
||||
- Add new ComponentProcessorWindow editor base class to generate component
|
||||
processors that can modify from single components to the whole project.
|
||||
- Add UxrEditorUtils.ProcessAllProjectComponents() functionality to process both
|
||||
innermost and non-innermost prefab elements.
|
||||
- Add UxrEditorUtils.ModifyComponent() to perform changes to components in the
|
||||
scene or project separately processing instances, prefab variants and original
|
||||
prefabs.
|
||||
- Add automatic detection of UXR installation path.
|
||||
- Add new menus in Tools->UltimateXR.
|
||||
- Add PushTransform() and PopTransform() methods in UxrComponent to facilitate
|
||||
saving and restoring transformation info.
|
||||
- Add new parameters to UxrColorTween.AnimateBlinkAlpha to support min alpha and
|
||||
max alpha.
|
||||
- Add new PBR shader with a tinted mask. Use in cyborg avatar to color it.
|
||||
- Add new cabinet prefab to Lab in example scene to showcase grabbable parent dummies.
|
||||
- Expose properties in UxrTeleportSpawnCollider to have public access.
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve manipulation workflow to a system that is more scalable, robust and
|
||||
solves the whole interaction process in different stages.
|
||||
- Separate UxrGrabManager in different files based on functionality.
|
||||
- Remove all properties from UxrApplyConstrainEventArgs leaving only GrabbableObject.
|
||||
Constraints are applied on an object level so it doesn't make sense to use grabbers,
|
||||
especially in multi-user environments.
|
||||
- Remove RequireComponent attribute from UxrGrabbableObjectComponent that forces
|
||||
a UxrGrabbableObject component on the same GameObject. GrabbableObject can be
|
||||
required or not depending on overridable property IsGrabbableObjectRequired.
|
||||
- Rename IsOwnershipChanged in UxrManipulationEventArgs to IsGrabbedStateChanged.
|
||||
- UxrGrabPointShape now gets additional grabberDistanceTransform to also use
|
||||
non-default grabber proximity transforms.
|
||||
- Change how grabbable parenting works: Set to avatar's parent when grabbing and
|
||||
to anchor's parent when removing from anchor without grabbing.
|
||||
- Move SDK constants from UxrManager to UxrConstants.
|
||||
- Move input/tracking SDK locators from UltimateXR/Editor/Sdks to
|
||||
UltimateXR/Editor/Sdks/InputTracking.
|
||||
- Add teleportation validators to UxrTeleportLocomotionBase to create custom logic
|
||||
for destination validation and cancel a teleportation.
|
||||
- Move AvatarMoving and AvatarMoved events to UxrAvatar as GlobalAvatarMoving and
|
||||
GlobalAvatarMoved static events.
|
||||
- Change Teleported event in UxrTeleportSpawnCollider to use new
|
||||
UxrTeleportSpawnUsedEventArgs parameter.
|
||||
- Change UxrComponent unique ID functionality so that IDs are generated in the
|
||||
editor instead of using unique paths in scene with ComponentExt.GetUniqueScenePath().
|
||||
- Improve avatar arm rig reference solving for hierarchies with siblings in
|
||||
the clavicle, upper arm or forearm.
|
||||
- Change GetUniqueScenePath in ComponentExt and TransformExt to make it cleaner.
|
||||
- Move AlignWindow, LookAtWindow and MirrorWindow tools to new namespace/folder in
|
||||
Editor/Utilities/TransformUtils.
|
||||
- Improve UxrEditorUtils.Prefabs functionality.
|
||||
- Improve TaskControllers documentation and functionality.
|
||||
- Improve UxrLookAt component with new axis functionality.
|
||||
- Make UxrControllerTracking's properties UpdateAvatarLeftHand/UpdateAvatarRightHand
|
||||
public instead of protected.
|
||||
- Allow UxrTeleportLocomotionBase to be disabled to ignore the component.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix UxrCameraPointer's ClickInput to Everything by default instead of None to avoid
|
||||
clicking each frame.
|
||||
- Fix bug in UxrPointerInputModule that prevents pointer up notifications being
|
||||
generated when the finger tip/pointer is dragged out of the UI.
|
||||
- Fix child dependent grabbable objects not being dynamic when releasing.
|
||||
- Fix bug in avatar IK where the coordinate system of clavicles/upperarm/forearm
|
||||
is inferred erroneously. Arms can look twisted.
|
||||
- Fix bug in standard avatar controller inspector when clicking Use Avatar Eyes.
|
||||
- Fix bug in UxrManager to avoid pre-caching multiple times when client network
|
||||
avatars are instantiated.
|
||||
- Fix bug in UxrManager where aync versions of teleport cause an await() to wait
|
||||
indefinitely when overlapping more than one teleport at the same time.
|
||||
- Fix bug in UxrTeleportSpawnCollider that throws null reference exceptions when
|
||||
Transform references are not set. When references are null, the Transform of the
|
||||
GameObject where the UxrTeleportSpawnCollider is added should be used instead.
|
||||
- Fix UxrEditorUtils.ProcessAllProjectComponents() not processing all components
|
||||
correctly.
|
||||
- Fix UxrEditorUtils.GetInnermostNon3DModelPrefabRoot() not working on all
|
||||
prefab/instance hierarchies correctly.
|
||||
- Fix UxrEditorUtils.GetInnermostNon3DModelPrefabRoot() to handle 3D model prefabs
|
||||
correctly.
|
||||
- Fix UxrUnityXRControllerInput when controllers have touchpads.
|
||||
- Fix warnings in example scene when loading ShotgunPump01.mp3 and ShotgunPump02.mp3
|
||||
- Fix missing EditorGUI.EndProperty() in UxrAxisPropertyDrawer.
|
||||
- Move UxrLaserPointerTargetTypes to correct namespace UltimateXR.UI instead of
|
||||
root UltimateXR namespace.
|
||||
- Fix UxrGrabPointShapeAxisAngle to compute center of grab correctly using snap point
|
||||
instead of using axis center.
|
||||
- Implement missing minAngle and maxAngle functionality in UxrGrabPointShapeAxisAngle.
|
||||
- Fix HandPositionAroundPivot manipulation mode drifting when grabbable object is
|
||||
child of another grabbable object.
|
||||
- Fix preview grab poses to work on hierarchies with non-uniform scaling.
|
||||
- Fix Lock Body Pivot parameter drifting in UxrStandardAvatarController.
|
||||
|
||||
## [0.9.7] - 2024-01-10
|
||||
|
||||
### Added
|
||||
|
||||
- Add support for Meta Quest 3.
|
||||
- Add support for Magic Leap 2.
|
||||
- Add support for Virtual Desktop controller naming.
|
||||
- Add support for Unity UI input on the screen and UltimateXR UI input in VR at
|
||||
the same time.
|
||||
- Add new functionality DontRelease to UxrPlacementOptions that keeps the object
|
||||
grabbed when UxrManager.Instance.PlaceObject() is called.
|
||||
- Add MinSingleRotationDegrees/MaxSingleRotationDegrees to UxrGrabbableObject when
|
||||
constrained to a single degree of freedom.
|
||||
- Add new symbol ULTIMATEXR_UNITY_XR_OCULUS when Unity.XR.Oculus is available.
|
||||
- Add joystick deadzone filtering in SteamVR.
|
||||
- Add support for position/rotation smoothing in all controller tracking components.
|
||||
- Add new UxrLinearPath spline type for linear interpolation in paths.
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve teleportation raycasts to discard avatar colliders and grabbed objects.
|
||||
- Improve teleportation to handle avatars with roll/pitch.
|
||||
- Improve Body IK to handle avatars with roll/pitch. Improved precision by
|
||||
performing computations in local avatar space.
|
||||
- Rename UxrPlacementType to UxrPlacementOptions.
|
||||
- Improve support for HandPositionAroundPivot manipulation mode.
|
||||
- Disable UxrInputModule component parameter "Disable Other Input Modules" by default
|
||||
instead of being enabled.
|
||||
- Remove deprecated references to CommonUsages.thumbrest and CommonUsages.thumbTouch
|
||||
in UxrUnityXRControllerInput.cs and use OculusUsages.thumbrest and
|
||||
OculusUsages.thumbTouch instead if available. Add support for OculusUsages.indexTouch.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix UxrLaserPointer hit quad position using controller forward.
|
||||
- Fix Pico controllers not working after using home button.
|
||||
- Fix Valve Index controllers' forward vectors.
|
||||
- Fix laser pointers not working correctly when mixing UI with 2D/3D objects.
|
||||
- Fix bug in UI module where finger tips and laser pointers cannot interact with
|
||||
multiple canvases when close to each other.
|
||||
- Fix null reference exception in manipulation system when placing constrained objects
|
||||
on anchors and grabbing them again.
|
||||
- Fix bug in UxrGrabManager that prevents GrabToggle manipulation mode to place
|
||||
objects on anchors.
|
||||
- Fix UxrGrabbableObject manipulation not working correctly when grab points are moved
|
||||
around during grabbing, for example when applying constraints.
|
||||
- Fix bug in UxrGrabbableObject.SetGrabPointEnabled not working correctly.
|
||||
- Fix UxrGrabPointShapes not computing center of grab correctly in some cases.
|
||||
- Fix scaling on root avatar GameObject not working correctly with Body/Arm IK.
|
||||
- Fix the following global input events in UxrControllerInput not being called:
|
||||
GlobalButtonStateChanged, GlobalInput1DChanged, GlobalInput2DChanged.
|
||||
- Fix UxrUnityXRControllerInput components not getting haptic capabilities correctly.
|
||||
- Fix warnings in example scene when loading ShotgunPump01.mp3 and ShotgunPump02.mp3
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove deprecated references to CommonUsages.thumbrest and CommonUsages.thumbTouch
|
||||
in UxrUnityXRControllerInput.cs and use OculusUsages.thumbrest and
|
||||
OculusUsages.thumbTouch instead if available.
|
||||
|
||||
## [0.9.6] - 2023-01-18
|
||||
|
||||
### Added
|
||||
|
||||
- Add SteamVR support for Rift/Rift-S/Quest/Quest2 headsets and controllers.
|
||||
- Add selective 2D/3D/UI GameObject interaction to UxrLaserPointer.
|
||||
- Add PrecachingStarting and PrecachingFinished events to UxrManager.
|
||||
- Add new exposed parameters to UxrLaserPointer for scripting.
|
||||
- Add new exposed parameters to UxrPointerEventData for scripting.
|
||||
- Add LocalStandardAvatarController property to UxrAvatar for quick access.
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve UxrLaserPointer inspector.
|
||||
- Improve UxrPointerInputModule event handling.
|
||||
- Make UxrControllerInput::GetIgnoreControllerInput() and SetIgnoreControllerInput()
|
||||
static so that they can be called at any point whether the controllers are active or not.
|
||||
- Change some common operations to favor execution time:
|
||||
[#12](https://github.com/VRMADA/ultimatexr-unity/pull/12).
|
||||
- Make grab preview poses no longer shown by default during play mode in the editor.
|
||||
Preview GameObjects are initially deactivated.
|
||||
- Improve hand pose editor load/save dialog boxes by caching the last load and save
|
||||
folders separately.
|
||||
- Change .meta files in Examples\FullScene\Settings\URP so that the IDs don't collide
|
||||
with the default URP project IDs.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix Transform.SetLocalPositionAndRotation when not available through new Unity API.
|
||||
- Fix UxrLaserPointer to not send UI events when laser is disabled.
|
||||
- Fix uninitialized hand pose when hand tracking is supported but not available.
|
||||
- Fix grabbable object position constraint not working correctly when grabbed using
|
||||
both hands.
|
||||
- Fix UxrGrabbableInspector not storing correctly new grab point parameters right
|
||||
after it has been created.
|
||||
- Fix Grab Toggle mode in UxrGrabbableObject not keeping the pose during the grab.
|
||||
- Fix "Enable When Hand Near" parameter in UxrGrabbableObject being enabled incorrectly
|
||||
sometimes when another grabbed object was in closer range.
|
||||
- Fix hand grab pose incorrectly changing when moving within the range of a grabbable
|
||||
object enabled by a non-default grab button.
|
||||
- Fix bug in hand pose editor that prevents to load external pose files when using
|
||||
UltimateXR in package installation mode.
|
||||
- Fix bug in hand pose editor where the "Add all poses from folder" loads all hand
|
||||
pose presets instead.
|
||||
- Fix UxrGrabManager's GrabObject, PlaceObject, ReleaseObject direct methods calls not
|
||||
updating the avatar's grab pose.
|
||||
- Fix global events in UxrControllerInput that should be static but are not:
|
||||
GlobalButtonStateChanged, GlobalInput1DChanged, GlobalInput2DChanged,
|
||||
GlobalHapticRequesting.
|
||||
- Fix UxrAvatar Reset to make it override.
|
||||
- Fix UxrAvatar.LaserPointers to return correct laser pointers instead of finger tips.
|
||||
- Fix avatar parent prefab not being stored correctly when inside a nested prefab.
|
||||
- Fix UxrGrenadeWeapon pin so that the timer cannot be reset by quickly releasing
|
||||
and grabbing the pin again.
|
||||
- Fix UxrSteamControllerInput so that OnDeviceConnected is called only once.
|
||||
|
||||
## [0.9.5] - 2022-11-12
|
||||
|
||||
### Added
|
||||
|
||||
- Improve automatic avatar rig bone reference solving.
|
||||
- Improve automatic generation of body IK setup in avatar automatic setup.
|
||||
- Add UxrWristTorsionIKSolver component when torsion bones are found in avatar.
|
||||
- Improve UxrStandardAvatarController inspector when IK is selected but rig has no nodes.
|
||||
- Add TrackedHandPose to UxrControllerInputCapabilities enum and applied to Valve Index.
|
||||
- Add public method SolveBodyIK() to still use body IK when AvatarMode is UpdateExternally.
|
||||
- Add support to isolate the hand part of the mesh in the hand preview poses if the hands
|
||||
are in the same mesh as the body.
|
||||
|
||||
### Changed
|
||||
|
||||
- Set avatar rig type to full/half body when body bones are found in the avatar rig.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix UxrWristTorsionInfo, UxrWristTorsionIKSolver and UxrAvatarArmInfo to generate
|
||||
correct data on all avatar rig coordinate systems.
|
||||
- Fix components that don't override Reset() or OnValidate().
|
||||
- Fix body IK when no neck bone is present.
|
||||
- Fix Valve Index controllers not sending UI input events when adopting a hand pose
|
||||
with the middle finger curled.
|
||||
- Fix bug in avatar finger bone reference solving if the finger has already data.
|
||||
|
||||
## [0.9.4] - 2022-10-29
|
||||
|
||||
### Added
|
||||
|
||||
- Add IUxrGrabbableModifier interface to create components that control certain parts
|
||||
of an UxrGrabbableObject. The UxrGrabbableObject inspector automatically disables the
|
||||
controlled UI sections and has also capability to show/hide the controlled parameters.
|
||||
The goal is to provide a scalable way to extend grabbable functionality by adding
|
||||
modifier components to the object.
|
||||
- Add Reset() and OnValidate() to the overridable Unity methods in UxrComponent.
|
||||
- Add ConstraintsFinished to UxrGrabbableObject to create logic after custom constraints
|
||||
have been applied.
|
||||
- Add constants to UxrGrabbableObjectEditor for UxrGrabbableObject field names.
|
||||
- Add "Any" variations to GetButtonsPress/GetButtonsTouch when multiple buttons are
|
||||
specified so that any button in the set is enough to meet the criteria instead of all.
|
||||
- Add EnumExt for Enum extensions.
|
||||
- Add static events to UxrControllerInput to receive events whenever any controller
|
||||
sends input data.
|
||||
|
||||
### Changed
|
||||
|
||||
- Change UxrApplyConstraintsEventArgs to contain the UxrGrabber instead of UxrGrabbableObject.
|
||||
The UxrGrabbableObject can still be accessed using the GrabbedObject property from
|
||||
the grabber.
|
||||
- Use ConstraintsFinished in UxrManipulationHapticFeedback in order to process object
|
||||
after custom constraints have been applied.
|
||||
- Rename UxrLocomotionTeleportBaseEditor to UxrTeleportLocomotionBaseEditor.
|
||||
- Update example scene prefabs so that they show the cyborg grab poses by default.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix support for PicoXR controller detection on newer versions of the PicoXR Unity SDK.
|
||||
- Remove Universal Additional Camera Data scripts added incorrectly to BRP avatar variants.
|
||||
Affected avatars are SmallHandsAvatar_BRP, BigHandsAvatar_BRP and CyborgAvatar_BRP.
|
||||
- Fix joystick directional buttons (left/right/up/down) when getting ignored input.
|
||||
- Fix bug in UxrGrabbableObjectEditor that under some circumstances throws exceptions
|
||||
when previewing grab poses.
|
||||
- Fix UxrGrabbableObject constrained rotation on a single axis not working correctly when
|
||||
parent has different axes.
|
||||
- Fix UxrTeleportSpawnCollider not raising Teleported event.
|
||||
|
||||
## [0.9.3] - 2022-10-24
|
||||
|
||||
### Added
|
||||
|
||||
- Add support to use UltimateXR through Unity Package Manager using git URL.
|
||||
|
||||
### Changed
|
||||
|
||||
- Change folder structure to adapt to the Unity Package Manager layout:
|
||||
https://docs.unity3d.com/Manual/cus-layout.html
|
||||
|
||||
## [0.9.2] - 2022-10-18
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix UxrGrabbableObject editor methods that caused compiler errors when creating a build.
|
||||
- Fix UxrGrabbableObject startup so that component can be added to an object at runtime.
|
||||
|
||||
## [0.9.1] - 2022-10-13
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve some UxrGrabbableObject parameter tooltips.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix GameObjectExt.GetBounds and GetLocalBounds exceptions when no renderers are found.
|
||||
- Fix GameObjectExt.GetBounds not computing value correctly.
|
||||
|
||||
## [0.9.0] - 2022-10-13
|
||||
|
||||
### Added
|
||||
|
||||
- Add new UxrGrabbableObject constraints functionality with improved manipulation.
|
||||
- Add UxrGrabbableObject gizmos to visualize rotation/translation constraints.
|
||||
- Add new UxrGrabbableObject rotation/translation constraint modes.
|
||||
- Add support to UxrGrabbableObject for rotation constraints on all 3 axes.
|
||||
- Add support to UxrGrabbableObject for a single rotation constraint over 360 degrees.
|
||||
- Improve manipulation behavior when grabbing objects to detect the grip and know which part
|
||||
of the hand creates more leverage.
|
||||
- Add possibility to parent to destination in locomotion components: UxrTeleportLocomotion and
|
||||
UxrSmoothLocomotion.
|
||||
- Add new teleport methods to UxrManager to teleport relative to moving objects.
|
||||
- Add new functionality to GameObjectExt to compute bounds recursively.
|
||||
- Add new functionality to MeshExt to compute skinned mesh vertices and bone influences.
|
||||
- Add new misc functionality to FloatExt, IntExt, Vector3Ext, Vector3IntExt and TransformExt.
|
||||
- Add new data to UxrAvatarRigInfo.
|
||||
- Add versioning to avatar rig info serialization and automatic updating.
|
||||
- Add IUxrLogger interface to unify logging in managers.
|
||||
- Add logging to UxrWeaponManager.
|
||||
- Add new properties to UxrComponent with initial Transform data.
|
||||
- Add new UxrAxis properties and functionality.
|
||||
- Add possibility to access avatar grabbers at edit-time.
|
||||
|
||||
### Changed
|
||||
|
||||
- Improve all UxrGrabbableObject and hand grab/release/constrain transitions.
|
||||
- Move UxrGrabbableObject constraints to the top of the inspector.
|
||||
- Replace GrabAndMove/RotateAroundAxis manipulation modes by new constraint system.
|
||||
- Change UxrGrabbableObject rotation and translation constraints reference.
|
||||
Rotations are performed around the grabbable object local axes.
|
||||
Translations are performed along the initial grabbable object local axes.
|
||||
- Improve UxrAvatarRig reference solving.
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove parent reference to UxrGrabbableObject rotation/translation constraints.
|
||||
- Remove UxrManipulationMode. New constraint system and UxrRotationProvider is used instead.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix manipulation not working correctly on moving platforms.
|
||||
- Fix incorrect manipulation release on objects with non-default grab button(s).
|
||||
- Fix UxrGrabbableObject release multipliers not working correctly with values less than 1.
|
||||
- Fix UxrGrabbableObject Constrain events not being called in some cases.
|
||||
- Fix UxrAvatarEditor throwing exception when using Fix button to save prefab variant.
|
||||
- Fix UxrCameraWallFade throwing exception when there are no avatars.
|
||||
- Fix constrained rotations not being able to go over 180 degrees.
|
||||
- Fix pre-caching triggered by non-local avatars. Only local avatar triggers pre-caching now.
|
||||
- Fix locomotion components detecting avatar or grabbed objects as obstacles.
|
||||
- Fix locomotion not working correctly on moving platforms.
|
||||
- Fix UxrWeaponManager not tracking actors correctly.
|
||||
- Fix UxrMagnifyingGlassUrp error when not using URP.
|
||||
- Fix CyborgAvatar_URP base to use index controllers correctly.
|
||||
- Fix some CyborgAvatar_BRP base materials that are using the URP variants.
|
||||
|
||||
## [0.8.4] - 2022-08-05
|
||||
|
||||
### Added
|
||||
|
||||
- Add new ULTIMATEXR_UNITY_TMPRO symbol when TextMeshPro is available.
|
||||
- Add support to UxrTextContentTween for TextMeshPro text components.
|
||||
|
||||
### Changed
|
||||
|
||||
- UxrTextContentTween.Animate() now uses a GameObject as target parameter so that
|
||||
either a Unity UI Text component or a TextMeshPro text component can be animated.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix UxrInterpolator.InterpolateText() use of rich text color tag.
|
||||
- Fix UxrAvatar to avoid infinite loops when enumerating the avatar prefab chain.
|
||||
- Fix UxrAvatarRigInfo.GetWorldElbowAxis() for left side when T-pose is found.
|
||||
- Fix UxrAvatarRig.ClearRigElements() to clear missing references.
|
||||
- Fix missing ULTIMATEXR_UNITY_URP in UxrMagnifyingGlassUrp to avoid URP hard requirement.
|
||||
|
||||
## [0.8.3] - 2022-08-01
|
||||
|
||||
### Added
|
||||
|
||||
- Add editor tooltips to UxrTeleportLocomotionBase and UxrTeleportLocomotion.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix UxrLaserPointerRaycaster bug that prevented using laser pointers as UI input.
|
||||
- Fix LaserDot.shader so that it works in stereo VR.
|
||||
|
||||
## [0.8.2] - 2022-07-21
|
||||
|
||||
### Added
|
||||
|
||||
- Add support for rotational constraints on more than one axis.
|
||||
- Add access to the grabbable object on UxrApplyConstraintsEventArgs.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Remove built-in compatibility in hand shader to fix shader errors when building.
|
||||
Compatibility will be added again as soon as Unity issue is fixed.
|
||||
Issue status can be followed here: https://github.com/VRMADA/ultimatexr-unity/issues/2
|
||||
- Fix grabbable objects being manipulated on movable platforms.
|
||||
- Fix UxrManipulationHapticFeedback component sending feedback incorrectly on movable platforms.
|
||||
|
||||
## [0.8.1] - 2022-07-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Use ULTIMATEXR_USE_PICOXR_SDK instead of UXR_USE_PICOXR_SDK for consistency.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Add new ControllerNames device names to UxrHtcViveInput to correctly detect HTC Vive controllers.
|
||||
- Add new ControllerNames device names to UxrValveIndexInput to correctly detect Knuckles controllers.
|
||||
- Add new ULTIMATEXR_UNITY_URP symbol to avoid compiler errors when Unity's URP package is not installed.
|
||||
|
||||
## [0.8.0] - 2022-07-06
|
||||
|
||||
### Added
|
||||
|
||||
- First public release!
|
||||
|
||||
[Unreleased]: https://github.com/VRMADA/ultimatexr-unity/compare/v0.9.7...HEAD
|
||||
[0.9.7]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.7
|
||||
[0.9.6]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.6
|
||||
[0.9.5]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.5
|
||||
[0.9.4]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.4
|
||||
[0.9.3]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.3
|
||||
[0.9.2]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.2
|
||||
[0.9.1]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.1
|
||||
[0.9.0]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.9.0
|
||||
[0.8.4]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.8.4
|
||||
[0.8.3]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.8.3
|
||||
[0.8.2]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.8.2
|
||||
[0.8.1]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.8.1
|
||||
[0.8.0]: https://github.com/VRMADA/ultimatexr-unity/releases/tag/v0.8.0
|
||||
7
Assets/UltimateXR/CHANGELOG.md.meta
Normal file
7
Assets/UltimateXR/CHANGELOG.md.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f389c08f5baefa04c9c1763f8a8514f4
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor.meta
Normal file
8
Assets/UltimateXR/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e57bd9c082580bf4f8a951b1ec95dc1e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Animation.meta
Normal file
8
Assets/UltimateXR/Editor/Animation.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 683fb1f4158e73347ba198cb71cd1f9c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Animation/IK.meta
Normal file
8
Assets/UltimateXR/Editor/Animation/IK.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 906ea6ad0d27cd741af855d8d8031c03
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
138
Assets/UltimateXR/Editor/Animation/IK/UxrCcdIKSolverEditor.cs
Normal file
138
Assets/UltimateXR/Editor/Animation/IK/UxrCcdIKSolverEditor.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrCcdIKSolverEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.IK;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrCcdIKSolver" />. Also draws handles in the scene window.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrCcdIKSolver))]
|
||||
public class UxrCcdIKSolverEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the link count variable and hooks the Update() method to monitor changes on the component's link count.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_linkCount = ((UxrCcdIKSolver)serializedObject.targetObject).Links.Count;
|
||||
EditorApplication.update += EditorApplication_Updated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the Update hook.
|
||||
/// </summary>
|
||||
private void OnDisable()
|
||||
{
|
||||
EditorApplication.update -= EditorApplication_Updated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the IK scene handles.
|
||||
/// </summary>
|
||||
private void OnSceneGUI()
|
||||
{
|
||||
UxrCcdIKSolver solverCcd = target as UxrCcdIKSolver;
|
||||
|
||||
if (solverCcd == null || solverCcd.Links == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying == false)
|
||||
{
|
||||
solverCcd.ComputeLinkData();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
foreach (UxrCcdLink link in solverCcd.Links)
|
||||
{
|
||||
if (link.Bone == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3 normal = link.Bone.TransformDirection(link.RotationAxis1);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis1.x), Mathf.Abs(link.RotationAxis1.y), Mathf.Abs(link.RotationAxis1.z), 0.3f);
|
||||
|
||||
float angle1Min = link.Axis1HasLimits ? link.Axis1AngleMin : -180.0f;
|
||||
float angle1Max = link.Axis1HasLimits ? link.Axis1AngleMax : 180.0f;
|
||||
|
||||
Handles.DrawSolidArc(link.Bone.position,
|
||||
normal,
|
||||
Quaternion.AngleAxis(angle1Min - link.Angle1, normal) * link.Bone.TransformDirection(link.LocalSpaceAxis1ZeroAngleVector),
|
||||
angle1Max - angle1Min,
|
||||
link.LinkLength * 0.5f);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis1.x), Mathf.Abs(link.RotationAxis1.y), Mathf.Abs(link.RotationAxis1.z), 1.0f);
|
||||
Handles.DrawLine(link.Bone.position, link.Bone.position + 0.6f * link.LinkLength * link.Bone.TransformDirection(link.LocalSpaceAxis1ZeroAngleVector));
|
||||
|
||||
if (link.Constraint == UxrCcdConstraintType.TwoAxes)
|
||||
{
|
||||
float angle2Min = link.Axis2HasLimits ? link.Axis2AngleMin : -180.0f;
|
||||
float angle2Max = link.Axis2HasLimits ? link.Axis2AngleMax : 180.0f;
|
||||
|
||||
normal = link.Bone.TransformDirection(link.RotationAxis2);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis2.x), Mathf.Abs(link.RotationAxis2.y), Mathf.Abs(link.RotationAxis2.z), 0.3f);
|
||||
Handles.DrawSolidArc(link.Bone.position,
|
||||
normal,
|
||||
Quaternion.AngleAxis(angle2Min + link.Angle2, normal) * link.Bone.TransformDirection(link.LocalSpaceAxis2ZeroAngleVector),
|
||||
angle2Max - angle2Min,
|
||||
link.LinkLength * 0.5f);
|
||||
Handles.color = new Color(Mathf.Abs(link.RotationAxis2.x), Mathf.Abs(link.RotationAxis2.y), Mathf.Abs(link.RotationAxis2.z), 1.0f);
|
||||
Handles.DrawLine(link.Bone.position, link.Bone.position + 0.6f * link.LinkLength * link.Bone.TransformDirection(link.LocalSpaceAxis2ZeroAngleVector));
|
||||
}
|
||||
|
||||
if (index == 0 && link.Bone != null && solverCcd.EndEffector != null && solverCcd.Goal != null)
|
||||
{
|
||||
Handles.color = Color.magenta;
|
||||
Handles.DrawLine(link.Bone.position, solverCcd.EndEffector.position);
|
||||
Handles.DrawLine(solverCcd.EndEffector.position, solverCcd.Goal.position);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Monitors for changes in the link count so that if new ones are added they are assigned default parameters.
|
||||
/// Unity does not support assigning default values to new elements added. This is the reason we need to do this.
|
||||
/// </summary>
|
||||
private void EditorApplication_Updated()
|
||||
{
|
||||
UxrCcdIKSolver solverCcd = target as UxrCcdIKSolver;
|
||||
|
||||
if (solverCcd != null && solverCcd.Links.Count != _linkCount)
|
||||
{
|
||||
if (solverCcd.Links.Count > _linkCount)
|
||||
{
|
||||
for (int i = _linkCount; i < solverCcd.Links.Count; ++i)
|
||||
{
|
||||
solverCcd.SetLinkDefaultValues(i);
|
||||
}
|
||||
}
|
||||
|
||||
_linkCount = solverCcd.Links.Count;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private int _linkCount;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3af81a625b57a0747b423d4b3523c429
|
||||
timeCreated: 1511875957
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
210
Assets/UltimateXR/Editor/Animation/IK/UxrIKBodySettingsDrawer.cs
Normal file
210
Assets/UltimateXR/Editor/Animation/IK/UxrIKBodySettingsDrawer.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrIKBodySettingsDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.IK;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Avatar.Controllers;
|
||||
using UltimateXR.Core;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrBodyIKSettings" />.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrBodyIKSettings))]
|
||||
public class UxrIKBodySettingsDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
public const string PropertyLockBodyPivot = "_lockBodyPivot";
|
||||
public const string PropertyBodyPivotRotationSpeed = "_bodyPivotRotationSpeed";
|
||||
public const string PropertyHeadFreeRangeBend = "_headFreeRangeBend";
|
||||
public const string PropertyHeadFreeRangeTorsion = "_headFreeRangeTorsion";
|
||||
public const string PropertyNeckHeadBalance = "_neckHeadBalance";
|
||||
public const string PropertySpineBend = "_spineBend";
|
||||
public const string PropertySpineTorsion = "_spineTorsion";
|
||||
public const string PropertyChestBend = "_chestBend";
|
||||
public const string PropertyChestTorsion = "_chestTorsion";
|
||||
public const string PropertyUpperChestBend = "_upperChestBend";
|
||||
public const string PropertyUpperChestTorsion = "_upperChestTorsion";
|
||||
public const string PropertyNeckBaseHeight = "_neckBaseHeight";
|
||||
public const string PropertyNeckForwardOffset = "_neckForwardOffset";
|
||||
public const string PropertyEyesBaseHeight = "_eyesBaseHeight";
|
||||
public const string PropertyEyesForwardOffset = "_eyesForwardOffset";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height in pixels for the given serialized property targeting a <see cref="UxrBodyIKSettings" />.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <param name="label">UI label</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (ShowNeckProperties(property))
|
||||
{
|
||||
return 15 * EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
return 13 * EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Draws an <see cref="UxrBodyIKSettings" /> serialized property and handles input.
|
||||
/// </summary>
|
||||
/// <param name="position">Position where to draw the property</param>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <param name="label">UI label</param>
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
int line = 0;
|
||||
|
||||
UxrAvatar avatar = ((MonoBehaviour)property.serializedObject.targetObject).GetComponent<UxrAvatar>();
|
||||
property.FindPropertyRelative(PropertyLockBodyPivot).boolValue = EditorGUI.Toggle(GetRect(position, line++, -1), ContentLockBodyPivot, property.FindPropertyRelative(PropertyLockBodyPivot).boolValue);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyBodyPivotRotationSpeed), 0.0f, 1.0f, ContentBodyPivotRotationSpeed);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyHeadFreeRangeBend), 0.0f, 180.0f, ContentHeadFreeRangeBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyHeadFreeRangeTorsion), 0.0f, 180.0f, ContentHeadFreeRangeTorsion);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyNeckHeadBalance), 0.0f, 1.0f, ContentNeckHeadBalance);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertySpineBend), 0.0f, 1.0f, ContentSpineBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertySpineTorsion), 0.0f, 1.0f, ContentSpineTorsion);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyChestBend), 0.0f, 1.0f, ContentChestBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyChestTorsion), 0.0f, 1.0f, ContentChestTorsion);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyUpperChestBend), 0.0f, 1.0f, ContentUpperChestBend);
|
||||
EditorGUI.Slider(GetRect(position, line++, -1), property.FindPropertyRelative(PropertyUpperChestTorsion), 0.0f, 1.0f, ContentUpperChestTorsion);
|
||||
|
||||
if (ShowNeckProperties(property))
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line++, 0), property.FindPropertyRelative(PropertyNeckBaseHeight), ContentNeckBaseHeight);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line++, 0), property.FindPropertyRelative(PropertyNeckForwardOffset), ContentNeckForwardOffset);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line, 0), property.FindPropertyRelative(PropertyEyesBaseHeight), ContentEyesBaseHeight);
|
||||
bool useAvatarEyesPressedBaseHeight = GUI.Button(GetRect(position, line, 1), new GUIContent("Use Avatar Eyes"));
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
if (useAvatarEyesPressedBaseHeight)
|
||||
{
|
||||
if (avatar.AvatarRig.Head.LeftEye == null || avatar.AvatarRig.Head.RightEye == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Assign field first", "The avatar component Rig field has eye(s) missing. Try to assign the value manually and use the eye gizmos for guidance.", UxrConstants.Editor.Ok);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
property.FindPropertyRelative(PropertyEyesBaseHeight).floatValue = (avatar.AvatarRig.Head.LeftEye.position.y + avatar.AvatarRig.Head.RightEye.position.y) * 0.5f - avatar.transform.position.y;
|
||||
}
|
||||
}
|
||||
|
||||
line++;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
EditorGUI.PropertyField(GetRect(position, line, 0), property.FindPropertyRelative(PropertyEyesForwardOffset), ContentEyesForwardOffset);
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
bool useAvatarEyesPressedForwardOffset = GUI.Button(GetRect(position, line, 1), new GUIContent("Use Avatar Eyes"));
|
||||
|
||||
if (useAvatarEyesPressedForwardOffset)
|
||||
{
|
||||
if (avatar.AvatarRig.Head.LeftEye == null || avatar.AvatarRig.Head.RightEye == null)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Assign field first", "The avatar component Rig field has eye(s) missing. Try to assign the value manually and use the eye gizmos for guidance.", UxrConstants.Editor.Ok);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 eyeLeft = avatar.transform.InverseTransformPoint(avatar.AvatarRig.Head.LeftEye.position);
|
||||
Vector3 eyeRight = avatar.transform.InverseTransformPoint(avatar.AvatarRig.Head.RightEye.position);
|
||||
property.FindPropertyRelative(PropertyEyesForwardOffset).floatValue = (eyeLeft.z + eyeRight.z) * 0.5f + 0.02f;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether to show the neck properties of the serialized <see cref="UxrBodyIKSettings" />.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <returns>Whether to show the neck properties</returns>
|
||||
private static bool ShowNeckProperties(SerializedProperty property)
|
||||
{
|
||||
UxrAvatarController controller = property.serializedObject.targetObject as UxrAvatarController;
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!controller.TryGetComponent<UxrAvatar>(out var avatar))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return avatar.AvatarRig.Head.Neck == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the rect for a given line in the property, since it will have multiple lines.
|
||||
/// </summary>
|
||||
/// <param name="position">Serialized property draw position</param>
|
||||
/// <param name="line">Line index</param>
|
||||
/// <param name="column">Column index</param>
|
||||
/// <returns>Rect to draw the given line in</returns>
|
||||
private static Rect GetRect(Rect position, int line, int column)
|
||||
{
|
||||
const int buttonWidth = 150;
|
||||
const int margin = 5;
|
||||
|
||||
return column switch
|
||||
{
|
||||
-1 => new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * line, position.width, EditorGUIUtility.singleLineHeight),
|
||||
0 => new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * line, position.width - buttonWidth - margin, EditorGUIUtility.singleLineHeight),
|
||||
_ => new Rect(position.x + position.width - buttonWidth, position.y + EditorGUIUtility.singleLineHeight * line, buttonWidth, EditorGUIUtility.singleLineHeight)
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentLockBodyPivot { get; } = new GUIContent("Lock Body Pivot", "For applications that require the avatar to remain in a fixed position");
|
||||
private GUIContent ContentBodyPivotRotationSpeed { get; } = new GUIContent("Body Pivot Rotation Speed", "The speed the body will twist to keep up with the head orientation");
|
||||
private GUIContent ContentHeadFreeRangeBend { get; } = new GUIContent("Head Free Range Bend", "The amount of degrees the head can rotate up and down without requiring support from the neck and bones below");
|
||||
private GUIContent ContentHeadFreeRangeTorsion { get; } = new GUIContent("Head Free Range Torsion", "The amount of degrees the head can rotate left and right without requiring support from the neck and bones below");
|
||||
private GUIContent ContentNeckHeadBalance { get; } = new GUIContent("Neck-Head Balance", "The balance between the neck and the head when solving the head orientation. Lower values will have the neck play a bigger role, while higher values will make the head play a bigger role");
|
||||
private GUIContent ContentSpineBend { get; } = new GUIContent("Spine Bend", "The amount of weight the spine will apply to solve up/down rotations");
|
||||
private GUIContent ContentSpineTorsion { get; } = new GUIContent("Spine Torsion", "The amount of weight the spine will apply to solve left/right rotations");
|
||||
private GUIContent ContentChestBend { get; } = new GUIContent("Chest Bend", "The amount of weight the chest will apply to solve up/down rotations");
|
||||
private GUIContent ContentChestTorsion { get; } = new GUIContent("Chest Torsion", "The amount of weight the chest will apply to solve left/right rotations");
|
||||
private GUIContent ContentUpperChestBend { get; } = new GUIContent("Upper Chest Bend", "The amount of weight the upper chest will apply to solve up/down rotations");
|
||||
private GUIContent ContentUpperChestTorsion { get; } = new GUIContent("Upper Chest Torsion", "The amount of weight the upper chest will apply to solve left/right rotations");
|
||||
private GUIContent ContentNeckBaseHeight { get; } = new GUIContent("Neck Base Height", "The height on the avatar where the base of the neck is located. The neck base will be drawn on the scene window as a white disc gizmo");
|
||||
private GUIContent ContentNeckForwardOffset { get; } = new GUIContent("Neck Forward Offset", "The forward offset from the avatar pivot where the neck is located. The neck base will be drawn on the scene window as a white disc gizmo");
|
||||
private GUIContent ContentEyesBaseHeight { get; } = new GUIContent("Eyes Base Height", "The height on the avatar where the eyes are located. The eye positions will be drawn on the scene window as white disc gizmos");
|
||||
private GUIContent ContentEyesForwardOffset { get; } = new GUIContent("Eyes Forward Offset", "The forward offset from the avatar pivot where the eyes are located. The eye positions will be drawn on the scene window as white disc gizmos");
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2121affa9bada5149845f3cfef8e8d4a
|
||||
timeCreated: 1512027976
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrIKSolverCcdLinkDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.IK;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.IK
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer for <see cref="UxrCcdLink" />.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrCcdLink))]
|
||||
public class UxrIKSolverCcdLinkDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Returns the height in pixels required to draw the property.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property to draw</param>
|
||||
/// <param name="label">UI label</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
int lines = 7;
|
||||
|
||||
if (property.FindPropertyRelative(PropertyAxis1HasLimits).boolValue)
|
||||
{
|
||||
lines += 2;
|
||||
}
|
||||
|
||||
int enumIndex = property.FindPropertyRelative(PropertyConstraint).enumValueIndex;
|
||||
|
||||
if (enumIndex == (int)UxrCcdConstraintType.TwoAxes)
|
||||
{
|
||||
if (property.FindPropertyRelative(PropertyAxis2HasLimits).boolValue)
|
||||
{
|
||||
lines += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
lines += 2;
|
||||
}
|
||||
}
|
||||
|
||||
return lines * EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector and handles input.
|
||||
/// </summary>
|
||||
/// <param name="position">Position where to draw the serialized property</param>
|
||||
/// <param name="property">Serialized property</param>
|
||||
/// <param name="label">UI label</param>
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
|
||||
EditorGUI.indentLevel += 1;
|
||||
|
||||
int line = 1;
|
||||
|
||||
property.FindPropertyRelative(PropertyWeight).floatValue = EditorGUI.Slider(UxrEditorUtils.GetRect(position, line++),
|
||||
ContentWeight,
|
||||
property.FindPropertyRelative(PropertyWeight).floatValue,
|
||||
0.0f,
|
||||
1.0f);
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyBone), ContentBone);
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyConstraint), ContentConstraint);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyRotationAxis1), ContentRotationAxis1);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis1HasLimits), ContentAxis1HasLimits);
|
||||
|
||||
if (property.FindPropertyRelative(PropertyAxis1HasLimits).boolValue)
|
||||
{
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis1AngleMin), ContentAxis1AngleMin);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis1AngleMax), ContentAxis1AngleMax);
|
||||
}
|
||||
|
||||
int enumIndex = property.FindPropertyRelative(PropertyConstraint).enumValueIndex;
|
||||
|
||||
if (enumIndex == (int)UxrCcdConstraintType.TwoAxes)
|
||||
{
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyRotationAxis2), ContentRotationAxis2);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis2HasLimits), ContentAxis2HasLimits);
|
||||
|
||||
if (property.FindPropertyRelative(PropertyAxis2HasLimits).boolValue)
|
||||
{
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis2AngleMin), ContentAxis2AngleMin);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAxis2AngleMax), ContentAxis2AngleMax);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyAlignToGoal), ContentAlignToGoal);
|
||||
|
||||
EditorGUI.indentLevel -= 1;
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentBone { get; } = new GUIContent("Bone", "");
|
||||
private GUIContent ContentWeight { get; } = new GUIContent("Weight", "");
|
||||
private GUIContent ContentConstraint { get; } = new GUIContent("Constraint", "");
|
||||
private GUIContent ContentRotationAxis1 { get; } = new GUIContent("Rotation Axis1", "");
|
||||
private GUIContent ContentRotationAxis2 { get; } = new GUIContent("Rotation Axis2", "");
|
||||
private GUIContent ContentAxis1HasLimits { get; } = new GUIContent("Axis1 Has Angle Limits", "");
|
||||
private GUIContent ContentAxis1AngleMin { get; } = new GUIContent("Axis1 Angle Min", "");
|
||||
private GUIContent ContentAxis1AngleMax { get; } = new GUIContent("Axis1 Angle Max", "");
|
||||
private GUIContent ContentAxis2HasLimits { get; } = new GUIContent("Axis2 Has Angle Limits", "");
|
||||
private GUIContent ContentAxis2AngleMin { get; } = new GUIContent("Axis2 Angle Min", "");
|
||||
private GUIContent ContentAxis2AngleMax { get; } = new GUIContent("Axis2 Angle Max", "");
|
||||
private GUIContent ContentAlignToGoal { get; } = new GUIContent("Align To Goal", "Tries to align this link to the same axes as the goal");
|
||||
|
||||
private const string PropertyBone = "_bone";
|
||||
private const string PropertyWeight = "_weight";
|
||||
private const string PropertyConstraint = "_constraint";
|
||||
private const string PropertyRotationAxis1 = "_rotationAxis1";
|
||||
private const string PropertyRotationAxis2 = "_rotationAxis2";
|
||||
private const string PropertyAxis1HasLimits = "_axis1HasLimits";
|
||||
private const string PropertyAxis1AngleMin = "_axis1AngleMin";
|
||||
private const string PropertyAxis1AngleMax = "_axis1AngleMax";
|
||||
private const string PropertyAxis2HasLimits = "_axis2HasLimits";
|
||||
private const string PropertyAxis2AngleMin = "_axis2AngleMin";
|
||||
private const string PropertyAxis2AngleMax = "_axis2AngleMax";
|
||||
private const string PropertyAlignToGoal = "_alignToGoal";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f57588fb49769d4449e44e297f493eca
|
||||
timeCreated: 1512027976
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Animation/Interpolation.meta
Normal file
8
Assets/UltimateXR/Editor/Animation/Interpolation.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 378b67fc1aa90e441ad3217fa6ca9138
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,189 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrEasingDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.Interpolation;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Extensions.Unity.Render;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.Interpolation
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector drawer for <see cref="UxrEasing" />.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrEasing))]
|
||||
public class UxrEasingDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// This constant determines the graph height in pixels.
|
||||
/// </summary>
|
||||
public const int GraphHeight = 80;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors & Finalizer
|
||||
|
||||
/// <summary>
|
||||
/// Creates the temporal material to draw the graph.
|
||||
/// </summary>
|
||||
public UxrEasingDrawer()
|
||||
{
|
||||
var shader = Shader.Find(UxrConstants.Shaders.HiddenInternalColoredShader);
|
||||
_lineMaterial = new Material(shader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the temporal material to draw the graph.
|
||||
/// </summary>
|
||||
~UxrEasingDrawer()
|
||||
{
|
||||
Object.DestroyImmediate(_lineMaterial);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height in pixels required to draw the property.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property describing an <see cref="UxrEasing" /></param>
|
||||
/// <param name="label">UI label</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return EditorGUIUtility.singleLineHeight + GraphHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Draws the easing graph.
|
||||
/// </summary>
|
||||
/// <param name="rect">Target rect</param>
|
||||
/// <param name="material">Material used</param>
|
||||
/// <param name="color">The line color</param>
|
||||
/// <param name="easing">The easing used</param>
|
||||
/// <param name="loopMode">The loop mode</param>
|
||||
/// <param name="loops">The number of loops to draw</param>
|
||||
public static void DrawGraph(Rect rect, Material material, Color color, UxrEasing easing, UxrLoopMode loopMode = UxrLoopMode.None, int loops = 1)
|
||||
{
|
||||
// Make coordinates relative to the rect.
|
||||
GUI.BeginClip(rect);
|
||||
|
||||
// Enable the internal material.
|
||||
material.SetPass(0);
|
||||
|
||||
// Draw background. Use alpha to avoid getting too dark.
|
||||
GL.Begin(GL.QUADS);
|
||||
GL.Color(Color.black.WithAlpha(0.4f));
|
||||
GL.Vertex3(0, rect.height, 0);
|
||||
GL.Vertex3(rect.width, rect.height, 0);
|
||||
GL.Vertex3(rect.width, 0, 0);
|
||||
GL.Vertex3(0, 0, 0);
|
||||
GL.End();
|
||||
|
||||
// Now draw the graph as a connected set of points.
|
||||
GL.Begin(GL.LINE_STRIP);
|
||||
GL.Color(color);
|
||||
|
||||
// Get the min/max graph values.
|
||||
// This is important because some interpolation curves go out the [0, 1] range.
|
||||
GetGraphRange(easing, out float min, out float max);
|
||||
|
||||
// Iterate over points and draw vertices.
|
||||
for (int i = 0; i < CurveSegments + 1; ++i)
|
||||
{
|
||||
float t = (float)i / CurveSegments;
|
||||
float value = UxrInterpolator.Interpolate(Vector4.one, Vector4.zero, 1.0f, 0.0f, t * loops, easing, loopMode).x;
|
||||
float valueScaled = Mathf.InverseLerp(min, max, value);
|
||||
GL.Vertex3(t * rect.width, rect.height * valueScaled, 0);
|
||||
}
|
||||
|
||||
GL.End();
|
||||
GUI.EndClip();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector and handles input.
|
||||
/// </summary>
|
||||
/// <param name="position">Position where to draw the inspector</param>
|
||||
/// <param name="property">Serialized property to draw</param>
|
||||
/// <param name="label">UI label</param>
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// Draw the property label and value
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, 0), property, label);
|
||||
|
||||
// Get the graph rect. Overwrite with graph height in pixels and indentation so that it is drawn below the values only and not taking the whole inspector width.
|
||||
Rect rect = UxrEditorUtils.GetRect(position, 1);
|
||||
rect.height = GraphHeight;
|
||||
rect.xMin += EditorGUIUtility.labelWidth;
|
||||
|
||||
// Get our easing value from the property.
|
||||
UxrEasing easing = (UxrEasing)property.enumValueIndex;
|
||||
|
||||
// Draw the graph!
|
||||
if (Event.current.type == EventType.Repaint)
|
||||
{
|
||||
DrawGraph(rect, _lineMaterial, Color.green, easing);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the min and max values for a type of interpolation.
|
||||
/// </summary>
|
||||
/// <param name="easing">Easing</param>
|
||||
/// <param name="min">Returns the min graph value</param>
|
||||
/// <param name="max">Returns the max graph value</param>
|
||||
private static void GetGraphRange(UxrEasing easing, out float min, out float max)
|
||||
{
|
||||
min = float.MaxValue;
|
||||
max = float.MinValue;
|
||||
|
||||
for (int i = 0; i < CurveSegments + 1; ++i)
|
||||
{
|
||||
float t = (float)i / CurveSegments;
|
||||
float value = UxrInterpolator.Interpolate(1.0f, 0.0f, t, easing);
|
||||
|
||||
if (value < min)
|
||||
{
|
||||
min = value;
|
||||
}
|
||||
|
||||
if (value > max)
|
||||
{
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Determines the amount of segments to draw the graph with.
|
||||
/// </summary>
|
||||
private const int CurveSegments = 200;
|
||||
|
||||
private readonly Material _lineMaterial;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29edf75ae0a2aee4b88acb8a976dbb6e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,139 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrInterpolationSettingsDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.Interpolation;
|
||||
using UltimateXR.Core;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.Interpolation
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector drawer for <see cref="UxrInterpolationSettings" />.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrInterpolationSettings))]
|
||||
public class UxrInterpolationSettingsDrawer : PropertyDrawer
|
||||
{
|
||||
#region Constructors & Finalizer
|
||||
|
||||
/// <summary>
|
||||
/// Creates the temporal material to draw the graph.
|
||||
/// </summary>
|
||||
public UxrInterpolationSettingsDrawer()
|
||||
{
|
||||
var shader = Shader.Find(UxrConstants.Shaders.HiddenInternalColoredShader);
|
||||
_lineMaterial = new Material(shader);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the temporal material to draw the graph.
|
||||
/// </summary>
|
||||
~UxrInterpolationSettingsDrawer()
|
||||
{
|
||||
Object.DestroyImmediate(_lineMaterial);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Gets the height in pixels required to draw the property.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property describing an <see cref="UxrInterpolationSettings" /></param>
|
||||
/// <param name="label">UI label</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
int lineCount = 5;
|
||||
int loopGraphHeight = 0;
|
||||
|
||||
if (property.FindPropertyRelative(PropertyLoopMode).enumValueIndex != (int)UxrLoopMode.None)
|
||||
{
|
||||
lineCount++;
|
||||
loopGraphHeight += UxrEasingDrawer.GraphHeight;
|
||||
}
|
||||
|
||||
if (property.FindPropertyRelative(PropertyDelay).floatValue > 0.0f)
|
||||
{
|
||||
lineCount++;
|
||||
}
|
||||
|
||||
return lineCount * EditorGUIUtility.singleLineHeight + UxrEasingDrawer.GraphHeight + loopGraphHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector and handles input.
|
||||
/// </summary>
|
||||
/// <param name="position">Position where to draw the inspector</param>
|
||||
/// <param name="property">Serialized property to draw</param>
|
||||
/// <param name="label">UI label</param>
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
int line = 0;
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyDurationSeconds), ContentDurationSeconds);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyDelay), ContentDelay);
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyEasing), ContentEasing);
|
||||
position.y += UxrEasingDrawer.GraphHeight;
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyLoopMode), ContentLoopMode);
|
||||
|
||||
UxrLoopMode loopMode = (UxrLoopMode)property.FindPropertyRelative(PropertyLoopMode).enumValueIndex;
|
||||
|
||||
if (loopMode != (int)UxrLoopMode.None)
|
||||
{
|
||||
// Draw preview graph
|
||||
|
||||
Rect graphRect = UxrEditorUtils.GetRect(position, line);
|
||||
graphRect.height = UxrEasingDrawer.GraphHeight;
|
||||
graphRect.xMin += EditorGUIUtility.labelWidth;
|
||||
|
||||
UxrEasing easing = (UxrEasing)property.FindPropertyRelative(PropertyEasing).enumValueIndex;
|
||||
|
||||
UxrEasingDrawer.DrawGraph(graphRect, _lineMaterial, Color.green, easing, loopMode, 5);
|
||||
|
||||
position.y += UxrEasingDrawer.GraphHeight;
|
||||
|
||||
// Draw looped duration property
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyLoopedDurationSeconds), ContentLoopedDurationSeconds);
|
||||
}
|
||||
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line++), property.FindPropertyRelative(PropertyUnscaledTime), ContentUnscaledTime);
|
||||
|
||||
if (property.FindPropertyRelative(PropertyDelay).floatValue > 0.0f)
|
||||
{
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, line), property.FindPropertyRelative(PropertyDelayUsingEndValue), ContentDelayUsingEndValue);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentDurationSeconds { get; } = new GUIContent("Duration (Seconds)", "The duration in seconds of the interpolation. In a looped animation it specifies the duration of each loop.");
|
||||
private GUIContent ContentDelay { get; } = new GUIContent("Delay (Seconds)", "The seconds to wait before the interpolation starts");
|
||||
private GUIContent ContentEasing { get; } = new GUIContent("Easing", "The animation curve to use for the interpolation");
|
||||
private GUIContent ContentLoopMode { get; } = new GUIContent("Loop Mode", "The type of loop to use");
|
||||
private GUIContent ContentLoopedDurationSeconds { get; } = new GUIContent("Looped Duration (Seconds)", "The total duration in seconds in a looped interpolation. Use -1 to loop indefinitely.");
|
||||
private GUIContent ContentUnscaledTime { get; } = new GUIContent("Use Unscaled Time", "Whether to use unscaled time, which is unaffected by the timescale");
|
||||
private GUIContent ContentDelayUsingEndValue { get; } = new GUIContent("Use End Value During Delay?", "Whether to use the end value in the interpolation during the initial delay");
|
||||
|
||||
private const string PropertyDurationSeconds = "_durationSeconds";
|
||||
private const string PropertyDelay = "_delaySeconds";
|
||||
private const string PropertyEasing = "_easing";
|
||||
private const string PropertyLoopMode = "_loopMode";
|
||||
private const string PropertyLoopedDurationSeconds = "_loopedDurationSeconds";
|
||||
private const string PropertyUnscaledTime = "_useUnscaledTime";
|
||||
private const string PropertyDelayUsingEndValue = "_delayUsingEndValue";
|
||||
|
||||
private readonly Material _lineMaterial;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d13258678ccb1cf4fb668f0506bfce5b
|
||||
timeCreated: 1505111962
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Animation/Lights.meta
Normal file
8
Assets/UltimateXR/Editor/Animation/Lights.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7b495cabfdb786e4082f0e4f3366f1a1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,163 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAnimateLightIntensityEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation;
|
||||
using UltimateXR.Animation.Lights;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.Lights
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrAnimatedLightIntensity" />.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrAnimatedLightIntensity))]
|
||||
[CanEditMultipleObjects]
|
||||
public class UxrAnimateLightIntensityEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_propertyLight = serializedObject.FindProperty("_light");
|
||||
_propertyAnimationMode = serializedObject.FindProperty("_animationMode");
|
||||
_propertyValueSpeed = serializedObject.FindProperty("_valueSpeed");
|
||||
_propertyValueSpeedDuration = serializedObject.FindProperty("_valueSpeedDurationSeconds");
|
||||
_propertyValueStart = serializedObject.FindProperty("_valueStart");
|
||||
_propertyValueEnd = serializedObject.FindProperty("_valueEnd");
|
||||
_propertyValueDisabled = serializedObject.FindProperty("_valueDisabled");
|
||||
_propertyInterpolationSettings = serializedObject.FindProperty("_interpolationSettings");
|
||||
_propertyValueNoiseTimeStart = serializedObject.FindProperty("_valueNoiseTimeStart");
|
||||
_propertyValueNoiseDuration = serializedObject.FindProperty("_valueNoiseDuration");
|
||||
_propertyValueNoiseValueStart = serializedObject.FindProperty("_valueNoiseValueStart");
|
||||
_propertyValueNoiseValueEnd = serializedObject.FindProperty("_valueNoiseValueEnd");
|
||||
_propertyValueNoiseValueMin = serializedObject.FindProperty("_valueNoiseValueMin");
|
||||
_propertyValueNoiseValueMax = serializedObject.FindProperty("_valueNoiseValueMax");
|
||||
_propertyValueNoiseFrequency = serializedObject.FindProperty("_valueNoiseFrequency");
|
||||
_propertyValueNoiseOffset = serializedObject.FindProperty("_valueNoiseOffset");
|
||||
_propertyUseUnscaledTime = serializedObject.FindProperty("_useUnscaledTime");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector and handles input.
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
UxrAnimatedLightIntensity animatedLightIntensity = (UxrAnimatedLightIntensity)serializedObject.targetObject;
|
||||
|
||||
if (animatedLightIntensity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyLight, ContentLight);
|
||||
|
||||
if (animatedLightIntensity.HasFinished == false)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyAnimationMode, ContentAnimationMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Curve finished");
|
||||
}
|
||||
|
||||
if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.None)
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.Speed)
|
||||
{
|
||||
Vector4AsFloatPropertyField(_propertyValueSpeed, ContentValueSpeed);
|
||||
EditorGUILayout.PropertyField(_propertyValueSpeedDuration, ContentValueSpeedDuration);
|
||||
EditorGUILayout.PropertyField(_propertyUseUnscaledTime);
|
||||
}
|
||||
else if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.Interpolate)
|
||||
{
|
||||
Vector4AsFloatPropertyField(_propertyValueStart, ContentValueStart);
|
||||
Vector4AsFloatPropertyField(_propertyValueEnd, ContentValueEnd);
|
||||
Vector4AsFloatPropertyField(_propertyValueDisabled, ContentValueDisabled);
|
||||
EditorGUILayout.PropertyField(_propertyInterpolationSettings, ContentInterpolationSettings);
|
||||
}
|
||||
else if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.Noise)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyValueNoiseTimeStart, ContentValueNoiseTimeStart);
|
||||
EditorGUILayout.PropertyField(_propertyValueNoiseDuration, ContentValueNoiseDuration);
|
||||
Vector4AsFloatPropertyField(_propertyValueNoiseValueStart, ContentValueNoiseValueStart);
|
||||
Vector4AsFloatPropertyField(_propertyValueNoiseValueEnd, ContentValueNoiseValueEnd);
|
||||
Vector4AsFloatPropertyField(_propertyValueNoiseValueMin, ContentValueNoiseValueMin);
|
||||
Vector4AsFloatPropertyField(_propertyValueNoiseValueMax, ContentValueNoiseValueMax);
|
||||
Vector4AsFloatPropertyField(_propertyValueNoiseFrequency, ContentValueNoiseFrequency);
|
||||
Vector4AsFloatPropertyField(_propertyValueNoiseOffset, ContentValueNoiseOffset);
|
||||
EditorGUILayout.PropertyField(_propertyUseUnscaledTime, ContentUseUnscaledTime);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Draws a float property field but assigns it to a Vector4 serialized property.
|
||||
/// </summary>
|
||||
/// <param name="property">Serialized property that targets a Vector4 value</param>
|
||||
/// <param name="guiContent">UI information</param>
|
||||
private void Vector4AsFloatPropertyField(SerializedProperty property, GUIContent guiContent)
|
||||
{
|
||||
property.vector4Value = new Vector4(EditorGUILayout.FloatField(guiContent, property.vector4Value.x), 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentLight { get; } = new GUIContent("Light");
|
||||
private GUIContent ContentAnimationMode { get; } = new GUIContent("Animation Mode");
|
||||
private GUIContent ContentValueSpeed { get; } = new GUIContent("Speed");
|
||||
private GUIContent ContentValueSpeedDuration { get; } = new GUIContent("Duration (seconds)");
|
||||
private GUIContent ContentValueStart { get; } = new GUIContent("Start Value");
|
||||
private GUIContent ContentValueEnd { get; } = new GUIContent("End Value");
|
||||
private GUIContent ContentValueDisabled { get; } = new GUIContent("Value When Disabled");
|
||||
private GUIContent ContentInterpolationSettings { get; } = new GUIContent("Interpolation Settings");
|
||||
private GUIContent ContentValueNoiseTimeStart { get; } = new GUIContent("Noise Time Start");
|
||||
private GUIContent ContentValueNoiseDuration { get; } = new GUIContent("Noise Duration");
|
||||
private GUIContent ContentValueNoiseValueStart { get; } = new GUIContent("Value Start");
|
||||
private GUIContent ContentValueNoiseValueEnd { get; } = new GUIContent("Value End");
|
||||
private GUIContent ContentValueNoiseValueMin { get; } = new GUIContent("Noise Value Min");
|
||||
private GUIContent ContentValueNoiseValueMax { get; } = new GUIContent("Noise Value Max");
|
||||
private GUIContent ContentValueNoiseFrequency { get; } = new GUIContent("Noise Frequency");
|
||||
private GUIContent ContentValueNoiseOffset { get; } = new GUIContent("Noise Offset");
|
||||
private GUIContent ContentUseUnscaledTime { get; } = new GUIContent("Use Unscaled Time");
|
||||
|
||||
private SerializedProperty _propertyLight;
|
||||
private SerializedProperty _propertyAnimationMode;
|
||||
private SerializedProperty _propertyValueSpeed;
|
||||
private SerializedProperty _propertyValueSpeedDuration;
|
||||
private SerializedProperty _propertyValueStart;
|
||||
private SerializedProperty _propertyValueEnd;
|
||||
private SerializedProperty _propertyValueDisabled;
|
||||
private SerializedProperty _propertyInterpolationSettings;
|
||||
private SerializedProperty _propertyValueNoiseTimeStart;
|
||||
private SerializedProperty _propertyValueNoiseDuration;
|
||||
private SerializedProperty _propertyValueNoiseValueStart;
|
||||
private SerializedProperty _propertyValueNoiseValueEnd;
|
||||
private SerializedProperty _propertyValueNoiseValueMin;
|
||||
private SerializedProperty _propertyValueNoiseValueMax;
|
||||
private SerializedProperty _propertyValueNoiseFrequency;
|
||||
private SerializedProperty _propertyValueNoiseOffset;
|
||||
private SerializedProperty _propertyUseUnscaledTime;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca36d821a4c7a8b4698ed55dcd0080b4
|
||||
timeCreated: 1511875957
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Animation/Materials.meta
Normal file
8
Assets/UltimateXR/Editor/Animation/Materials.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0c28b289ce91fc43a0b03df7ebc1f63
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,237 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAnimatedMaterialEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation;
|
||||
using UltimateXR.Animation.Materials;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.Materials
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrAnimatedMaterial" />.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrAnimatedMaterial))]
|
||||
[CanEditMultipleObjects]
|
||||
public class UxrAnimatedMaterialEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Caches serialized properties.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propertyAnimationMode = serializedObject.FindProperty("_animationMode");
|
||||
_propertyAnimateSelf = serializedObject.FindProperty("_animateSelf");
|
||||
_propertyTargetGameObject = serializedObject.FindProperty("_targetGameObject");
|
||||
_propertyMaterialSlot = serializedObject.FindProperty("_materialSlot");
|
||||
_propertyMaterialMode = serializedObject.FindProperty("_materialMode");
|
||||
_propertyRestoreWhenFinished = serializedObject.FindProperty("_restoreWhenFinished");
|
||||
_propertyParameterType = serializedObject.FindProperty("_parameterType");
|
||||
_propertyParameterName = serializedObject.FindProperty("_parameterName");
|
||||
_propertyValueSpeed = serializedObject.FindProperty("_valueSpeed");
|
||||
_propertyValueSpeedDuration = serializedObject.FindProperty("_valueSpeedDurationSeconds");
|
||||
_propertyValueStart = serializedObject.FindProperty("_valueStart");
|
||||
_propertyValueEnd = serializedObject.FindProperty("_valueEnd");
|
||||
_propertyValueDisabled = serializedObject.FindProperty("_valueDisabled");
|
||||
_propertyInterpolationSettings = serializedObject.FindProperty("_interpolationSettings");
|
||||
_propertyValueNoiseTimeStart = serializedObject.FindProperty("_valueNoiseTimeStart");
|
||||
_propertyValueNoiseDuration = serializedObject.FindProperty("_valueNoiseDuration");
|
||||
_propertyValueNoiseValueStart = serializedObject.FindProperty("_valueNoiseValueStart");
|
||||
_propertyValueNoiseValueEnd = serializedObject.FindProperty("_valueNoiseValueEnd");
|
||||
_propertyValueNoiseValueMin = serializedObject.FindProperty("_valueNoiseValueMin");
|
||||
_propertyValueNoiseValueMax = serializedObject.FindProperty("_valueNoiseValueMax");
|
||||
_propertyValueNoiseFrequency = serializedObject.FindProperty("_valueNoiseFrequency");
|
||||
_propertyValueNoiseOffset = serializedObject.FindProperty("_valueNoiseOffset");
|
||||
_propertyUseUnscaledTime = serializedObject.FindProperty("_useUnscaledTime");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector UI.
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
UxrAnimatedMaterial animatedMaterial = (UxrAnimatedMaterial)serializedObject.targetObject;
|
||||
|
||||
if (animatedMaterial == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (animatedMaterial.HasFinished == false)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyAnimationMode, ContentAnimationMode);
|
||||
EditorGUILayout.PropertyField(_propertyAnimateSelf, ContentAnimateSelf);
|
||||
|
||||
if (!_propertyAnimateSelf.boolValue)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyTargetGameObject, ContentTargetGameObject);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Curve finished");
|
||||
}
|
||||
|
||||
if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.None)
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyMaterialSlot, ContentMaterialSlot);
|
||||
EditorGUILayout.PropertyField(_propertyMaterialMode, ContentMaterialMode);
|
||||
|
||||
if (_propertyMaterialMode.enumValueIndex == (int)UxrMaterialMode.InstanceOnly)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyRestoreWhenFinished, ContentRestoreWhenFinished);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyParameterType, ContentParameterType);
|
||||
EditorGUILayout.PropertyField(_propertyParameterName, ContentParameterName);
|
||||
|
||||
if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.Speed)
|
||||
{
|
||||
ParameterPropertyField(ContentValueSpeed, _propertyValueSpeed);
|
||||
EditorGUILayout.PropertyField(_propertyValueSpeedDuration, ContentValueSpeedDuration);
|
||||
EditorGUILayout.PropertyField(_propertyUseUnscaledTime, ContentUseUnscaledTime);
|
||||
}
|
||||
else if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.Interpolate)
|
||||
{
|
||||
ParameterPropertyField(ContentValueStart, _propertyValueStart, true);
|
||||
ParameterPropertyField(ContentValueEnd, _propertyValueEnd, true);
|
||||
ParameterPropertyField(ContentValueDisabled, _propertyValueDisabled, true);
|
||||
EditorGUILayout.PropertyField(_propertyInterpolationSettings, ContentInterpolationSettings, true);
|
||||
}
|
||||
else if (_propertyAnimationMode.enumValueIndex == (int)UxrAnimationMode.Noise)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyValueNoiseTimeStart, ContentValueNoiseTimeStart);
|
||||
EditorGUILayout.PropertyField(_propertyValueNoiseDuration, ContentValueNoiseDuration);
|
||||
ParameterPropertyField(ContentValueNoiseValueStart, _propertyValueNoiseValueStart, true);
|
||||
ParameterPropertyField(ContentValueNoiseValueEnd, _propertyValueNoiseValueEnd, true);
|
||||
ParameterPropertyField(ContentValueNoiseValueMin, _propertyValueNoiseValueMin, true);
|
||||
ParameterPropertyField(ContentValueNoiseValueMax, _propertyValueNoiseValueMax, true);
|
||||
ParameterPropertyField(ContentValueNoiseFrequency, _propertyValueNoiseFrequency);
|
||||
ParameterPropertyField(ContentValueNoiseOffset, _propertyValueNoiseOffset);
|
||||
EditorGUILayout.PropertyField(_propertyUseUnscaledTime, ContentUseUnscaledTime);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Draws an inspector property field depending on the material parameter type.
|
||||
/// </summary>
|
||||
/// <param name="guiContent">The label and tooltip to show in the inspector</param>
|
||||
/// <param name="property">The serialized property</param>
|
||||
/// <param name="isParameterValue">
|
||||
/// When using colors, Whether to force to show the field as a vector4 instead of a color
|
||||
/// picker
|
||||
/// </param>
|
||||
private void ParameterPropertyField(GUIContent guiContent, SerializedProperty property, bool isParameterValue = false)
|
||||
{
|
||||
switch (_propertyParameterType.enumValueIndex)
|
||||
{
|
||||
case (int)UxrMaterialParameterType.Int:
|
||||
property.vector4Value = new Vector4(EditorGUILayout.IntField(guiContent, Mathf.RoundToInt(property.vector4Value.x)), 0, 0, 0);
|
||||
break;
|
||||
|
||||
case (int)UxrMaterialParameterType.Float:
|
||||
property.vector4Value = new Vector4(EditorGUILayout.FloatField(guiContent, property.vector4Value.x), 0, 0, 0);
|
||||
break;
|
||||
|
||||
case (int)UxrMaterialParameterType.Vector2:
|
||||
property.vector4Value = EditorGUILayout.Vector2Field(guiContent, new Vector2(property.vector4Value.x, property.vector4Value.y));
|
||||
break;
|
||||
|
||||
case (int)UxrMaterialParameterType.Vector3:
|
||||
property.vector4Value = EditorGUILayout.Vector3Field(guiContent, new Vector3(property.vector4Value.x, property.vector4Value.y, property.vector4Value.z));
|
||||
break;
|
||||
|
||||
case (int)UxrMaterialParameterType.Vector4:
|
||||
property.vector4Value = EditorGUILayout.Vector4Field(guiContent, property.vector4Value);
|
||||
break;
|
||||
|
||||
case (int)UxrMaterialParameterType.Color:
|
||||
|
||||
if (!isParameterValue)
|
||||
{
|
||||
property.vector4Value = EditorGUILayout.Vector4Field(guiContent, property.vector4Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
property.vector4Value = EditorGUILayout.ColorField(guiContent, property.vector4Value);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentAnimationMode { get; } = new GUIContent("Animation Mode");
|
||||
private GUIContent ContentAnimateSelf { get; } = new GUIContent("Animate Self");
|
||||
private GUIContent ContentTargetGameObject { get; } = new GUIContent("Target GameObject");
|
||||
private GUIContent ContentMaterialSlot { get; } = new GUIContent("Material Slot");
|
||||
private GUIContent ContentMaterialMode { get; } = new GUIContent("Material Mode");
|
||||
private GUIContent ContentRestoreWhenFinished { get; } = new GUIContent("Restore When Finished", "Restores the original material when the instance animation finished. Use this for performance since shared materials can save draw calls and render state changes");
|
||||
private GUIContent ContentParameterType { get; } = new GUIContent("Parameter Type");
|
||||
private GUIContent ContentParameterName { get; } = new GUIContent("Parameter Name");
|
||||
private GUIContent ContentValueSpeed { get; } = new GUIContent("Speed");
|
||||
private GUIContent ContentValueSpeedDuration { get; } = new GUIContent("Duration (seconds)");
|
||||
private GUIContent ContentValueStart { get; } = new GUIContent("Start Value");
|
||||
private GUIContent ContentValueEnd { get; } = new GUIContent("End Value");
|
||||
private GUIContent ContentValueDisabled { get; } = new GUIContent("Value When Disabled");
|
||||
private GUIContent ContentInterpolationSettings { get; } = new GUIContent("Interpolation Settings");
|
||||
private GUIContent ContentValueNoiseTimeStart { get; } = new GUIContent("Noise Time Start");
|
||||
private GUIContent ContentValueNoiseDuration { get; } = new GUIContent("Noise Duration");
|
||||
private GUIContent ContentValueNoiseValueStart { get; } = new GUIContent("Value Start");
|
||||
private GUIContent ContentValueNoiseValueEnd { get; } = new GUIContent("Value End");
|
||||
private GUIContent ContentValueNoiseValueMin { get; } = new GUIContent("Noise Value Min");
|
||||
private GUIContent ContentValueNoiseValueMax { get; } = new GUIContent("Noise Value Max");
|
||||
private GUIContent ContentValueNoiseFrequency { get; } = new GUIContent("Noise Frequency");
|
||||
private GUIContent ContentValueNoiseOffset { get; } = new GUIContent("Noise Offset");
|
||||
private GUIContent ContentUseUnscaledTime { get; } = new GUIContent("Use Unscaled Time");
|
||||
|
||||
private SerializedProperty _propertyAnimationMode;
|
||||
private SerializedProperty _propertyAnimateSelf;
|
||||
private SerializedProperty _propertyTargetGameObject;
|
||||
private SerializedProperty _propertyMaterialSlot;
|
||||
private SerializedProperty _propertyMaterialMode;
|
||||
private SerializedProperty _propertyRestoreWhenFinished;
|
||||
private SerializedProperty _propertyParameterType;
|
||||
private SerializedProperty _propertyParameterName;
|
||||
private SerializedProperty _propertyValueSpeed;
|
||||
private SerializedProperty _propertyValueSpeedDuration;
|
||||
private SerializedProperty _propertyValueStart;
|
||||
private SerializedProperty _propertyValueEnd;
|
||||
private SerializedProperty _propertyValueDisabled;
|
||||
private SerializedProperty _propertyInterpolationSettings;
|
||||
private SerializedProperty _propertyValueNoiseTimeStart;
|
||||
private SerializedProperty _propertyValueNoiseDuration;
|
||||
private SerializedProperty _propertyValueNoiseValueStart;
|
||||
private SerializedProperty _propertyValueNoiseValueEnd;
|
||||
private SerializedProperty _propertyValueNoiseValueMin;
|
||||
private SerializedProperty _propertyValueNoiseValueMax;
|
||||
private SerializedProperty _propertyValueNoiseFrequency;
|
||||
private SerializedProperty _propertyValueNoiseOffset;
|
||||
private SerializedProperty _propertyUseUnscaledTime;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0106c1d6d9a8af2468aa8e5f1b3f3510
|
||||
timeCreated: 1511875957
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Animation/Transforms.meta
Normal file
8
Assets/UltimateXR/Editor/Animation/Transforms.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e28f7a30a665f264fa80e223355148ee
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,212 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAnimatedTransformEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation;
|
||||
using UltimateXR.Animation.Transforms;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.Transforms
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrAnimatedTransform" />.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrAnimatedTransform))]
|
||||
public class UxrAnimatedTransformEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Caches serialized properties.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propertyTranslationMode = serializedObject.FindProperty("_translationMode");
|
||||
_propertyTranslationSpace = serializedObject.FindProperty("_translationSpace");
|
||||
_propertyTranslationSpeed = serializedObject.FindProperty("_translationSpeed");
|
||||
_propertyTranslationStart = serializedObject.FindProperty("_translationStart");
|
||||
_propertyTranslationEnd = serializedObject.FindProperty("_translationEnd");
|
||||
_propertyTranslationUseUnscaledTime = serializedObject.FindProperty("_translationUseUnscaledTime");
|
||||
_propertyTranslationInterpolationSetting = serializedObject.FindProperty("_translationInterpolationSettings");
|
||||
_propertyRotationMode = serializedObject.FindProperty("_rotationMode");
|
||||
_propertyRotationSpace = serializedObject.FindProperty("_rotationSpace");
|
||||
_propertyEulerSpeed = serializedObject.FindProperty("_eulerSpeed");
|
||||
_propertyEulerStart = serializedObject.FindProperty("_eulerStart");
|
||||
_propertyEulerEnd = serializedObject.FindProperty("_eulerEnd");
|
||||
_propertyRotationUseUnscaledTime = serializedObject.FindProperty("_rotationUseUnscaledTime");
|
||||
_propertyRotationInterpolationSettings = serializedObject.FindProperty("_rotationInterpolationSettings");
|
||||
_propertyScalingMode = serializedObject.FindProperty("_scalingMode");
|
||||
_propertyScalingSpeed = serializedObject.FindProperty("_scalingSpeed");
|
||||
_propertyScalingStart = serializedObject.FindProperty("_scalingStart");
|
||||
_propertyScalingEnd = serializedObject.FindProperty("_scalingEnd");
|
||||
_propertyScalingUseUnscaledTime = serializedObject.FindProperty("_scalingUseUnscaledTime");
|
||||
_propertyScalingInterpolationSettings = serializedObject.FindProperty("_scalingInterpolationSettings");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector and handles input.
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
UxrAnimatedTransform animatedTransform = (UxrAnimatedTransform)serializedObject.targetObject;
|
||||
|
||||
if (animatedTransform == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (animatedTransform.HasTranslationFinished == false)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyTranslationMode, ContentTranslationMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Translation curve finished");
|
||||
}
|
||||
|
||||
if (_propertyTranslationMode.enumValueIndex == (int)UxrAnimationMode.Speed)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_propertyTranslationSpace, ContentTranslationSpace);
|
||||
EditorGUILayout.PropertyField(_propertyTranslationSpeed, ContentTranslationSpeed);
|
||||
EditorGUILayout.PropertyField(_propertyTranslationUseUnscaledTime, ContentTranslationUseUnscaledTime);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else if (_propertyTranslationMode.enumValueIndex == (int)UxrAnimationMode.Interpolate)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_propertyTranslationSpace, ContentTranslationSpace);
|
||||
EditorGUILayout.PropertyField(_propertyTranslationStart, ContentTranslationStart);
|
||||
EditorGUILayout.PropertyField(_propertyTranslationEnd, ContentTranslationEnd);
|
||||
EditorGUILayout.PropertyField(_propertyTranslationInterpolationSetting, ContentTranslationInterpolationSetting);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else if (_propertyTranslationMode.enumValueIndex == (int)UxrAnimationMode.Noise)
|
||||
{
|
||||
EditorGUILayout.LabelField("Unsupported for now");
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (animatedTransform.HasRotationFinished == false)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyRotationMode, ContentRotationMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Rotation curve finished");
|
||||
}
|
||||
|
||||
if (_propertyRotationMode.enumValueIndex == (int)UxrAnimationMode.Speed)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_propertyRotationSpace, ContentRotationSpace);
|
||||
EditorGUILayout.PropertyField(_propertyEulerSpeed, ContentEulerSpeed);
|
||||
EditorGUILayout.PropertyField(_propertyRotationUseUnscaledTime, ContentRotationUseUnscaledTime);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else if (_propertyRotationMode.enumValueIndex == (int)UxrAnimationMode.Interpolate)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_propertyRotationSpace, ContentRotationSpace);
|
||||
EditorGUILayout.PropertyField(_propertyEulerStart, ContentEulerStart);
|
||||
EditorGUILayout.PropertyField(_propertyEulerEnd, ContentEulerEnd);
|
||||
EditorGUILayout.PropertyField(_propertyRotationInterpolationSettings, ContentRotationInterpolationSettings);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else if (_propertyRotationMode.enumValueIndex == (int)UxrAnimationMode.Noise)
|
||||
{
|
||||
EditorGUILayout.LabelField("Unsupported for now");
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
if (animatedTransform.HasScalingFinished == false)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyScalingMode, ContentScalingMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField("Scaling curve finished");
|
||||
}
|
||||
|
||||
if (_propertyScalingMode.enumValueIndex == (int)UxrAnimationMode.Speed)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_propertyScalingSpeed, ContentScalingSpeed);
|
||||
EditorGUILayout.PropertyField(_propertyScalingUseUnscaledTime, ContentScalingUseUnscaledTime);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else if (_propertyScalingMode.enumValueIndex == (int)UxrAnimationMode.Interpolate)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_propertyScalingStart, ContentScalingStart);
|
||||
EditorGUILayout.PropertyField(_propertyScalingEnd, ContentScalingEnd);
|
||||
EditorGUILayout.PropertyField(_propertyScalingInterpolationSettings, ContentScalingInterpolationSettings);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
else if (_propertyScalingMode.enumValueIndex == (int)UxrAnimationMode.Noise)
|
||||
{
|
||||
EditorGUILayout.LabelField("Unsupported for now");
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentTranslationMode { get; } = new GUIContent("Translation Mode", "Selects the translation mode to use");
|
||||
private GUIContent ContentTranslationSpace { get; } = new GUIContent("Translation Space", "Selects the space in which the translation will be performed");
|
||||
private GUIContent ContentTranslationSpeed { get; } = new GUIContent("Translation Speed", "The number of units per second to move");
|
||||
private GUIContent ContentTranslationStart { get; } = new GUIContent("Start Position", "The start position. In a looped animation, the start position of each loop");
|
||||
private GUIContent ContentTranslationEnd { get; } = new GUIContent("End Position", "The end position. In a looped animation, the end position of each loop");
|
||||
private GUIContent ContentTranslationUseUnscaledTime { get; } = new GUIContent("Use Unscaled Time", "Whether to use unscaled time, which is the timer without considering time scaling for effects such as bullet-time");
|
||||
private GUIContent ContentTranslationInterpolationSetting { get; } = new GUIContent("Interpolation Settings", "The translation interpolation settings");
|
||||
private GUIContent ContentRotationMode { get; } = new GUIContent("Rotation Mode", "Selects the rotation mode to use");
|
||||
private GUIContent ContentRotationSpace { get; } = new GUIContent("Rotation Space", "Selects the space in which the rotation will be performed");
|
||||
private GUIContent ContentEulerSpeed { get; } = new GUIContent("Angular Speed", "The number of degrees per second to rotate");
|
||||
private GUIContent ContentEulerStart { get; } = new GUIContent("Start Angles", "The start Euler angles. In a looped animation, the start Euler angles of each loop");
|
||||
private GUIContent ContentEulerEnd { get; } = new GUIContent("End Angles", "The end Euler angles. In a looped animation, the end Euler angles of each loop");
|
||||
private GUIContent ContentRotationUseUnscaledTime { get; } = new GUIContent("Use Unscaled Time", "Whether to use unscaled time, which is the timer without considering time scaling for effects such as bullet-time");
|
||||
private GUIContent ContentRotationInterpolationSettings { get; } = new GUIContent("Interpolation Settings", "The rotation interpolation settings");
|
||||
private GUIContent ContentScalingMode { get; } = new GUIContent("Scaling Mode", "Selects the scaling mode to use");
|
||||
private GUIContent ContentScalingSpeed { get; } = new GUIContent("Scaling Speed", "The number of units per second to scale");
|
||||
private GUIContent ContentScalingStart { get; } = new GUIContent("Start Scale", "The start scale. In a looped animation, the start scale of each loop");
|
||||
private GUIContent ContentScalingEnd { get; } = new GUIContent("End Scale", "The end scale. In a looped animation, the end scale of each loop");
|
||||
private GUIContent ContentScalingUseUnscaledTime { get; } = new GUIContent("Use Unscaled Time", "Whether to use unscaled time, which is the timer without considering time scaling for effects such as bullet-time");
|
||||
private GUIContent ContentScalingInterpolationSettings { get; } = new GUIContent("Interpolation Settings", "The scale interpolation settings");
|
||||
|
||||
private SerializedProperty _propertyTranslationMode;
|
||||
private SerializedProperty _propertyTranslationSpace;
|
||||
private SerializedProperty _propertyTranslationSpeed;
|
||||
private SerializedProperty _propertyTranslationStart;
|
||||
private SerializedProperty _propertyTranslationEnd;
|
||||
private SerializedProperty _propertyTranslationUseUnscaledTime;
|
||||
private SerializedProperty _propertyTranslationInterpolationSetting;
|
||||
private SerializedProperty _propertyRotationMode;
|
||||
private SerializedProperty _propertyRotationSpace;
|
||||
private SerializedProperty _propertyEulerSpeed;
|
||||
private SerializedProperty _propertyEulerStart;
|
||||
private SerializedProperty _propertyEulerEnd;
|
||||
private SerializedProperty _propertyRotationUseUnscaledTime;
|
||||
private SerializedProperty _propertyRotationInterpolationSettings;
|
||||
private SerializedProperty _propertyScalingMode;
|
||||
private SerializedProperty _propertyScalingSpeed;
|
||||
private SerializedProperty _propertyScalingStart;
|
||||
private SerializedProperty _propertyScalingEnd;
|
||||
private SerializedProperty _propertyScalingUseUnscaledTime;
|
||||
private SerializedProperty _propertyScalingInterpolationSettings;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d4025aaca37b8142ad37f1a20f663a4
|
||||
timeCreated: 1511875957
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrLookAtEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Animation.Transforms;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Animation.Transforms
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrLookAt" />.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrLookAt))]
|
||||
public class UxrLookAtEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Caches serialized properties.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propertyMode = serializedObject.FindProperty("_mode");
|
||||
_propertyTarget = serializedObject.FindProperty("_target");
|
||||
_propertyLookAxis = serializedObject.FindProperty("_lookAxis");
|
||||
_propertyUpAxis = serializedObject.FindProperty("_upAxis");
|
||||
_propertyMatchDirection = serializedObject.FindProperty("_matchDirection");
|
||||
_propertyAllowRotateAroundUp = serializedObject.FindProperty("_allowRotateAroundUp");
|
||||
_propertyAllowRotateAroundRight = serializedObject.FindProperty("_allowRotateAroundRight");
|
||||
_propertyInvertedLookAxis = serializedObject.FindProperty("_invertedLookAxis");
|
||||
_propertyOnlyOnce = serializedObject.FindProperty("_onlyOnce");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the inspector and handles input.
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyMode, ContentMode);
|
||||
|
||||
if (_propertyMode.enumValueIndex == (int)UxrLookAtMode.Target || _propertyMode.enumValueIndex == (int)UxrLookAtMode.MatchTargetDirection)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyTarget, ContentTarget);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyLookAxis, ContentLookAxis);
|
||||
EditorGUILayout.PropertyField(_propertyUpAxis, ContentUpAxis);
|
||||
|
||||
if (_propertyMode.enumValueIndex == (int)UxrLookAtMode.MatchWorldDirection || _propertyMode.enumValueIndex == (int)UxrLookAtMode.MatchTargetDirection)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyMatchDirection, ContentMatchDirection);
|
||||
}
|
||||
|
||||
if (_propertyMode.enumValueIndex == (int)UxrLookAtMode.Target)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyAllowRotateAroundUp, ContentAllowRotateAroundUp);
|
||||
EditorGUILayout.PropertyField(_propertyAllowRotateAroundRight, ContentAllowRotateAroundRight);
|
||||
EditorGUILayout.PropertyField(_propertyInvertedLookAxis, ContentInvertedLookAxis);
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyOnlyOnce, ContentOnlyOnce);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentMode { get; } = new GUIContent("Look-at Mode", "Selects which look-at mode to use");
|
||||
private GUIContent ContentTarget { get; } = new GUIContent("Target", "Selects the object the object will look at");
|
||||
private GUIContent ContentLookAxis { get; } = new GUIContent("Look Axis", "Selects the object axis that will point towards the target");
|
||||
private GUIContent ContentUpAxis { get; } = new GUIContent("Up Axis", "Selects the object axis that points \"up\"");
|
||||
private GUIContent ContentMatchDirection { get; } = new GUIContent("Direction To Match", "Selects the direction to match \"up\"");
|
||||
private GUIContent ContentAllowRotateAroundUp { get; } = new GUIContent("Allow Rotation Around \"up\"", "Whether the look-at can rotate the object around the up axis");
|
||||
private GUIContent ContentAllowRotateAroundRight { get; } = new GUIContent("Allow Rotation Around \"right\"", "Whether the look-at can rotate the object around the right axis");
|
||||
private GUIContent ContentInvertedLookAxis { get; } = new GUIContent("Inverted Look", "Whether to invert the look-at");
|
||||
private GUIContent ContentOnlyOnce { get; } = new GUIContent("Only Once", "Whether to execute the look-at only the first frame");
|
||||
|
||||
private SerializedProperty _propertyMode;
|
||||
private SerializedProperty _propertyTarget;
|
||||
private SerializedProperty _propertyLookAxis;
|
||||
private SerializedProperty _propertyUpAxis;
|
||||
private SerializedProperty _propertyMatchDirection;
|
||||
private SerializedProperty _propertyAllowRotateAroundUp;
|
||||
private SerializedProperty _propertyAllowRotateAroundRight;
|
||||
private SerializedProperty _propertyInvertedLookAxis;
|
||||
private SerializedProperty _propertyOnlyOnce;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4316bec080e7be4d9111763803595f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Attributes.meta
Normal file
8
Assets/UltimateXR/Editor/Attributes.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ec2c8b53527de449b1ba546bfcdd98f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,48 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="HideInNormalInspectorPropertyDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Attributes;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer for inspector fields that use the HideInNormalInspector attribute.
|
||||
/// From https://answers.unity.com/questions/157775/hide-from-inspector-interface-but-not-from-the-deb.html
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(HideInNormalInspectorAttribute))]
|
||||
public class HideInNormalInspectorPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Called when the GUI wants to know the height needed to draw the property.
|
||||
/// </summary>
|
||||
/// <param name="property">SerializedProperty that needs to be drawn</param>
|
||||
/// <param name="label">Label used</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// Even if GetPropertyHeight() returns 0, sometimes it displays a single row of pixels.
|
||||
// We avoid this by showing an empty label.
|
||||
EditorGUI.BeginProperty(position, new GUIContent(""), property);
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47f3a00b24bb6ee4fb7afd366cc4df5a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="ReadOnlyPropertyDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Attributes;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer for inspector fields that use the ReadOnly attribute.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(ReadOnlyAttribute))]
|
||||
public class ReadOnlyPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <summary>
|
||||
/// Called when the GUI wants to know the height needed to draw the property.
|
||||
/// </summary>
|
||||
/// <param name="property">SerializedProperty that needs to be drawn</param>
|
||||
/// <param name="label">Label used</param>
|
||||
/// <returns>Height in pixels</returns>
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var roAttr = (ReadOnlyAttribute)attribute;
|
||||
|
||||
return Application.isPlaying ? roAttr.HideInPlayMode ? 0 : EditorGUIUtility.singleLineHeight :
|
||||
roAttr.HideInEditMode ? 0 : EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Called when the GUI needs to draw the property.
|
||||
/// </summary>
|
||||
/// <param name="position">GUI position</param>
|
||||
/// <param name="property">Property to draw</param>
|
||||
/// <param name="label">Property label</param>
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var roAttr = (ReadOnlyAttribute)attribute;
|
||||
|
||||
if (roAttr.HideInEditMode && !Application.isPlaying)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GUI.enabled = !Application.isPlaying && roAttr.OnlyWhilePlaying;
|
||||
EditorGUI.PropertyField(position, property, label);
|
||||
GUI.enabled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4555f79d196764240a3a598274214168
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Audio.meta
Normal file
8
Assets/UltimateXR/Editor/Audio.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 346ce0ff1e271ae4c97a129c543e8361
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
119
Assets/UltimateXR/Editor/Audio/UxrAudioManipulationEditor.cs
Normal file
119
Assets/UltimateXR/Editor/Audio/UxrAudioManipulationEditor.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAudioManipulationEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Audio;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
#pragma warning disable 0414
|
||||
|
||||
namespace UltimateXR.Editor.Audio
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor used by the <see cref="UxrAudioManipulation" /> component.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrAudioManipulation))]
|
||||
[CanEditMultipleObjects]
|
||||
public class UxrAudioManipulationEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Creates references to the serialized properties
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propContinuousManipulationAudio = serializedObject.FindProperty("_continuousManipulationAudio");
|
||||
_propAudioLoopClip = serializedObject.FindProperty("_audioLoopClip");
|
||||
_propMinVolume = serializedObject.FindProperty("_minVolume");
|
||||
_propMaxVolume = serializedObject.FindProperty("_maxVolume");
|
||||
_propMinFrequency = serializedObject.FindProperty("_minFrequency");
|
||||
_propMaxFrequency = serializedObject.FindProperty("_maxFrequency");
|
||||
_propMinSpeed = serializedObject.FindProperty("_minSpeed");
|
||||
_propMaxSpeed = serializedObject.FindProperty("_maxSpeed");
|
||||
_propMinAngularSpeed = serializedObject.FindProperty("_minAngularSpeed");
|
||||
_propMaxAngularSpeed = serializedObject.FindProperty("_maxAngularSpeed");
|
||||
_propUseExternalRigidbody = serializedObject.FindProperty("_useExternalRigidbody");
|
||||
_propExternalRigidbody = serializedObject.FindProperty("_externalRigidbody");
|
||||
|
||||
_propAudioOnGrab = serializedObject.FindProperty("_audioOnGrab");
|
||||
_propAudioOnPlace = serializedObject.FindProperty("_audioOnPlace");
|
||||
_propAudioOnRelease = serializedObject.FindProperty("_audioOnRelease");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the custom inspector
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(_propContinuousManipulationAudio, ContentContinuousManipulationAudio);
|
||||
|
||||
if (_propContinuousManipulationAudio.boolValue)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propAudioLoopClip, ContentAudioLoopClip);
|
||||
EditorGUILayout.Slider(_propMinVolume, 0.0f, 1.0f, ContentMinVolume);
|
||||
EditorGUILayout.Slider(_propMaxVolume, 0.0f, 1.0f, ContentMaxVolume);
|
||||
EditorGUILayout.PropertyField(_propMinFrequency, ContentMinFrequency);
|
||||
EditorGUILayout.PropertyField(_propMaxFrequency, ContentMaxFrequency);
|
||||
EditorGUILayout.PropertyField(_propMinSpeed, ContentMinSpeed);
|
||||
EditorGUILayout.PropertyField(_propMaxSpeed, ContentMaxSpeed);
|
||||
EditorGUILayout.PropertyField(_propMinAngularSpeed, ContentMinAngularSpeed);
|
||||
EditorGUILayout.PropertyField(_propMaxAngularSpeed, ContentMaxAngularSpeed);
|
||||
EditorGUILayout.PropertyField(_propUseExternalRigidbody, ContentUseExternalRigidbody);
|
||||
|
||||
if (_propUseExternalRigidbody.boolValue)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propExternalRigidbody, ContentExternalRigidbody);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_propAudioOnGrab, true);
|
||||
EditorGUILayout.PropertyField(_propAudioOnPlace, true);
|
||||
EditorGUILayout.PropertyField(_propAudioOnRelease, true);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentContinuousManipulationAudio { get; } = new GUIContent("Continuous Manipulation", "");
|
||||
private GUIContent ContentAudioLoopClip { get; } = new GUIContent("Audio Loop Clip", "");
|
||||
private GUIContent ContentMinVolume { get; } = new GUIContent("Min Volume", "");
|
||||
private GUIContent ContentMaxVolume { get; } = new GUIContent("Max Volume", "");
|
||||
private GUIContent ContentMinFrequency { get; } = new GUIContent("Min Frequency", "");
|
||||
private GUIContent ContentMaxFrequency { get; } = new GUIContent("Max Frequency", "");
|
||||
private GUIContent ContentMinSpeed { get; } = new GUIContent("Min Speed", "");
|
||||
private GUIContent ContentMaxSpeed { get; } = new GUIContent("Max Speed", "");
|
||||
private GUIContent ContentMinAngularSpeed { get; } = new GUIContent("Min Angular Speed", "");
|
||||
private GUIContent ContentMaxAngularSpeed { get; } = new GUIContent("Max Angular Speed", "");
|
||||
private GUIContent ContentUseExternalRigidbody { get; } = new GUIContent("Use External Rigidbody", "");
|
||||
private GUIContent ContentExternalRigidbody { get; } = new GUIContent("External Rigidbody", "");
|
||||
|
||||
private SerializedProperty _propContinuousManipulationAudio;
|
||||
private SerializedProperty _propAudioLoopClip;
|
||||
private SerializedProperty _propMinVolume;
|
||||
private SerializedProperty _propMaxVolume;
|
||||
private SerializedProperty _propMinFrequency;
|
||||
private SerializedProperty _propMaxFrequency;
|
||||
private SerializedProperty _propMinSpeed;
|
||||
private SerializedProperty _propMaxSpeed;
|
||||
private SerializedProperty _propMinAngularSpeed;
|
||||
private SerializedProperty _propMaxAngularSpeed;
|
||||
private SerializedProperty _propUseExternalRigidbody;
|
||||
private SerializedProperty _propExternalRigidbody;
|
||||
|
||||
private SerializedProperty _propAudioOnGrab;
|
||||
private SerializedProperty _propAudioOnPlace;
|
||||
private SerializedProperty _propAudioOnRelease;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 0414
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8619ab470731d449b2c32c6e42b4d21
|
||||
timeCreated: 1516001748
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Avatar.meta
Normal file
8
Assets/UltimateXR/Editor/Avatar.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5895a050ed7564d4cad6d70d05821699
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
82
Assets/UltimateXR/Editor/Avatar/AddAvatarToSceneMenu.cs
Normal file
82
Assets/UltimateXR/Editor/Avatar/AddAvatarToSceneMenu.cs
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/UltimateXR/Editor/Avatar/AddAvatarToSceneMenu.cs.meta
Normal file
11
Assets/UltimateXR/Editor/Avatar/AddAvatarToSceneMenu.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e087a265e2b755f4ba843e1c6295c466
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
172
Assets/UltimateXR/Editor/Avatar/BigHandGizmoLeft.prefab
Normal file
172
Assets/UltimateXR/Editor/Avatar/BigHandGizmoLeft.prefab
Normal 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}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93019d606e943b7429d29c694143ad6e
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
184
Assets/UltimateXR/Editor/Avatar/BigHandGizmoRight.prefab
Normal file
184
Assets/UltimateXR/Editor/Avatar/BigHandGizmoRight.prefab
Normal 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}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d45d3edc285cfd64a86fddd771e13f47
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Avatar/Controllers.meta
Normal file
8
Assets/UltimateXR/Editor/Avatar/Controllers.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 470a2f8a41647a14a98eec5954b6b218
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b019ea387b41a1438953b9ff201213b
|
||||
timeCreated: 1501659089
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
123
Assets/UltimateXR/Editor/Avatar/GizmoMat.mat
Normal file
123
Assets/UltimateXR/Editor/Avatar/GizmoMat.mat
Normal 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: []
|
||||
8
Assets/UltimateXR/Editor/Avatar/GizmoMat.mat.meta
Normal file
8
Assets/UltimateXR/Editor/Avatar/GizmoMat.mat.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efed6a9e4d429f64fb8335d6c1b71f6b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
188
Assets/UltimateXR/Editor/Avatar/SmallHandGizmoLeft.prefab
Normal file
188
Assets/UltimateXR/Editor/Avatar/SmallHandGizmoLeft.prefab
Normal 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}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 672e7f52fe868134a80bf396141fe261
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
188
Assets/UltimateXR/Editor/Avatar/SmallHandGizmoRight.prefab
Normal file
188
Assets/UltimateXR/Editor/Avatar/SmallHandGizmoRight.prefab
Normal 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}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a1c1014903295a408b755f1fed2863e
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
855
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditor.cs
Normal file
855
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditor.cs
Normal 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
|
||||
}
|
||||
}
|
||||
12
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditor.cs.meta
Normal file
12
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditor.cs.meta
Normal 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:
|
||||
108
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditorExt.cs
Normal file
108
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditorExt.cs
Normal 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
|
||||
}
|
||||
}
|
||||
11
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditorExt.cs.meta
Normal file
11
Assets/UltimateXR/Editor/Avatar/UxrAvatarEditorExt.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e99978505dd0ec4faf3fb7e0fb22a76
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffadeb7d00884d79bc722da4e20739aa
|
||||
timeCreated: 1653306477
|
||||
530
Assets/UltimateXR/Editor/Avatar/UxrHandIntegrationEditor.cs
Normal file
530
Assets/UltimateXR/Editor/Avatar/UxrHandIntegrationEditor.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39a38dfa3b85bb9429b657870ef60ce6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Core.meta
Normal file
8
Assets/UltimateXR/Editor/Core.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67f33cd3a4d69a24c82bb867dddb6c02
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Core/Components.meta
Normal file
8
Assets/UltimateXR/Editor/Core/Components.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc45e86f1c364654584db717b44e2f23
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,88 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrSyncObjectEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Linq;
|
||||
using UltimateXR.Core.Components;
|
||||
using UltimateXR.Core.StateSave;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Core.Components
|
||||
{
|
||||
[CustomEditor(typeof(UxrSyncObject))]
|
||||
[CanEditMultipleObjects]
|
||||
public class UxrSyncObjectEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Creates references to the serialized properties.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propertySyncTransform = serializedObject.FindProperty(PropertyNameSyncTransform);
|
||||
_propertyTransformSpace = serializedObject.FindProperty(PropertyNameTransformSpace);
|
||||
_propertySyncActiveAndEnabled = serializedObject.FindProperty(PropertyNameSyncActiveAndEnabled);
|
||||
_propertySyncWhileDisabled = serializedObject.FindProperty(PropertyNameSyncWhileDisabled);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(_propertySyncTransform, ContentSyncTransform);
|
||||
|
||||
if (_propertySyncTransform.boolValue)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyTransformSpace, ContentTransformSpace);
|
||||
}
|
||||
|
||||
foreach (Object selectedObject in targets)
|
||||
{
|
||||
UxrSyncObject syncObject = selectedObject as UxrSyncObject;
|
||||
IUxrStateSave stateSaveTransform = syncObject.GetComponents<IUxrStateSave>().FirstOrDefault(c => c != syncObject && c.RequiresTransformSerialization(UxrStateSaveLevel.ChangesSinceBeginning));
|
||||
|
||||
if (syncObject.SyncTransform && stateSaveTransform != null)
|
||||
{
|
||||
if (targets.Length > 1)
|
||||
{
|
||||
EditorGUILayout.HelpBox($"The transform in {syncObject.name} is already synced by a {stateSaveTransform.Component.GetType().Name} component on the same GameObject. Consider disabling transform syncing.", MessageType.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox($"The transform is already synced by a {stateSaveTransform.Component.GetType().Name} component on the same GameObject. Consider disabling transform syncing.", MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(_propertySyncActiveAndEnabled, ContentSyncActiveAndEnabled);
|
||||
EditorGUILayout.PropertyField(_propertySyncWhileDisabled, ContentSyncWhileDisabled);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private static GUIContent ContentSyncTransform { get; } = new GUIContent("Sync Transform", "Synchronizes the transform in multiplayer and save stats.");
|
||||
private static GUIContent ContentTransformSpace { get; } = new GUIContent("Space", "Space that the transform is saved in.");
|
||||
private static GUIContent ContentSyncActiveAndEnabled { get; } = new GUIContent("Sync Active/Enabled", "Synchronizes the GameObject's active state and the component's enabled state.");
|
||||
private static GUIContent ContentSyncWhileDisabled { get; } = new GUIContent("Sync While Disabled", "Synchronizes even while the Component/GameObject is disabled.");
|
||||
|
||||
private const string PropertyNameSyncTransform = "_syncTransform";
|
||||
private const string PropertyNameTransformSpace = "_transformSpace";
|
||||
private const string PropertyNameSyncActiveAndEnabled = "_syncActiveAndEnabled";
|
||||
private const string PropertyNameSyncWhileDisabled = "_syncWhileDisabled";
|
||||
|
||||
private SerializedProperty _propertySyncTransform;
|
||||
private SerializedProperty _propertyTransformSpace;
|
||||
private SerializedProperty _propertySyncActiveAndEnabled;
|
||||
private SerializedProperty _propertySyncWhileDisabled;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76bd9d6956a81f7479e374e3fd31d679
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Core/Instantiation.meta
Normal file
8
Assets/UltimateXR/Editor/Core/Instantiation.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ccb906d54174c324090202dc8456da80
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,209 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrInstanceManagerEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Components;
|
||||
using UltimateXR.Core.Instantiation;
|
||||
using UltimateXR.Core.Settings;
|
||||
using UltimateXR.Core.Unique;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace UltimateXR.Editor.Core.Instantiation
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrInstanceManager" />.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrInstanceManager))]
|
||||
public class UxrInstanceManagerEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the prefab list contains only elements with a IUxrUnique component in the root. If not, it will return
|
||||
/// false, keep the serialized property elements to null and return a message to show.
|
||||
/// </summary>
|
||||
/// <param name="propertyPrefabList">SerializedProperty with a list of prefabs (GameObject)</param>
|
||||
/// <param name="message">If the method return false, the message will contain a string to show on screen</param>
|
||||
/// <returns>Whether the prefab list was valid (true) or contained one or more invalid elements (false)</returns>
|
||||
public static bool ValidatePrefabsWithUniqueId(SerializedProperty propertyPrefabList, out string message)
|
||||
{
|
||||
List<string> invalidPrefabNames = null;
|
||||
message = null;
|
||||
|
||||
for (int i = 0; i < propertyPrefabList.arraySize; ++i)
|
||||
{
|
||||
GameObject prefab = propertyPrefabList.GetArrayElementAtIndex(i).objectReferenceValue as GameObject;
|
||||
|
||||
if (prefab != null && prefab.GetComponent<IUxrUniqueId>() == null)
|
||||
{
|
||||
if (invalidPrefabNames == null)
|
||||
{
|
||||
invalidPrefabNames = new List<string>();
|
||||
}
|
||||
|
||||
invalidPrefabNames.Add(prefab.name);
|
||||
propertyPrefabList.GetArrayElementAtIndex(i).objectReferenceValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (invalidPrefabNames != null)
|
||||
{
|
||||
int maxEntries = 10;
|
||||
|
||||
if (invalidPrefabNames.Count <= maxEntries)
|
||||
{
|
||||
message = $"One or more prefabs don't have a component to track it. Consider adding a {nameof(UxrSyncObject)} to the root of the following prefab(s):\n\n{string.Join("\n", invalidPrefabNames)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
message = $"The list of prefabs contains many elements without a component to track it. Consider adding a {nameof(UxrSyncObject)} on the root to be able to instantiate the prefab using the {nameof(UxrInstanceManager)}.\nInvalid prefabs have been removed from the list.";
|
||||
}
|
||||
}
|
||||
|
||||
return invalidPrefabNames == null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Creates references to the serialized properties.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propertyRegisterAutomatically = serializedObject.FindProperty(PropertyNameRegisterAutomatically);
|
||||
_propertyIncludeFrameworkPrefabs = serializedObject.FindProperty(PropertyNameIncludeFrameworkPrefabs);
|
||||
_propertyAutomaticPrefabs = serializedObject.FindProperty(PropertyNameAutomaticPrefabs);
|
||||
_propertyUserDefinedPrefabs = serializedObject.FindProperty(PropertyNameUserDefinedPrefabs);
|
||||
|
||||
if (_propertyAutomaticPrefabs.arraySize == 0 && _propertyRegisterAutomatically.boolValue)
|
||||
{
|
||||
FindPrefabsAutomatically();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
_propertyAutomaticPrefabs.isExpanded = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.HelpBox($"Use {nameof(UxrInstanceManager)} to instantiate objects at runtime that need to be synchronized on all devices in multiplayer, save-files or replays.\nTo be able to track instantiation, prefabs need at least one component with the {nameof(IUxrUniqueId)} interface on the root, such as any component derived from {nameof(UxrComponent)}. A {nameof(UxrSyncObject)} component can be used when there is no other present.",
|
||||
MessageType.Info);
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyRegisterAutomatically, ContentRegisterAutomatically);
|
||||
|
||||
if (_propertyRegisterAutomatically.boolValue)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyIncludeFrameworkPrefabs, ContentIncludeFrameworkPrefabs);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.Space(EditorGUIUtility.labelWidth);
|
||||
|
||||
if (GUILayout.Button(ContentFindPrefabs, GUILayout.ExpandWidth(true)))
|
||||
{
|
||||
FindPrefabsAutomatically();
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyAutomaticPrefabs, ContentAutomaticPrefabs);
|
||||
|
||||
if (!ValidatePrefabsWithUniqueId(_propertyAutomaticPrefabs, out string message))
|
||||
{
|
||||
EditorUtility.DisplayDialog(UxrConstants.Editor.Error, message, UxrConstants.Editor.Ok);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox($"Use prefab lists to keep big projects well organized and to avoid long generation times of the automatic list. To create a new prefab list use the Create->UltimateXR menu in the Project Window.", MessageType.Info);
|
||||
EditorGUILayout.PropertyField(_propertyUserDefinedPrefabs, ContentUserDefinedPrefabs);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Tries to populate the prefab list with all instantiable prefabs in the project.
|
||||
/// </summary>
|
||||
private void FindPrefabsAutomatically()
|
||||
{
|
||||
List<GameObject> prefabs = new List<GameObject>();
|
||||
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
|
||||
EditorUtility.DisplayCancelableProgressBar("Finding Prefabs", "Building asset list", 0.0f);
|
||||
|
||||
List<string> paths = AssetDatabase.GetAllAssetPaths().Where(p => p.EndsWith(".prefab")).OrderBy(p => p).ToList();
|
||||
|
||||
for (var i = 0; i < paths.Count; i++)
|
||||
{
|
||||
string path = paths[i];
|
||||
|
||||
if (!_propertyIncludeFrameworkPrefabs.boolValue && UxrEditorUtils.PathIsInUltimateXR(path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GameObject prefab = AssetDatabase.LoadMainAssetAtPath(path) as GameObject;
|
||||
|
||||
if (prefab != null)
|
||||
{
|
||||
EditorUtility.DisplayCancelableProgressBar("Finding Prefabs", prefab.name, paths.Count == 1 ? 1.0f : i / (paths.Count - 1));
|
||||
|
||||
IUxrUniqueId component = prefab.GetComponent<IUxrUniqueId>();
|
||||
|
||||
if (component != null)
|
||||
{
|
||||
prefabs.Add(prefab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UxrEditorUtils.AssignSerializedPropertyArray(_propertyAutomaticPrefabs, prefabs);
|
||||
|
||||
EditorUtility.ClearProgressBar();
|
||||
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Relevant)
|
||||
{
|
||||
Debug.Log($"{UxrConstants.CoreModule} Found {prefabs.Count} instantiable prefabs with Unique ID in {sw.ElapsedMilliseconds}ms.");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private static GUIContent ContentRegisterAutomatically { get; } = new GUIContent("Create List Automatically", "Create a list automatically of all instantiable prefabs in the project. Use manual lists in big projects to avoid long refresh times.");
|
||||
private static GUIContent ContentIncludeFrameworkPrefabs { get; } = new GUIContent($"Include {nameof(UltimateXR)} Prefabs", "Include all instantiable prefabs from the framework in the list too.");
|
||||
private static GUIContent ContentFindPrefabs { get; } = new GUIContent("Regenerate List", "Finds all instantiable prefabs in the project.");
|
||||
private static GUIContent ContentAutomaticPrefabs { get; } = new GUIContent("Registered Prefabs", "List of prefabs");
|
||||
private static GUIContent ContentUserDefinedPrefabs { get; } = new GUIContent("User Defined Prefab Lists", "List of prefabs");
|
||||
|
||||
private const string PropertyNameRegisterAutomatically = "_registerAutomatically";
|
||||
private const string PropertyNameIncludeFrameworkPrefabs = "_includeFrameworkPrefabs";
|
||||
private const string PropertyNameAutomaticPrefabs = "_automaticPrefabs";
|
||||
private const string PropertyNameUserDefinedPrefabs = "_userDefinedPrefabs";
|
||||
|
||||
private SerializedProperty _propertyRegisterAutomatically;
|
||||
private SerializedProperty _propertyIncludeFrameworkPrefabs;
|
||||
private SerializedProperty _propertyAutomaticPrefabs;
|
||||
private SerializedProperty _propertyUserDefinedPrefabs;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4c1411e2e9960b4294227f67525ca07
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrPrefabListEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Instantiation;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Core.Instantiation
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrPrefabList" />.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrPrefabList))]
|
||||
public class UxrGlobalSettingsEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Creates references to the serialized properties.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propPrefabList = serializedObject.FindProperty(PropertyPrefabList);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(_propPrefabList, ContentPrefabList);
|
||||
|
||||
if (!UxrInstanceManagerEditor.ValidatePrefabsWithUniqueId(_propPrefabList, out string message))
|
||||
{
|
||||
EditorUtility.DisplayDialog(UxrConstants.Editor.Error, message, UxrConstants.Editor.Ok);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentPrefabList { get; } = new GUIContent("Prefab List", "List of prefabs");
|
||||
|
||||
private const string PropertyPrefabList = "_prefabList";
|
||||
|
||||
private SerializedProperty _propPrefabList;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efee02476eee24a45a611814d56c4410
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Core/Math.meta
Normal file
8
Assets/UltimateXR/Editor/Core/Math.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 57a69f04a7c99c6438e8baffecb9481e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
86
Assets/UltimateXR/Editor/Core/Math/UxrAxisPropertyDrawer.cs
Normal file
86
Assets/UltimateXR/Editor/Core/Math/UxrAxisPropertyDrawer.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAxisPropertyDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core.Math;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Core.Math
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom property drawer for <see cref="UxrAxis" />.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrAxis))]
|
||||
public class UxrAxisPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
public const string PropertyAxis = "_axis";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Draws an axis popup selector using <see cref="EditorGUILayout" />.
|
||||
/// </summary>
|
||||
/// <param name="content">Label and tooltip</param>
|
||||
/// <param name="axis">Axis value</param>
|
||||
/// <returns>New axis value</returns>
|
||||
public static UxrAxis EditorGuiLayout(GUIContent content, UxrAxis axis)
|
||||
{
|
||||
return EditorGUILayout.Popup(content, (int)axis, AxesAsStrings);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
SerializedProperty propertyAxis = property.FindPropertyRelative(PropertyAxis);
|
||||
|
||||
if (property.serializedObject.isEditingMultipleObjects)
|
||||
{
|
||||
// Multi-selection doesn't work correctly with PropertyDrawers when not using PropertyFields. Disable UI.
|
||||
// https://answers.unity.com/questions/1214493/custompropertydrawer-cant-restrict-multi-editing.html
|
||||
bool isGuiEnabled = GUI.enabled;
|
||||
GUI.enabled = false;
|
||||
EditorGUI.PropertyField(UxrEditorUtils.GetRect(position, 0), propertyAxis, label);
|
||||
GUI.enabled = isGuiEnabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyAxis.intValue = EditorGUI.Popup(UxrEditorUtils.GetRect(position, 0), label, propertyAxis.intValue, UxrEditorUtils.ToGUIContentArray(AxesAsStrings));
|
||||
}
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets the possible axis values as strings.
|
||||
/// </summary>
|
||||
private static string[] AxesAsStrings { get; } = { "X", "Y", "Z" };
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab8dfed24d683ba44b4415fef957f698
|
||||
timeCreated: 1538564324
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Core/Settings.meta
Normal file
8
Assets/UltimateXR/Editor/Core/Settings.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5788e34be9db9e14c9ea46ab55af0d4f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,140 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrGlobalSettingsEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Settings;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Core.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom inspector for <see cref="UxrGlobalSettings" />.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrGlobalSettings))]
|
||||
public class UxrGlobalSettingsEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Creates references to the serialized properties.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_propLogLevelAnimation = serializedObject.FindProperty(PropertyLogLevelAnimation);
|
||||
_propLogLevelAvatar = serializedObject.FindProperty(PropertyLogLevelAvatar);
|
||||
_propLogLevelCore = serializedObject.FindProperty(PropertyLogLevelCore);
|
||||
_propLogLevelDevices = serializedObject.FindProperty(PropertyLogLevelDevices);
|
||||
_propLogLevelLocomotion = serializedObject.FindProperty(PropertyLogLevelLocomotion);
|
||||
_propLogLevelManipulation = serializedObject.FindProperty(PropertyLogLevelManipulation);
|
||||
_propLogLevelNetworking = serializedObject.FindProperty(PropertyLogLevelNetworking);
|
||||
_propLogLevelRendering = serializedObject.FindProperty(PropertyLogLevelRendering);
|
||||
_propLogLevelUI = serializedObject.FindProperty(PropertyLogLevelUI);
|
||||
_propLogLevelWeapons = serializedObject.FindProperty(PropertyLogLevelWeapons);
|
||||
_propNetFormatInitialState = serializedObject.FindProperty(PropertyNetFormatInitialState);
|
||||
_propNetFormatStateSync = serializedObject.FindProperty(PropertyNetFormatStateSync);
|
||||
_propNetSyncGrabbablePhysics = serializedObject.FindProperty(PropertyNetSyncGrabbablePhysics);
|
||||
_propNetGrabbableSyncIntervalSeconds = serializedObject.FindProperty(PropertyNetGrabbableSyncIntervalSeconds);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.TextArea($"{UxrConstants.UltimateXR} version: {UxrConstants.Version}");
|
||||
|
||||
// Log level configuration
|
||||
|
||||
_showLogLevels = UxrEditorUtils.FoldoutStylish("Log Levels", _showLogLevels);
|
||||
|
||||
if (_showLogLevels)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propLogLevelAnimation, ContentLogLevelAnimation);
|
||||
EditorGUILayout.PropertyField(_propLogLevelAvatar, ContentLogLevelAvatar);
|
||||
EditorGUILayout.PropertyField(_propLogLevelCore, ContentLogLevelCore);
|
||||
EditorGUILayout.PropertyField(_propLogLevelDevices, ContentLogLevelDevices);
|
||||
EditorGUILayout.PropertyField(_propLogLevelLocomotion, ContentLogLevelLocomotion);
|
||||
EditorGUILayout.PropertyField(_propLogLevelManipulation, ContentLogLevelManipulation);
|
||||
EditorGUILayout.PropertyField(_propLogLevelNetworking, ContentLogLevelNetworking);
|
||||
EditorGUILayout.PropertyField(_propLogLevelRendering, ContentLogLevelRendering);
|
||||
EditorGUILayout.PropertyField(_propLogLevelUI, ContentLogLevelUI);
|
||||
EditorGUILayout.PropertyField(_propLogLevelWeapons, ContentLogLevelWeapons);
|
||||
}
|
||||
|
||||
// Networking config
|
||||
|
||||
_showNetworking = UxrEditorUtils.FoldoutStylish("Networking", _showNetworking);
|
||||
|
||||
if (_showNetworking)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propNetFormatInitialState, ContentNetFormatInitialState);
|
||||
EditorGUILayout.PropertyField(_propNetFormatStateSync, ContentNetFormatStateSync);
|
||||
EditorGUILayout.PropertyField(_propNetSyncGrabbablePhysics, ContentNetSyncGrabbablePhysics);
|
||||
|
||||
if (_propNetSyncGrabbablePhysics.boolValue)
|
||||
{
|
||||
EditorGUILayout.Slider(_propNetGrabbableSyncIntervalSeconds, 0.1f, 10.0f, ContentNetGrabbableSyncIntervalSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentLogLevelAnimation { get; } = new GUIContent("Animation", "Selects the console log level for animation events");
|
||||
private GUIContent ContentLogLevelAvatar { get; } = new GUIContent("Avatar", "Selects the console log level for avatar events");
|
||||
private GUIContent ContentLogLevelCore { get; } = new GUIContent("Core", "Selects the console log level for core events");
|
||||
private GUIContent ContentLogLevelDevices { get; } = new GUIContent("Devices", "Selects the console log level for device events");
|
||||
private GUIContent ContentLogLevelLocomotion { get; } = new GUIContent("Locomotion", "Selects the console log level for locomotion events");
|
||||
private GUIContent ContentLogLevelManipulation { get; } = new GUIContent("Manipulation", "Selects the console log level for manipulation events");
|
||||
private GUIContent ContentLogLevelNetworking { get; } = new GUIContent("Networking", "Selects the console log level for networking events");
|
||||
private GUIContent ContentLogLevelRendering { get; } = new GUIContent("Rendering", "Selects the console log level for rendering events");
|
||||
private GUIContent ContentLogLevelUI { get; } = new GUIContent("UI", "Selects the console log level for UI events");
|
||||
private GUIContent ContentLogLevelWeapons { get; } = new GUIContent("Weapons", "Selects the console log level for weapon events");
|
||||
private GUIContent ContentNetFormatInitialState { get; } = new GUIContent("Initial State Msg Format", "Selects the message format to use when the host sends the initial state of the session upon joining. Compression has a little CPU overhead but will use less bandwidth.");
|
||||
private GUIContent ContentNetFormatStateSync { get; } = new GUIContent("State Sync Msg Format", "Selects the message format to use when exchanging state synchronization updates. Compression has a little CPU overhead but will use less bandwidth.");
|
||||
private GUIContent ContentNetSyncGrabbablePhysics { get; } = new GUIContent("Sync Grabbable Physics", "Selects whether to sync grabbable objects with rigidbodies that have no NetworkTransform/NetworkRidibody set up. This keeps position/rotation and speeds manually in sync by sending periodic messages.");
|
||||
private GUIContent ContentNetGrabbableSyncIntervalSeconds { get; } = new GUIContent("Grabbable Sync Interval (Seconds)", "Selects the interval in seconds grabbable objects with rigidbodies are kept in sync when there are no NetworkTransform/NetworkRidibody set up. Lower values will send RPC messages more frequently but will increase bandwidth.");
|
||||
|
||||
private const string PropertyLogLevelAnimation = "_logLevelAnimation";
|
||||
private const string PropertyLogLevelAvatar = "_logLevelAvatar";
|
||||
private const string PropertyLogLevelCore = "_logLevelCore";
|
||||
private const string PropertyLogLevelDevices = "_logLevelDevices";
|
||||
private const string PropertyLogLevelLocomotion = "_logLevelLocomotion";
|
||||
private const string PropertyLogLevelManipulation = "_logLevelManipulation";
|
||||
private const string PropertyLogLevelNetworking = "_logLevelNetworking";
|
||||
private const string PropertyLogLevelRendering = "_logLevelRendering";
|
||||
private const string PropertyLogLevelUI = "_logLevelUI";
|
||||
private const string PropertyLogLevelWeapons = "_logLevelWeapons";
|
||||
private const string PropertyNetFormatInitialState = "_netFormatInitialState";
|
||||
private const string PropertyNetFormatStateSync = "_netFormatStateSync";
|
||||
private const string PropertyNetSyncGrabbablePhysics = "_syncGrabbablePhysics";
|
||||
private const string PropertyNetGrabbableSyncIntervalSeconds = "_grabbableSyncIntervalSeconds";
|
||||
|
||||
private SerializedProperty _propLogLevelAnimation;
|
||||
private SerializedProperty _propLogLevelAvatar;
|
||||
private SerializedProperty _propLogLevelCore;
|
||||
private SerializedProperty _propLogLevelDevices;
|
||||
private SerializedProperty _propLogLevelLocomotion;
|
||||
private SerializedProperty _propLogLevelManipulation;
|
||||
private SerializedProperty _propLogLevelNetworking;
|
||||
private SerializedProperty _propLogLevelRendering;
|
||||
private SerializedProperty _propLogLevelUI;
|
||||
private SerializedProperty _propLogLevelWeapons;
|
||||
private SerializedProperty _propNetFormatInitialState;
|
||||
private SerializedProperty _propNetFormatStateSync;
|
||||
private SerializedProperty _propNetSyncGrabbablePhysics;
|
||||
private SerializedProperty _propNetGrabbableSyncIntervalSeconds;
|
||||
|
||||
private bool _showLogLevels = true;
|
||||
private bool _showNetworking = true;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d96f219608a592843aa52a749f16f5a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,91 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrComponentIntegrityChecker.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Core.Unique;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace UltimateXR.Editor.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Class that hooks to Unity scene saving to detect inconsistencies in unique IDs of <see cref="IUxrUniqueId" />
|
||||
/// components.
|
||||
/// </summary>
|
||||
public static class UxrComponentIntegrityChecker
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Method called when Unity loads. It will hook to the scene saving event.
|
||||
/// </summary>
|
||||
[InitializeOnLoadMethod]
|
||||
public static void HookToSceneSave()
|
||||
{
|
||||
EditorSceneManager.sceneSaving -= EditorSceneManager_sceneSaving;
|
||||
EditorSceneManager.sceneSaving += EditorSceneManager_sceneSaving;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Called by Unity when the scene is saved.
|
||||
/// </summary>
|
||||
/// <param name="scene">Scene to be saved</param>
|
||||
/// <param name="path">Path to save to</param>
|
||||
private static void EditorSceneManager_sceneSaving(Scene scene, string path)
|
||||
{
|
||||
// Momentarily don't perform automatic ID generation, since changes might call OnValidate() which is where automatic ID generation is done.
|
||||
EditorPrefs.SetBool(UxrConstants.Editor.AutomaticIdGenerationPrefs, false);
|
||||
|
||||
Dictionary<Guid, IUxrUniqueId> sceneUxrComponents = new Dictionary<Guid, IUxrUniqueId>();
|
||||
|
||||
foreach (GameObject rootGameObject in scene.GetRootGameObjects())
|
||||
{
|
||||
IUxrUniqueId[] components = rootGameObject.GetComponentsInChildren<IUxrUniqueId>(true);
|
||||
|
||||
foreach (IUxrUniqueId component in components)
|
||||
{
|
||||
int attemptCount = 0;
|
||||
|
||||
while (component.UniqueId == default || sceneUxrComponents.ContainsKey(component.UniqueId))
|
||||
{
|
||||
// ID is either missing (shouldn't happen) or duplicated (by duplicating a GameObject in the scene). Generate new ID.
|
||||
component.ChangeUniqueId(UxrUniqueIdImplementer.GetNewUniqueId());
|
||||
|
||||
attemptCount++;
|
||||
|
||||
if (attemptCount > MaxAttempts)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (component.UniqueId != default)
|
||||
{
|
||||
sceneUxrComponents.TryAdd(component.UniqueId, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-enable automatic ID generation.
|
||||
EditorPrefs.SetBool(UxrConstants.Editor.AutomaticIdGenerationPrefs, true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private const int MaxAttempts = 100;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ec9b4c64e5426846b83f134ace8f4af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
177
Assets/UltimateXR/Editor/Core/UxrSdkManagerWindow.cs
Normal file
177
Assets/UltimateXR/Editor/Core/UxrSdkManagerWindow.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrSdkManagerWindow.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UltimateXR.Core;
|
||||
using UltimateXR.Editor.Sdks;
|
||||
using UltimateXR.Extensions.System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Editor class that allows to create/modify/delete hand poses that can be used for interaction or manipulation in
|
||||
/// avatars.
|
||||
/// </summary>
|
||||
public class UxrSdkManagerWindow : EditorWindow
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Shows the SDK Manager window.
|
||||
/// </summary>
|
||||
[MenuItem(UxrConstants.Editor.MenuPathSdks + "SDK Manager", priority = UxrConstants.Editor.PriorityMenuPathSdks + 100)]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
ShowWindow(UxrSdkLocator.SupportType.InputTracking);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the SDK Manager window.
|
||||
/// </summary>
|
||||
/// <param name="supportType">SDK type tab to show</param>
|
||||
public static void ShowWindow(UxrSdkLocator.SupportType supportType)
|
||||
{
|
||||
UxrSdkManagerWindow managerWindow = GetWindow(typeof(UxrSdkManagerWindow), true, "UltimateXR SDK Manager") as UxrSdkManagerWindow;
|
||||
|
||||
if (GetRegisteredSdkSupportTypes().Contains(supportType))
|
||||
{
|
||||
managerWindow._selectedType = (int)supportType;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the window.
|
||||
/// </summary>
|
||||
private void OnEnable()
|
||||
{
|
||||
_foldouts = new Dictionary<UxrSdkLocator, bool>();
|
||||
_registeredTypes = GetRegisteredSdkSupportTypes();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the UI and handles input events.
|
||||
/// </summary>
|
||||
private void OnGUI()
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorGUILayout.LabelField("Compiling...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_registeredTypes.Count == 0)
|
||||
{
|
||||
EditorGUILayout.LabelField("No SDK locators have been registered");
|
||||
return;
|
||||
}
|
||||
|
||||
// SDK type tabs
|
||||
|
||||
if (_registeredTypes.Count > 1)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
_selectedType = GUILayout.Toolbar(_selectedType, _registeredTypes.Select(t => t.ToString().SplitCamelCase()).ToArray());
|
||||
}
|
||||
|
||||
// SDK list
|
||||
|
||||
IEnumerable<UxrSdkLocator> locatorsOfCurrentType = UxrSdkManager.SDKLocators.Where(l => l.Support == _registeredTypes[_selectedType]);
|
||||
|
||||
if (!locatorsOfCurrentType.Any())
|
||||
{
|
||||
EditorGUILayout.LabelField("Support coming in next versions. Stay tuned!");
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Supported SDKs:", EditorStyles.boldLabel);
|
||||
EditorGUILayout.Space();
|
||||
|
||||
foreach (UxrSdkLocator sdkLocator in locatorsOfCurrentType)
|
||||
{
|
||||
if (!_foldouts.ContainsKey(sdkLocator))
|
||||
{
|
||||
_foldouts.Add(sdkLocator, true);
|
||||
}
|
||||
|
||||
_foldouts[sdkLocator] = UxrEditorUtils.FoldoutStylish(sdkLocator.Name, _foldouts[sdkLocator]);
|
||||
|
||||
if (_foldouts[sdkLocator])
|
||||
{
|
||||
EditorGUI.indentLevel += 1;
|
||||
|
||||
EditorGUILayout.LabelField("Status: " + sdkLocator.CurrentStateString);
|
||||
|
||||
if (sdkLocator.CurrentState == UxrSdkLocator.State.NotInstalled)
|
||||
{
|
||||
if (UxrEditorUtils.CenteredButton(new GUIContent("Get SDK")))
|
||||
{
|
||||
sdkLocator.TryGet();
|
||||
}
|
||||
}
|
||||
else if (sdkLocator.CurrentState == UxrSdkLocator.State.Available && sdkLocator.CanBeUpdated)
|
||||
{
|
||||
if (UxrEditorUtils.CenteredButton(new GUIContent("SDK Update Check")))
|
||||
{
|
||||
sdkLocator.TryUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = UxrSdkManager.HasAnySymbols(sdkLocator);
|
||||
|
||||
if (UxrEditorUtils.CenteredButton(new GUIContent("Remove Symbols")))
|
||||
{
|
||||
UxrSdkManager.RemoveSymbols(sdkLocator);
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
|
||||
if (sdkLocator.CurrentState == UxrSdkLocator.State.Available)
|
||||
{
|
||||
sdkLocator.OnInspectorGUI();
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the different SDK types that have been registered
|
||||
/// </summary>
|
||||
/// <returns>SDK types</returns>
|
||||
private static List<UxrSdkLocator.SupportType> GetRegisteredSdkSupportTypes()
|
||||
{
|
||||
return Enum.GetValues(typeof(UxrSdkLocator.SupportType)).OfType<UxrSdkLocator.SupportType>().ToList();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private List<UxrSdkLocator.SupportType> _registeredTypes = new List<UxrSdkLocator.SupportType>();
|
||||
private int _selectedType;
|
||||
private Dictionary<UxrSdkLocator, bool> _foldouts;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Assets/UltimateXR/Editor/Core/UxrSdkManagerWindow.cs.meta
Normal file
11
Assets/UltimateXR/Editor/Core/UxrSdkManagerWindow.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9e2598fd14163842989366affd635c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Devices.meta
Normal file
8
Assets/UltimateXR/Editor/Devices.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abc96dd969bfe354188b98a1edfba068
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Devices/Integrations.meta
Normal file
8
Assets/UltimateXR/Editor/Devices/Integrations.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 443be23ae50d17b409d3f638f6bab8ed
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/UltimateXR/Editor/Devices/Integrations/Valve.meta
Normal file
8
Assets/UltimateXR/Editor/Devices/Integrations/Valve.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33b0413256240b44da62d52daed1e4cb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,101 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrValveIndexInputEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Devices.Integrations.Valve;
|
||||
using UltimateXR.Editor.Manipulation.HandPoses;
|
||||
using UltimateXR.Extensions.System.Collections;
|
||||
using UltimateXR.Extensions.Unity;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Devices.Integrations.Valve
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Unity editor for the <see cref="UxrValveIndexInput" /> component.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrValveIndexInput))]
|
||||
public class UxrValveIndexInputEditor : UxrControllerInputEditor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Caches the serialized properties.
|
||||
/// </summary>
|
||||
public void OnEnable()
|
||||
{
|
||||
_propertyOpenHandPoseName = serializedObject.FindProperty("_openHandPoseName");
|
||||
_propertyIndexCurlAmount = serializedObject.FindProperty("_indexCurlAmount");
|
||||
_propertyMiddleCurlAmount = serializedObject.FindProperty("_middleCurlAmount");
|
||||
_propertyRingCurlAmount = serializedObject.FindProperty("_ringCurlAmount");
|
||||
_propertyLittleCurlAmount = serializedObject.FindProperty("_littleCurlAmount");
|
||||
_propertyThumbCurlAmount = serializedObject.FindProperty("_thumbCurlAmount");
|
||||
_propertyThumbSpreadAmount = serializedObject.FindProperty("_thumbSpreadAmount");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
// Draw base GUI
|
||||
base.OnInspectorGUI();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
UxrAvatar avatar = (serializedObject.targetObject as UxrValveIndexInput)?.gameObject.SafeGetComponentInParent<UxrAvatar>();
|
||||
IReadOnlyList<string> poseNames = UxrHandPoseEditorWindow.GetAvatarPoseNames(avatar);
|
||||
|
||||
if (poseNames.Count == 0 || _propertyOpenHandPoseName == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Avatar has no hand poses available to set the open hand pose when grabbing the Index controllers", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
int openPoseNameIndex = EditorGUILayout.Popup(ContentOpenHandPoseName, poseNames.IndexOf(_propertyOpenHandPoseName.stringValue), UxrEditorUtils.ToGUIContentArray(poseNames.ToArray()));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
_propertyOpenHandPoseName.stringValue = poseNames[openPoseNameIndex];
|
||||
}
|
||||
|
||||
EditorGUILayout.Slider(_propertyIndexCurlAmount, 0.0f, 90.0f, ContentIndexCurlAmount);
|
||||
EditorGUILayout.Slider(_propertyMiddleCurlAmount, 0.0f, 90.0f, ContentMiddleCurlAmount);
|
||||
EditorGUILayout.Slider(_propertyRingCurlAmount, 0.0f, 90.0f, ContentRingCurlAmount);
|
||||
EditorGUILayout.Slider(_propertyLittleCurlAmount, 0.0f, 90.0f, ContentLittleCurlAmount);
|
||||
EditorGUILayout.Slider(_propertyThumbCurlAmount, 0.0f, 90.0f, ContentThumbCurlAmount);
|
||||
EditorGUILayout.Slider(_propertyThumbSpreadAmount, 0.0f, 90.0f, ContentThumbSpreadAmount);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentOpenHandPoseName { get; } = new GUIContent("Open Hand Pose", "Selects the hand pose that will be used as default when Index Controllers are enabled. Fingers will be curled using the tracking values starting from this pose.");
|
||||
private GUIContent ContentIndexCurlAmount { get; } = new GUIContent("Index Curl Amount", "");
|
||||
private GUIContent ContentMiddleCurlAmount { get; } = new GUIContent("Middle Curl Amount", "");
|
||||
private GUIContent ContentRingCurlAmount { get; } = new GUIContent("Ring Curl Amount", "");
|
||||
private GUIContent ContentLittleCurlAmount { get; } = new GUIContent("Little Curl Amount", "");
|
||||
private GUIContent ContentThumbCurlAmount { get; } = new GUIContent("Thumb Curl Amount", "");
|
||||
private GUIContent ContentThumbSpreadAmount { get; } = new GUIContent("Thumb Spread Amount", "");
|
||||
|
||||
private SerializedProperty _propertyOpenHandPoseName;
|
||||
private SerializedProperty _propertyIndexCurlAmount;
|
||||
private SerializedProperty _propertyMiddleCurlAmount;
|
||||
private SerializedProperty _propertyRingCurlAmount;
|
||||
private SerializedProperty _propertyLittleCurlAmount;
|
||||
private SerializedProperty _propertyThumbCurlAmount;
|
||||
private SerializedProperty _propertyThumbSpreadAmount;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d21101798f95e764d8901e483b332c42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,70 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrController3DModelEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Devices.Visualization;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UltimateXR.Editor.Devices
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Unity editor for the <see cref="UxrController3DModel" /> component.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrController3DModel))]
|
||||
public class UxrController3DModelEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Caches the serialized properties.
|
||||
/// </summary>
|
||||
public void OnEnable()
|
||||
{
|
||||
_propertyNeedsBothHands = serializedObject.FindProperty("_needsBothHands");
|
||||
_propertyHandSide = serializedObject.FindProperty("_handSide");
|
||||
_propertyControllerHand = serializedObject.FindProperty("_controllerHand");
|
||||
_propertyControllerHandLeft = serializedObject.FindProperty("_controllerHandLeft");
|
||||
_propertyControllerHandRight = serializedObject.FindProperty("_controllerHandRight");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(_propertyNeedsBothHands);
|
||||
|
||||
if (_propertyNeedsBothHands.boolValue)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyControllerHandLeft);
|
||||
EditorGUILayout.PropertyField(_propertyControllerHandRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(_propertyHandSide);
|
||||
EditorGUILayout.PropertyField(_propertyControllerHand);
|
||||
}
|
||||
|
||||
// Rest of inspector
|
||||
|
||||
DrawPropertiesExcluding(serializedObject, "m_Script", "_needsBothHands", "_handSide", "_controllerHand", "_controllerHandLeft", "_controllerHandRight");
|
||||
|
||||
// Apply modified properties if necessary
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private SerializedProperty _propertyNeedsBothHands;
|
||||
private SerializedProperty _propertyHandSide;
|
||||
private SerializedProperty _propertyControllerHand;
|
||||
private SerializedProperty _propertyControllerHandLeft;
|
||||
private SerializedProperty _propertyControllerHandRight;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab4a46fd0a0ecc542993b5da82c4db48
|
||||
timeCreated: 1516615188
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,193 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrController3DModelElementDrawer.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Devices.Visualization;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Devices
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom UI property drawer for the <see cref="UxrElement" /> type.
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(UxrElement))]
|
||||
public class UxrController3DModelElementDrawer : PropertyDrawer
|
||||
{
|
||||
#region Public Overrides PropertyDrawer
|
||||
|
||||
/// <inheritdoc />
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
UxrController3DModel controller3DModel = property.serializedObject.targetObject as UxrController3DModel;
|
||||
int enumIndex = property.FindPropertyRelative(PropertyElementType).enumValueIndex;
|
||||
int lineCount = 1;
|
||||
|
||||
if (enumIndex == (int)UxrElementType.NotSet)
|
||||
{
|
||||
lineCount = 2;
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Button)
|
||||
{
|
||||
lineCount = 8;
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input1DRotate)
|
||||
{
|
||||
lineCount = 8;
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input1DPush)
|
||||
{
|
||||
lineCount = 8;
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input2DJoystick)
|
||||
{
|
||||
lineCount = 9;
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input2DTouch)
|
||||
{
|
||||
lineCount = 9;
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.DPad)
|
||||
{
|
||||
lineCount = 11;
|
||||
}
|
||||
|
||||
if (controller3DModel && !controller3DModel.NeedsBothHands && enumIndex != (int)UxrElementType.NotSet)
|
||||
{
|
||||
// Doesn't need hand parameter
|
||||
lineCount -= 1;
|
||||
}
|
||||
|
||||
return lineCount * EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
UxrController3DModel controller3DModel = property.serializedObject.targetObject as UxrController3DModel;
|
||||
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
|
||||
EditorGUI.indentLevel += 1;
|
||||
|
||||
int posY = 1;
|
||||
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyElementType), ContentElementType);
|
||||
|
||||
int enumIndex = property.FindPropertyRelative(PropertyElementType).enumValueIndex;
|
||||
|
||||
if (enumIndex != (int)UxrElementType.NotSet)
|
||||
{
|
||||
if (controller3DModel && controller3DModel.NeedsBothHands)
|
||||
{
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyHand), ContentHand);
|
||||
}
|
||||
else
|
||||
{
|
||||
property.FindPropertyRelative(PropertyHand).enumValueIndex = (int)controller3DModel.HandSide;
|
||||
}
|
||||
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyElement), ContentElement);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyGameObject), ContentGameObject);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyFinger), ContentFinger);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyFingerContactPoint), ContentFingerContactPoint);
|
||||
|
||||
if (enumIndex == (int)UxrElementType.Button)
|
||||
{
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyButtonPressedOffset), ContentButtonPressedOffset);
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input1DRotate)
|
||||
{
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyInput1DPressedOffsetAngle), ContentInput1DPressedOffsetAngle);
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input1DPush)
|
||||
{
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyInput1DPressedOffset), ContentInput1DPressedOffset);
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input2DJoystick)
|
||||
{
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyInput2DFirstAxisOffsetAngle), ContentInput2DFirstAxisOffsetAngle);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyInput2DSecondAxisOffsetAngle), ContentInput2DSecondAxisOffsetAngle);
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.Input2DTouch)
|
||||
{
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyInput2DFirstAxisOffset), ContentInput2DFirstAxisOffset);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyInput2DSecondAxisOffset), ContentInput2DSecondAxisOffset);
|
||||
}
|
||||
else if (enumIndex == (int)UxrElementType.DPad)
|
||||
{
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyDpadFirstAxisOffset), ContentDpadFirstAxisOffset);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyDpadSecondAxisOffset), ContentDpadSecondAxisOffset);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyDpadFirstAxisOffsetAngle), ContentDpadFirstAxisOffsetAngle);
|
||||
EditorGUI.PropertyField(GetRect(position, posY++), property.FindPropertyRelative(PropertyDpadSecondAxisOffsetAngle), ContentDpadSecondAxisOffsetAngle);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel -= 1;
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Helper method that returns the rect for a given line number.
|
||||
/// </summary>
|
||||
/// <param name="position"><see cref="OnGUI" /> position parameter</param>
|
||||
/// <param name="line">Line number</param>
|
||||
/// <returns>Rect to draw the given UI line</returns>
|
||||
private Rect GetRect(Rect position, int line)
|
||||
{
|
||||
return new Rect(position.x, position.y + EditorGUIUtility.singleLineHeight * line, position.width, EditorGUIUtility.singleLineHeight);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private GUIContent ContentElementType { get; } = new GUIContent("Type", "");
|
||||
private GUIContent ContentHand { get; } = new GUIContent("Hand", "");
|
||||
private GUIContent ContentElement { get; } = new GUIContent("Element", "");
|
||||
private GUIContent ContentGameObject { get; } = new GUIContent("GameObject", "");
|
||||
private GUIContent ContentFinger { get; } = new GUIContent("Finger Used", "");
|
||||
private GUIContent ContentFingerContactPoint { get; } = new GUIContent("Finger Contact Pos", "");
|
||||
private GUIContent ContentButtonPressedOffset { get; } = new GUIContent("Pressed Offset", "");
|
||||
private GUIContent ContentInput1DPressedOffsetAngle { get; } = new GUIContent("Pressed Angle Offset", "");
|
||||
private GUIContent ContentInput1DPressedOffset { get; } = new GUIContent("Pressed Offset", "");
|
||||
private GUIContent ContentInput2DFirstAxisOffsetAngle { get; } = new GUIContent("1st Axis Angle Amplitude", "");
|
||||
private GUIContent ContentInput2DSecondAxisOffsetAngle { get; } = new GUIContent("2nd Axis Angle Amplitude", "");
|
||||
private GUIContent ContentInput2DFirstAxisOffset { get; } = new GUIContent("1st Axis Offset Amplitude", "");
|
||||
private GUIContent ContentInput2DSecondAxisOffset { get; } = new GUIContent("2nd Axis Offset Amplitude", "");
|
||||
private GUIContent ContentDpadFirstAxisOffsetAngle { get; } = new GUIContent("1st Axis Angle Amplitude", "");
|
||||
private GUIContent ContentDpadSecondAxisOffsetAngle { get; } = new GUIContent("2nd Axis Angle Amplitude", "");
|
||||
private GUIContent ContentDpadFirstAxisOffset { get; } = new GUIContent("1st Axis Offset Amplitude", "");
|
||||
private GUIContent ContentDpadSecondAxisOffset { get; } = new GUIContent("2nd Axis Offset Amplitude", "");
|
||||
|
||||
private const string PropertyElementType = "_elementType";
|
||||
private const string PropertyHand = "_hand";
|
||||
private const string PropertyElement = "_element";
|
||||
private const string PropertyGameObject = "_gameObject";
|
||||
private const string PropertyFinger = "_finger";
|
||||
private const string PropertyFingerContactPoint = "_fingerContactPoint";
|
||||
private const string PropertyButtonPressedOffset = "_buttonPressedOffset";
|
||||
private const string PropertyInput1DPressedOffsetAngle = "_input1DPressedOffsetAngle";
|
||||
private const string PropertyInput1DPressedOffset = "_input1DPressedOffset";
|
||||
private const string PropertyInput2DFirstAxisOffsetAngle = "_input2DFirstAxisOffsetAngle";
|
||||
private const string PropertyInput2DSecondAxisOffsetAngle = "_input2DSecondAxisOffsetAngle";
|
||||
private const string PropertyInput2DFirstAxisOffset = "_input2DFirstAxisOffset";
|
||||
private const string PropertyInput2DSecondAxisOffset = "_input2DSecondAxisOffset";
|
||||
private const string PropertyDpadFirstAxisOffsetAngle = "_dpadFirstAxisOffsetAngle";
|
||||
private const string PropertyDpadSecondAxisOffsetAngle = "_dpadSecondAxisOffsetAngle";
|
||||
private const string PropertyDpadFirstAxisOffset = "_dpadFirstAxisOffset";
|
||||
private const string PropertyDpadSecondAxisOffset = "_dpadSecondAxisOffset";
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ab5b0aa93218ec408789d651c56ffed
|
||||
timeCreated: 1505111962
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
76
Assets/UltimateXR/Editor/Devices/UxrControllerInputEditor.cs
Normal file
76
Assets/UltimateXR/Editor/Devices/UxrControllerInputEditor.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrControllerInputEditor.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Devices;
|
||||
using UltimateXR.Editor.Core;
|
||||
using UltimateXR.Editor.Sdks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Editor.Devices
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Unity editor for the device input components. Checks for SDK availability.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(UxrControllerInput), true)]
|
||||
public class UxrControllerInputEditor : UnityEditor.Editor
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Draws the UI related to checking for the required SDK.
|
||||
/// </summary>
|
||||
/// <param name="controllerInput">The controller input component to draw the UI for</param>
|
||||
public static void DrawSDKCheckInspectorGUI(UxrControllerInput controllerInput)
|
||||
{
|
||||
if (string.IsNullOrEmpty(controllerInput.SDKDependency) == false)
|
||||
{
|
||||
if (UxrSdkManager.IsAvailable(controllerInput.SDKDependency) == false)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.HelpBox("In order to work properly this component needs the following SDK installed and active: " + controllerInput.SDKDependency, MessageType.Warning);
|
||||
|
||||
if (UxrEditorUtils.CenteredButton(new GUIContent("Check", "Go to the SDK Manager to check the SDK")))
|
||||
{
|
||||
UxrSdkManagerWindow.ShowWindow(UxrSdkLocator.SupportType.InputTracking);
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given input component needs an SDK installed and available. Then draws the component itself.
|
||||
/// </summary>
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
UxrControllerInput controllerInput = serializedObject.targetObject as UxrControllerInput;
|
||||
DrawSDKCheckInspectorGUI(controllerInput);
|
||||
|
||||
if (controllerInput)
|
||||
{
|
||||
if (controllerInput.SetupType == UxrControllerSetupType.Single)
|
||||
{
|
||||
DrawPropertiesExcluding(serializedObject, "m_Script", "_leftController", "_rightController", "_enableObjectListLeft", "_enableObjectListRight");
|
||||
}
|
||||
else if (controllerInput.SetupType == UxrControllerSetupType.Dual)
|
||||
{
|
||||
DrawPropertiesExcluding(serializedObject, "m_Script", "_controller", "_enableObjectList");
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user