Add ultimate xr

This commit is contained in:
2024-08-06 21:58:35 +02:00
parent 864033bf10
commit 7165bacd9d
3952 changed files with 2162037 additions and 35 deletions

8
Assets/Oculus/VR.meta Normal file
View File

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

View File

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

View File

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

Binary file not shown.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9f4dd5a3030be6e489716719133eb2d4
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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

View File

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

View 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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7ee2ac7946102ff4b80c9a643c0bfdae
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
View File

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

60
Assets/UltimateXR/.gitignore vendored Normal file
View 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

View 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

View File

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

View File

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

View File

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

View File

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

View 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
}
}

View File

@@ -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:

View 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
}
}

View File

@@ -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:

View File

@@ -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
}
}

View File

@@ -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:

View File

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

View File

@@ -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
}
}

View File

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

View File

@@ -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
}
}

View File

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

View File

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

View File

@@ -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
}
}

View File

@@ -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:

View File

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

View File

@@ -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
}
}

View File

@@ -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:

View File

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

View File

@@ -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
}
}

View File

@@ -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:

View File

@@ -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
}
}

View File

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

View File

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

View File

@@ -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
}
}

View File

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

View File

@@ -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
}
}

View File

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

View File

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

View 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

View File

@@ -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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
}
}

View File

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

View File

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

View File

@@ -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
}
}

View File

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

View File

@@ -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
}
}

View File

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

View File

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

View 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
}
}

View File

@@ -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:

View File

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

View File

@@ -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
}
}

View File

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

View File

@@ -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
}
}

View File

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

View 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
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
}
}

View File

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

View File

@@ -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
}
}

View File

@@ -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:

View File

@@ -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
}
}

View File

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

View 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