NEW HVR 2.9.1f
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using HurricaneVR.Framework.Core.ScriptableObjects;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Editor
|
||||
{
|
||||
public class CustomContexts
|
||||
{
|
||||
[MenuItem("Assets/HVR/Convert to Strength", false, 1)]
|
||||
private static void StrengthConvert(MenuCommand command)
|
||||
{
|
||||
foreach (var o in Selection.objects)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(o);
|
||||
var js = AssetDatabase.LoadAssetAtPath<HVRJointSettings>(path);
|
||||
if (!js)
|
||||
continue;
|
||||
|
||||
var fileName = path.Replace(".asset", "");
|
||||
fileName += "_Strength.asset";
|
||||
|
||||
var s = AssetDatabase.LoadAssetAtPath<PDStrength>(fileName);
|
||||
if (!s)
|
||||
{
|
||||
s = ScriptableObject.CreateInstance<PDStrength>();
|
||||
}
|
||||
|
||||
s.Mode = js.ApplyMode;
|
||||
s.Spring = js.XDrive.Spring;
|
||||
s.Damper = js.XDrive.Damper;
|
||||
s.MaxForce = js.XDrive.MaxForce;
|
||||
s.TorqueSpring = js.SlerpDrive.Spring;
|
||||
s.TorqueDamper = js.SlerpDrive.Damper;
|
||||
s.MaxTorque = js.SlerpDrive.MaxForce;
|
||||
|
||||
AssetUtils.CreateOrReplaceAsset(s, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Assets/HVR/Convert to Strength", true, 1)]
|
||||
private static bool StrengthConvertValidation()
|
||||
{
|
||||
foreach (var o in Selection.objects)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(o);
|
||||
var js = AssetDatabase.LoadAssetAtPath<HVRJointSettings>(path);
|
||||
if (!js)
|
||||
return false;
|
||||
}
|
||||
|
||||
return Selection.objects.Length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2d14f6a173045b08af8717e276df756
|
||||
timeCreated: 1666239275
|
||||
@@ -0,0 +1,49 @@
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Editor
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(EmbeddedAttribute), true)]
|
||||
public class EmbeddedAssetDrawer : PropertyDrawer
|
||||
{
|
||||
private EmbeddeAssetEditor _editor;
|
||||
|
||||
public EmbeddeAssetEditor Editor
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_editor == null)
|
||||
_editor = new EmbeddeAssetEditor();
|
||||
return _editor;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
var a = attribute as EmbeddedAttribute;
|
||||
|
||||
Editor.DrawEditorCombo(position, fieldInfo.FieldType, label, property, $"Save {property.displayName}.", $"{property.displayName.Replace(" ", "_")}", "asset", string.Empty);
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (!property.isExpanded || property.objectReferenceValue == null)
|
||||
{
|
||||
return EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
float height = base.GetPropertyHeight(property, label) + EditorGUIUtility.singleLineHeight;
|
||||
var so = new SerializedObject(property.objectReferenceValue);
|
||||
var prop = so.GetIterator();
|
||||
prop.NextVisible(true);
|
||||
while (prop.NextVisible(true))
|
||||
{
|
||||
if (prop.name == "m_Script")
|
||||
continue;
|
||||
height += EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
return height * 1.2f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d3003c99effe439d9d06c4e9334443ba
|
||||
timeCreated: 1666146629
|
||||
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEditor.VersionControl;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace HurricaneVR.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper for drawing embedded asset editors
|
||||
/// </summary>
|
||||
public class EmbeddeAssetEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Free the resources in OnDisable()
|
||||
/// </summary>
|
||||
public void OnDisable()
|
||||
{
|
||||
DestroyEditor();
|
||||
}
|
||||
|
||||
private readonly GUIContent m_CreateButtonGUIContent = new GUIContent("Create Asset", "Create new asset.");
|
||||
|
||||
UnityEditor.Editor m_Editor = null;
|
||||
const int kIndentOffset = 3;
|
||||
private Type _type;
|
||||
|
||||
public void DrawEditorCombo(Rect position, Type type, GUIContent label, SerializedProperty property, string title, string defaultName, string extension, string message)
|
||||
{
|
||||
_type = type;
|
||||
DrawEditorCombo(position, property, title, defaultName, extension, message, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this from OnInspectorGUI. Will draw the asset reference field, and
|
||||
/// the embedded editor, or a Create Asset button, if no asset is set.
|
||||
/// </summary>
|
||||
private void DrawEditorCombo(Rect position, SerializedProperty property,
|
||||
string title, string defaultName, string extension, string message,
|
||||
bool indent)
|
||||
{
|
||||
UpdateEditor(property);
|
||||
if (!m_Editor)
|
||||
{
|
||||
AssetFieldWithCreateButton(position, property, title, defaultName, extension, message);
|
||||
return;
|
||||
}
|
||||
|
||||
var rect = position;
|
||||
var propRect = rect;
|
||||
propRect.height = EditorGUIUtility.singleLineHeight;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.PropertyField(propRect, property);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
UpdateEditor(property);
|
||||
}
|
||||
|
||||
if (m_Editor)
|
||||
{
|
||||
Rect foldoutRect = new Rect(rect.x - kIndentOffset, rect.y, rect.width + kIndentOffset, EditorGUIUtility.singleLineHeight);
|
||||
property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, GUIContent.none, true);
|
||||
|
||||
bool canEditAsset = AssetDatabase.IsOpenForEdit(m_Editor.target, StatusQueryOptions.UseCachedIfPossible);
|
||||
GUI.enabled = canEditAsset;
|
||||
if (property.isExpanded)
|
||||
{
|
||||
position.y += EditorGUIUtility.singleLineHeight;
|
||||
var box = position;
|
||||
box.height *= .9f;
|
||||
EditorGUI.HelpBox(box, "CTRL+S to persist asset changes.", MessageType.None);
|
||||
position.y += EditorGUIUtility.singleLineHeight;
|
||||
EditorGUI.BeginChangeCheck();
|
||||
var so = new SerializedObject(property.objectReferenceValue);
|
||||
var prop = so.GetIterator();
|
||||
|
||||
while (prop.NextVisible(true))
|
||||
{
|
||||
if (prop.name == "m_Script")
|
||||
continue;
|
||||
position.height = EditorGUIUtility.singleLineHeight;
|
||||
EditorGUI.PropertyField(position, prop);
|
||||
position.y += EditorGUIUtility.singleLineHeight;
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
if (m_Editor.target != null)
|
||||
{
|
||||
if (!canEditAsset && GUILayout.Button("Check out"))
|
||||
{
|
||||
Task task = Provider.Checkout(AssetDatabase.GetAssetPath(m_Editor.target), CheckoutMode.Asset);
|
||||
task.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetFieldWithCreateButton(Rect position, SerializedProperty property,
|
||||
string title, string defaultName, string extension, string message)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
float hSpace = 5;
|
||||
float buttonWidth = GUI.skin.button.CalcSize(m_CreateButtonGUIContent).x;
|
||||
|
||||
var r = position;
|
||||
r.width -= buttonWidth + hSpace;
|
||||
EditorGUI.PropertyField(r, property);
|
||||
r.x += r.width + hSpace;
|
||||
r.width = buttonWidth;
|
||||
if (GUI.Button(r, m_CreateButtonGUIContent))
|
||||
{
|
||||
string newAssetPath = EditorUtility.SaveFilePanelInProject(
|
||||
title, defaultName, extension, message);
|
||||
if (!string.IsNullOrEmpty(newAssetPath))
|
||||
{
|
||||
var asset = CreateAt(_type, newAssetPath);
|
||||
property.objectReferenceValue = asset;
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
UpdateEditor(property);
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyEditor()
|
||||
{
|
||||
if (m_Editor != null)
|
||||
{
|
||||
UnityEngine.Object.DestroyImmediate(m_Editor);
|
||||
m_Editor = null;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateEditor(SerializedProperty property)
|
||||
{
|
||||
property.serializedObject.ApplyModifiedProperties();
|
||||
|
||||
var target = property.objectReferenceValue;
|
||||
if (m_Editor && m_Editor.target != target)
|
||||
{
|
||||
DestroyEditor();
|
||||
}
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
if (!m_Editor)
|
||||
{
|
||||
m_Editor = UnityEditor.Editor.CreateEditor(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ScriptableObject CreateAt(Type assetType, string assetPath)
|
||||
{
|
||||
ScriptableObject asset = ScriptableObject.CreateInstance(assetType);
|
||||
if (!asset)
|
||||
{
|
||||
Debug.LogError("Failed to create instance of " + assetType.Name + " at " + assetPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(asset, assetPath);
|
||||
return asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63f79aabdd614d20a214af69939cd772
|
||||
timeCreated: 1666142031
|
||||
@@ -43,6 +43,10 @@ namespace HurricaneVR.Editor
|
||||
value = EditorGUILayout.ObjectField(label, value, typeof(HVRJointSettings), false) as HVRJointSettings;
|
||||
}
|
||||
|
||||
public static void StrengthField(string label, ref PDStrength value)
|
||||
{
|
||||
value = EditorGUILayout.ObjectField(label, value, typeof(PDStrength), false) as PDStrength;
|
||||
}
|
||||
|
||||
public static void Header(string label)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace HurricaneVR.Editor
|
||||
public class HVREditorManager
|
||||
{
|
||||
private const string HurricaneVRUploader = "HurricaneVRUploader";
|
||||
public const string Version = "2.8.4";
|
||||
public const string Version = "2.9.1f";
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void Hook()
|
||||
|
||||
@@ -7,13 +7,14 @@ using HurricaneVR.Framework.Core.HandPoser;
|
||||
using HurricaneVR.Framework.Core.ScriptableObjects;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using HurricaneVR.Framework.Shared;
|
||||
using HurricaneVR.Framework.Shared.Utilities;
|
||||
using HurricaneVR.Framework.Weapons;
|
||||
using HurricaneVR.Framework.Weapons.Guns;
|
||||
using HurricaneVR.Framework.Weapons.Guns.PartFinders;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using HVRPistol = HurricaneVR.Framework.Weapons.Guns.HVRPistol;
|
||||
using Object = UnityEngine.Object;
|
||||
using Zero;
|
||||
|
||||
namespace HurricaneVR.Editor
|
||||
{
|
||||
@@ -26,8 +27,8 @@ namespace HurricaneVR.Editor
|
||||
|
||||
//private const string TwoHandPistol = "HandSettings/HVR_Pistol_TwoHand";
|
||||
//private const string TwoHandLarge = "HandSettings/HVR_LargeWeapon_TwoHanded";
|
||||
private const string TwoHandLargeStabilizer = "HandSettings/HVR_Stabilizer_TwoHanded";
|
||||
private const string TwoHandPistolStabilizer = "HandSettings/HVR_Pistol_Stabilizer_TwoHanded";
|
||||
private const string TwoHandLargeStabilizer = "HandSettings/HVR_Stabilizer_TwoHanded_Strength";
|
||||
private const string TwoHandPistolStabilizer = "HandSettings/HVR_Pistol_Stabilizer_TwoHanded_Strength";
|
||||
|
||||
//private const string OneHandPistol = "HandSettings/HVR_Pistol_OneHand";
|
||||
//private const string OneHandDefault = "HandSettings/HVR_DefaultHandSettings";
|
||||
@@ -48,7 +49,7 @@ namespace HurricaneVR.Editor
|
||||
private float _gunMass = 1.5f;
|
||||
private float _bulletSpeed = 80f;
|
||||
private int _rpm = 900;
|
||||
private FireType _firingType;
|
||||
private GunFireType _firingType;
|
||||
|
||||
private HVRHandPose _gripPose;
|
||||
private HVRHandPose _stabilizerPose;
|
||||
@@ -67,9 +68,9 @@ namespace HurricaneVR.Editor
|
||||
private bool _stabilizerRequiresGripGrabbed = true;
|
||||
private bool _stabilizerDropsOnGripReleased = true;
|
||||
private float _cycleTime = .05f;
|
||||
private HVRJointSettings _gripOneHand;
|
||||
private HVRJointSettings _gripTwoHand;
|
||||
private HVRJointSettings _stabilizerTwoHand;
|
||||
private PDStrength _gripOneHand;
|
||||
private PDStrength _gripTwoHand;
|
||||
private PDStrength _stabilizerTwoHand;
|
||||
private bool _ejectedBulletPooled = true;
|
||||
private HVRRecoilSettings _recoilSettings;
|
||||
private Vector2 _scrollPosition;
|
||||
@@ -127,7 +128,7 @@ namespace HurricaneVR.Editor
|
||||
|
||||
HVREditorExtensions.IntField("Rounds Per Minute", ref _rpm);
|
||||
HVREditorExtensions.FloatField("Bullet Speed", ref _bulletSpeed);
|
||||
_firingType = (FireType)EditorGUILayout.EnumPopup("Firing Mode", _firingType);
|
||||
_firingType = (GunFireType)EditorGUILayout.EnumPopup("Firing Mode", _firingType);
|
||||
var currentType = _gunType;
|
||||
_gunType = (HVRGunType)EditorGUILayout.EnumPopup("Type", _gunType);
|
||||
_hitLayerMask = LayerMaskDrawer.LayerMaskField("Hit Layer Mask", _hitLayerMask);
|
||||
@@ -179,9 +180,9 @@ namespace HurricaneVR.Editor
|
||||
// PopulateDefaultHandSettings();
|
||||
//}
|
||||
|
||||
HVREditorExtensions.JointField("Grip One Handed", ref _gripOneHand);
|
||||
HVREditorExtensions.JointField("Grip Two Handed", ref _gripTwoHand);
|
||||
HVREditorExtensions.JointField("Stabilizer Two Handed", ref _stabilizerTwoHand);
|
||||
HVREditorExtensions.StrengthField("Grip One Handed", ref _gripOneHand);
|
||||
HVREditorExtensions.StrengthField("Grip Two Handed", ref _gripTwoHand);
|
||||
HVREditorExtensions.StrengthField("Stabilizer Two Handed", ref _stabilizerTwoHand);
|
||||
|
||||
GUILayout.Space(20f);
|
||||
HVREditorExtensions.Header("SFX");
|
||||
@@ -377,8 +378,8 @@ namespace HurricaneVR.Editor
|
||||
Undo.RegisterCreatedObjectUndo(root, _gunPrefab.name);
|
||||
|
||||
gunGrabbable = AddGrabbable(root, out var poser, out var gp);
|
||||
gunGrabbable.OneHandJointSettings = _gripOneHand;
|
||||
gunGrabbable.TwoHandJointSettings = _gripTwoHand;
|
||||
gunGrabbable.OneHandStrength = _gripOneHand;
|
||||
gunGrabbable.TwoHandStrength = _gripTwoHand;
|
||||
poser.PrimaryPose.Pose = _gripPose;
|
||||
gunGrabbable.HoldType = HVRHoldType.Swap;
|
||||
gunGrabbable.RequireOverlapClearance = true;
|
||||
@@ -398,19 +399,19 @@ namespace HurricaneVR.Editor
|
||||
|
||||
private GameObject CreatePistol()
|
||||
{
|
||||
var root = CreateGun<ExtGunBase>(out var gunGrabbable, out var model, out var gun);
|
||||
var root = CreateGun<HVRPistol>(out var gunGrabbable, out var model, out var gun);
|
||||
return root;
|
||||
}
|
||||
|
||||
private GameObject CreateAutomatic()
|
||||
{
|
||||
var root = CreateGun<ExtGunBase>(out var gunGrabbable, out var model, out var gun);
|
||||
var root = CreateGun<HVRAutomaticGun>(out var gunGrabbable, out var model, out var gun);
|
||||
return root;
|
||||
}
|
||||
|
||||
private GameObject CreatePumpShotgun()
|
||||
{
|
||||
var root = CreateGun<ExtGunShotgun>(out var gunGrabbable, out var model, out var gun);
|
||||
var root = CreateGun<HVRShotgun>(out var gunGrabbable, out var model, out var gun);
|
||||
var mag = root.AddComponent<HVRShotgunMagazine>();
|
||||
gun.ChambersAfterFiring = false;
|
||||
mag.MaxCount = 5;
|
||||
@@ -454,9 +455,8 @@ namespace HurricaneVR.Editor
|
||||
//grabbable.TrackingType = HVRGrabTracking.None;
|
||||
grabbable.HoldType = HVRHoldType.OneHand;
|
||||
grabbable.DisableHandCollision = true;
|
||||
grabbable.PoseImmediately = true;
|
||||
grabbable.ForceGrabbable = false;
|
||||
grabbable.TwoHandJointSettings = _stabilizerTwoHand;
|
||||
grabbable.TwoHandStrength = _stabilizerTwoHand;
|
||||
grabbable.ExtraIgnoreCollisionParents = new List<Transform>() { gunGrabbable.Rigidbody.transform };
|
||||
|
||||
if (_stabilizerRequiresGripGrabbed)
|
||||
@@ -500,6 +500,10 @@ namespace HurricaneVR.Editor
|
||||
gun.RecoilComponent = gun.gameObject.AddComponent<HVRRecoil>();
|
||||
gun.RecoilComponent.Settings = _recoilSettings;
|
||||
gun.GunSounds = gun.gameObject.AddComponent<HVRGunSounds>();
|
||||
gun.GunSounds.Fired = FiredSFX;
|
||||
gun.GunSounds.OutOfAmmo = DryFireSFX;
|
||||
gun.GunSounds.SlideBack = CockedBackSFX;
|
||||
gun.GunSounds.SlideForward = CockedForwardSFX;
|
||||
gun.Bolt = bolt;
|
||||
|
||||
var adjustTransforms = AddAdjustTransform(gun.gameObject);
|
||||
|
||||
@@ -14,6 +14,12 @@ using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
using UnityEditor.SceneManagement;
|
||||
#else
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
#endif
|
||||
|
||||
namespace HurricaneVR.Editor
|
||||
{
|
||||
[CustomEditor(typeof(HVRHandPoser))]
|
||||
@@ -108,10 +114,7 @@ namespace HurricaneVR.Editor
|
||||
|
||||
private HVRHandPoseBlend PrimaryPose
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poser.PrimaryPose;
|
||||
}
|
||||
get { return Poser.PrimaryPose; }
|
||||
set
|
||||
{
|
||||
Poser.PrimaryPose = value;
|
||||
@@ -121,10 +124,7 @@ namespace HurricaneVR.Editor
|
||||
|
||||
public HVRHandPose SelectedPose
|
||||
{
|
||||
get
|
||||
{
|
||||
return SelectedBlendPose?.Pose;
|
||||
}
|
||||
get { return SelectedBlendPose?.Pose; }
|
||||
set
|
||||
{
|
||||
if (SelectedBlendPose == null) return;
|
||||
@@ -184,7 +184,6 @@ namespace HurricaneVR.Editor
|
||||
{
|
||||
SceneView.duringSceneGui -= OnSceneGUI2;
|
||||
SceneView.duringSceneGui += OnSceneGUI2;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -225,7 +224,6 @@ namespace HurricaneVR.Editor
|
||||
}
|
||||
|
||||
foreach (var c in cleanup) _map.Remove(c);
|
||||
|
||||
}
|
||||
|
||||
private void GetHands(ref HVRPosableHand leftHand, ref HVRPosableHand rightHand)
|
||||
@@ -414,6 +412,7 @@ namespace HurricaneVR.Editor
|
||||
{
|
||||
selectedFinger = i;
|
||||
}
|
||||
|
||||
selectedBone = bone.Transform;
|
||||
}
|
||||
}
|
||||
@@ -425,6 +424,9 @@ namespace HurricaneVR.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private bool _inPrefabMode;
|
||||
private bool _active;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
Poser = target as HVRHandPoser;
|
||||
@@ -452,13 +454,30 @@ namespace HurricaneVR.Editor
|
||||
|
||||
_root = new VisualElement();
|
||||
_tree = UnityEngine.Resources.Load<VisualTreeAsset>("HVRHandPoserEditor");
|
||||
|
||||
var stage = PrefabStageUtility.GetPrefabStage(Poser.gameObject);
|
||||
_inPrefabMode = stage != null;
|
||||
|
||||
_active = true;
|
||||
var s = _root.schedule.Execute(EditorUpdate);
|
||||
s.Every(1000);
|
||||
s.Until(() => !_active);
|
||||
}
|
||||
|
||||
private void EditorUpdate()
|
||||
{
|
||||
CheckRigidBody();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_active = false;
|
||||
}
|
||||
|
||||
private void CreatePoseIfNeeded()
|
||||
{
|
||||
if (PrimaryPose.Pose == null && HVRSettings.Instance.OpenHandPose)
|
||||
{
|
||||
|
||||
_root.schedule.Execute(() =>
|
||||
{
|
||||
PrimaryPose.SetDefaults();
|
||||
@@ -473,7 +492,6 @@ namespace HurricaneVR.Editor
|
||||
|
||||
public override VisualElement CreateInspectorGUI()
|
||||
{
|
||||
|
||||
_root.Clear();
|
||||
_tree.CloneTree(_root);
|
||||
|
||||
@@ -495,99 +513,111 @@ namespace HurricaneVR.Editor
|
||||
SetupHandButtons();
|
||||
SetupAutoPoseButtons();
|
||||
|
||||
//can't remember why I would add this field on the ui...
|
||||
//_selectionIndexField = new IntegerField("SelectedIndex");
|
||||
//_selectionIndexField.bindingPath = "SelectionIndex";
|
||||
//_selectionIndexField.RegisterValueChangedCallback(evt =>
|
||||
//{
|
||||
// if (PosesListView.selectedIndex != evt.newValue) PosesListView.selectedIndex = evt.newValue;
|
||||
//});
|
||||
//_root.Add(_selectionIndexField);
|
||||
|
||||
_selectionIndexField = new IntegerField("SelectedIndex");
|
||||
_selectionIndexField.bindingPath = "SelectionIndex";
|
||||
_selectionIndexField.RegisterValueChangedCallback(evt =>
|
||||
if (_inPrefabMode)
|
||||
{
|
||||
if (PosesListView.selectedIndex != evt.newValue) PosesListView.selectedIndex = evt.newValue;
|
||||
});
|
||||
_root.Add(_selectionIndexField);
|
||||
|
||||
PreviewLeftToggle = _root.Q<Toggle>("PreviewLeft");
|
||||
PreviewLeftToggle.BindProperty(SP_PreviewLeft);
|
||||
PreviewRightToggle = _root.Q<Toggle>("PreviewRight");
|
||||
PreviewRightToggle.BindProperty(SP_PreviewRight);
|
||||
|
||||
PreviewLeftToggle.RegisterValueChangedCallback(OnPreviewLeftChanged);
|
||||
PreviewRightToggle.RegisterValueChangedCallback(OnPreviewRightChanged);
|
||||
|
||||
ToggleLeftAutoPose = _root.Q<Toggle>("LeftAutoPose");
|
||||
ToggleLeftAutoPose.BindProperty(SP_LeftAutoPose);
|
||||
ToggleRightAutoPose = _root.Q<Toggle>("RightAutoPose");
|
||||
ToggleRightAutoPose.BindProperty(SP_RightAutoPose);
|
||||
|
||||
ToggleLeftAutoPose.RegisterValueChangedCallback(OnLeftAutoPoseChanged);
|
||||
ToggleRightAutoPose.RegisterValueChangedCallback(OnRightAutoPoseChanged);
|
||||
|
||||
if (SelectedIndex >= PosesListView.itemsSource.Count + PrimaryIndex)
|
||||
{
|
||||
Debug.Log($"Stored SelectedIndex is higher than pose count.");
|
||||
SelectedIndex = PosesListView.itemsSource.Count - PrimaryIndex - 1;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
PosesListView.selectedIndex = SelectedIndex;
|
||||
|
||||
|
||||
GetPhysicsPosers();
|
||||
|
||||
if (FullBody)
|
||||
{
|
||||
var body = GameObject.Find(_bodyId);
|
||||
if (body)
|
||||
{
|
||||
SP_BodyPreview.objectReferenceValue = body;
|
||||
}
|
||||
|
||||
UpdateBodyPreview(SelectedPose != null ? SelectedPose.LeftHand : null, SelectedPose != null ? SelectedPose.RightHand : null, PreviewLeft, PreviewRight);
|
||||
_root.Q("MirrorAxis").style.display = DisplayStyle.None;
|
||||
_root.Q("boxPreview").style.display = DisplayStyle.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
SP_PreviewLeft.boolValue = SP_LeftHandPreview.objectReferenceValue != null;
|
||||
SP_PreviewRight.boolValue = SP_RightHandPreview.objectReferenceValue != null;
|
||||
_root.Q("warning").style.display = DisplayStyle.None;
|
||||
|
||||
if (!SP_PreviewLeft.boolValue)
|
||||
PreviewLeftToggle = _root.Q<Toggle>("PreviewLeft");
|
||||
PreviewLeftToggle.BindProperty(SP_PreviewLeft);
|
||||
PreviewRightToggle = _root.Q<Toggle>("PreviewRight");
|
||||
PreviewRightToggle.BindProperty(SP_PreviewRight);
|
||||
|
||||
PreviewLeftToggle.RegisterValueChangedCallback(OnPreviewLeftChanged);
|
||||
PreviewRightToggle.RegisterValueChangedCallback(OnPreviewRightChanged);
|
||||
|
||||
ToggleLeftAutoPose = _root.Q<Toggle>("LeftAutoPose");
|
||||
|
||||
ToggleLeftAutoPose.BindProperty(SP_LeftAutoPose);
|
||||
ToggleRightAutoPose = _root.Q<Toggle>("RightAutoPose");
|
||||
ToggleRightAutoPose.BindProperty(SP_RightAutoPose);
|
||||
|
||||
ToggleLeftAutoPose.RegisterValueChangedCallback(OnLeftAutoPoseChanged);
|
||||
ToggleRightAutoPose.RegisterValueChangedCallback(OnRightAutoPoseChanged);
|
||||
|
||||
if (SelectedIndex >= PosesListView.itemsSource.Count + PrimaryIndex)
|
||||
{
|
||||
FindPreviewHand(true, out var left);
|
||||
if (left)
|
||||
Debug.Log($"Stored SelectedIndex is higher than pose count.");
|
||||
SelectedIndex = PosesListView.itemsSource.Count - PrimaryIndex - 1;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
PosesListView.selectedIndex = SelectedIndex;
|
||||
|
||||
|
||||
GetPhysicsPosers();
|
||||
|
||||
if (FullBody)
|
||||
{
|
||||
var body = GameObject.Find(_bodyId);
|
||||
if (body)
|
||||
{
|
||||
SP_PreviewLeft.boolValue = true;
|
||||
SP_LeftHandPreview.objectReferenceValue = left;
|
||||
SP_BodyPreview.objectReferenceValue = body;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SP_PreviewRight.boolValue)
|
||||
UpdateBodyPreview(SelectedPose != null ? SelectedPose.LeftHand : null, SelectedPose != null ? SelectedPose.RightHand : null, PreviewLeft, PreviewRight);
|
||||
}
|
||||
else
|
||||
{
|
||||
FindPreviewHand(false, out var right);
|
||||
if (right)
|
||||
SP_PreviewLeft.boolValue = SP_LeftHandPreview.objectReferenceValue != null;
|
||||
SP_PreviewRight.boolValue = SP_RightHandPreview.objectReferenceValue != null;
|
||||
|
||||
if (!SP_PreviewLeft.boolValue)
|
||||
{
|
||||
SP_PreviewRight.boolValue = true;
|
||||
SP_RightHandPreview.objectReferenceValue = right;
|
||||
FindPreviewHand(true, out var left);
|
||||
if (left)
|
||||
{
|
||||
SP_PreviewLeft.boolValue = true;
|
||||
SP_LeftHandPreview.objectReferenceValue = left;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SP_PreviewRight.boolValue)
|
||||
{
|
||||
FindPreviewHand(false, out var right);
|
||||
if (right)
|
||||
{
|
||||
SP_PreviewRight.boolValue = true;
|
||||
SP_RightHandPreview.objectReferenceValue = right;
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePreview(false, SP_PreviewRight.boolValue, SelectedPose != null ? SelectedPose.LeftHand : null);
|
||||
UpdatePreview(true, SP_PreviewLeft.boolValue, SelectedPose != null ? SelectedPose.RightHand : null);
|
||||
}
|
||||
|
||||
UpdatePreview(false, SP_PreviewRight.boolValue, SelectedPose != null ? SelectedPose.LeftHand : null);
|
||||
UpdatePreview(true, SP_PreviewLeft.boolValue, SelectedPose != null ? SelectedPose.RightHand : null);
|
||||
if (_leftPhysicsPoser)
|
||||
{
|
||||
SP_LeftAutoPose.boolValue = _leftPhysicsPoser.LiveUpdate;
|
||||
}
|
||||
else
|
||||
{
|
||||
SP_LeftAutoPose.boolValue = false;
|
||||
}
|
||||
|
||||
if (_rightPhysicsPoser)
|
||||
{
|
||||
SP_RightAutoPose.boolValue = _rightPhysicsPoser.LiveUpdate;
|
||||
}
|
||||
else
|
||||
{
|
||||
SP_RightAutoPose.boolValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_leftPhysicsPoser)
|
||||
{
|
||||
SP_LeftAutoPose.boolValue = _leftPhysicsPoser.LiveUpdate;
|
||||
}
|
||||
else
|
||||
{
|
||||
SP_LeftAutoPose.boolValue = false;
|
||||
}
|
||||
|
||||
if (_rightPhysicsPoser)
|
||||
{
|
||||
SP_RightAutoPose.boolValue = _rightPhysicsPoser.LiveUpdate;
|
||||
}
|
||||
else
|
||||
{
|
||||
SP_RightAutoPose.boolValue = false;
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
@@ -650,6 +680,7 @@ namespace HurricaneVR.Editor
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_rightPhysicsPoser.LiveUpdate = evt.newValue;
|
||||
}
|
||||
}
|
||||
@@ -663,6 +694,7 @@ namespace HurricaneVR.Editor
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_leftPhysicsPoser.LiveUpdate = evt.newValue;
|
||||
}
|
||||
}
|
||||
@@ -709,12 +741,10 @@ namespace HurricaneVR.Editor
|
||||
{
|
||||
_rightPhysicsPoser.LiveUpdate = SP_RightAutoPose.boolValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnPreviewLeftChanged(ChangeEvent<bool> evt)
|
||||
{
|
||||
|
||||
CreatePoseIfNeeded();
|
||||
|
||||
if (FullBody)
|
||||
@@ -757,6 +787,18 @@ namespace HurricaneVR.Editor
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckRigidBody()
|
||||
{
|
||||
var g = Poser.GetComponentInParent<HVRGrabbable>();
|
||||
Rigidbody rb = null;
|
||||
if (g)
|
||||
{
|
||||
rb = g.gameObject.GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
_root.Q("lblAutoPoseWarning").style.display = rb ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
|
||||
private void UpdateBodyPreview(HVRHandPoseData leftpose, HVRHandPoseData rightpose, bool previewLeft, bool previewRight, bool poseChanged = false)
|
||||
{
|
||||
if (!previewRight && !previewLeft)
|
||||
@@ -769,6 +811,7 @@ namespace HurricaneVR.Editor
|
||||
SetupIKTarget(previewLeft, "LeftIKTarget", out var dummy);
|
||||
SetupIKTarget(previewRight, "RightIKTarget", out var dummy2);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -863,7 +906,6 @@ namespace HurricaneVR.Editor
|
||||
}
|
||||
|
||||
|
||||
|
||||
SceneView.RepaintAll();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
@@ -958,6 +1000,9 @@ namespace HurricaneVR.Editor
|
||||
|
||||
private void OnSelectedPoseChanged(ChangeEvent<Object> evt)
|
||||
{
|
||||
if (_inPrefabMode)
|
||||
return;
|
||||
|
||||
if (evt.newValue != null)
|
||||
{
|
||||
var newPose = evt.newValue as HVRHandPose;
|
||||
@@ -1289,7 +1334,6 @@ namespace HurricaneVR.Editor
|
||||
rightHand.Pose(right);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var mirrorLeft = _root.Q<Button>("ButtonMirrorLeft");
|
||||
@@ -1328,8 +1372,6 @@ namespace HurricaneVR.Editor
|
||||
leftHand.Pose(left);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1391,10 +1433,7 @@ namespace HurricaneVR.Editor
|
||||
SelectedPoseField.bindingPath = "Pose";
|
||||
//SelectedPoseField.RegisterValueChangedCallback(OnSelectedPoseChanged);
|
||||
////unity decide to fk with everything in 2020, hack to handle selected pose field from firing it's change event on enable that didn't happen in 2019..
|
||||
var schedule = container.schedule.Execute(() =>
|
||||
{
|
||||
SelectedPoseField.RegisterValueChangedCallback(OnSelectedPoseChanged);
|
||||
});
|
||||
var schedule = container.schedule.Execute(() => { SelectedPoseField.RegisterValueChangedCallback(OnSelectedPoseChanged); });
|
||||
schedule.StartingIn(1000);
|
||||
}
|
||||
|
||||
@@ -1417,7 +1456,6 @@ namespace HurricaneVR.Editor
|
||||
|
||||
|
||||
#if UNITY_2021_1_OR_NEWER
|
||||
|
||||
PosesListView.onSelectionChange += OnPoseSelectionChanged;
|
||||
#else
|
||||
|
||||
@@ -1455,6 +1493,9 @@ namespace HurricaneVR.Editor
|
||||
|
||||
SelectedIndex = PosesListView.selectedIndex;
|
||||
|
||||
var poseName = SelectedPose == null ? "None" : SelectedPose.name;
|
||||
blendEditorRoot.Q<Label>("lblSelectedPose").text = $"Selected Pose: {poseName}";
|
||||
|
||||
BindBlendContainer();
|
||||
}
|
||||
|
||||
@@ -1469,7 +1510,6 @@ namespace HurricaneVR.Editor
|
||||
if (index == PrimaryIndex)
|
||||
{
|
||||
label.AddToClassList("primarypose");
|
||||
|
||||
}
|
||||
|
||||
if (index < Poser.PoseNames.Count)
|
||||
@@ -1509,7 +1549,11 @@ namespace HurricaneVR.Editor
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
|
||||
#if UNITY_2021_2_OR_NEWER
|
||||
PosesListView?.Rebuild();
|
||||
#else
|
||||
PosesListView?.Refresh();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,8 +207,8 @@ namespace HurricaneVR
|
||||
Left.localPosition = Vector3.zero;
|
||||
Right.localPosition = Vector3.zero;
|
||||
|
||||
var leftPrefab = PrefabUtility.SaveAsPrefabAssetAndConnect(Left.gameObject, "Assets/LeftHandPrefab.prefab", InteractionMode.UserAction);
|
||||
var rightPrefab = PrefabUtility.SaveAsPrefabAssetAndConnect(Right.gameObject, "Assets/RightHandPrefab.prefab", InteractionMode.UserAction);
|
||||
var leftPrefab = PrefabUtility.SaveAsPrefabAssetAndConnect(Left.gameObject, $"Assets/{Left.name}.prefab", InteractionMode.UserAction);
|
||||
var rightPrefab = PrefabUtility.SaveAsPrefabAssetAndConnect(Right.gameObject, $"Assets/{Right.name}.prefab", InteractionMode.UserAction);
|
||||
|
||||
var so = new SerializedObject(HVRSettings.Instance);
|
||||
var left = so.FindProperty("LeftHand");
|
||||
@@ -248,6 +248,35 @@ namespace HurricaneVR
|
||||
SetupFallback(rightHand);
|
||||
|
||||
PosesAssigned = true;
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
var leftPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(LeftPhysics.gameObject);
|
||||
var rightPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(RightPhysics.gameObject);
|
||||
Debug.Log($"Applying pose overrides to {leftPath} and {rightPath}.");
|
||||
PrefabUtility.ApplyObjectOverride(LeftPhysics, leftPath, InteractionMode.AutomatedAction);
|
||||
PrefabUtility.ApplyObjectOverride(RightPhysics, rightPath, InteractionMode.AutomatedAction);
|
||||
PrefabUtility.ApplyObjectOverride(LeftPoser, leftPath, InteractionMode.AutomatedAction);
|
||||
PrefabUtility.ApplyObjectOverride(RightPoser, rightPath, InteractionMode.AutomatedAction);
|
||||
|
||||
//if (leftHand.FallbackPoser)
|
||||
//{
|
||||
// var so = new SerializedObject(leftHand.FallbackPoser);
|
||||
// var blend = so.FindProperty("PrimaryPose");
|
||||
// var pose = blend.FindPropertyRelative("Pose");
|
||||
|
||||
// PrefabUtility.ApplyPropertyOverride(pose, leftPath, InteractionMode.AutomatedAction);
|
||||
//}
|
||||
|
||||
//if (rightHand.FallbackPoser)
|
||||
//{
|
||||
// var so = new SerializedObject(rightHand.FallbackPoser);
|
||||
// var blend = so.FindProperty("PrimaryPose");
|
||||
// var pose = blend.FindPropertyRelative("Pose");
|
||||
|
||||
// PrefabUtility.ApplyPropertyOverride(pose, rightPath, InteractionMode.AutomatedAction);
|
||||
//}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -454,8 +483,8 @@ namespace HurricaneVR
|
||||
|
||||
if (GUILayout.Button("Detect Mirror"))
|
||||
{
|
||||
LeftHand.DetectBoneAxes(RightHand, LeftHand.transform.parent.forward, LeftHand.transform.parent.up);
|
||||
RightHand.DetectBoneAxes(LeftHand, LeftHand.transform.parent.forward, LeftHand.transform.parent.up);
|
||||
DetectBoneAxes(LeftHand, RightHand, LeftHand.transform.parent.forward, LeftHand.transform.parent.up);
|
||||
DetectBoneAxes(RightHand, LeftHand, LeftHand.transform.parent.forward, LeftHand.transform.parent.up);
|
||||
|
||||
_badMirrorText = "";
|
||||
_badMirror = false;
|
||||
@@ -477,6 +506,40 @@ namespace HurricaneVR
|
||||
}
|
||||
}
|
||||
|
||||
public void DetectBoneAxes(HVRPosableHand hand, HVRPosableHand otherHand, Vector3 forward, Vector3 up)
|
||||
{
|
||||
var so = new SerializedObject(hand);
|
||||
var fingers = so.FindProperty("_fingers");
|
||||
|
||||
for (var i = 0; i < fingers.arraySize; i++)
|
||||
{
|
||||
var spFinger = fingers.GetArrayElementAtIndex(i);
|
||||
var spBones = spFinger.FindPropertyRelative("Bones");
|
||||
|
||||
for (var j = 0; j < spBones.arraySize; j++)
|
||||
{
|
||||
var spBone = spBones.GetArrayElementAtIndex(j);
|
||||
var bone = hand.Fingers[i].Bones[j];
|
||||
var targetBone = otherHand.Fingers[i].Bones[j];
|
||||
|
||||
// Get local orthogonal axes of the right hand pointing forward and up
|
||||
var axis1 = HVRPosableHand.GetSignedAxisVectorToDirection(bone.Transform.rotation, forward);
|
||||
var axis2 = HVRPosableHand.GetSignedAxisVectorToDirection(bone.Transform.rotation, up);
|
||||
|
||||
var targetAxis1 = HVRPosableHand.GetSignedAxisVectorToDirection(targetBone.Transform.rotation, forward);
|
||||
var targetAxis2 = HVRPosableHand.GetSignedAxisVectorToDirection(targetBone.Transform.rotation, up);
|
||||
|
||||
spBone.FindPropertyRelative(nameof(HVRPosableBone.Forward)).vector3Value = axis1;
|
||||
spBone.FindPropertyRelative(nameof(HVRPosableBone.Up)).vector3Value = axis2;
|
||||
spBone.FindPropertyRelative(nameof(HVRPosableBone.OtherForward)).vector3Value = targetAxis1;
|
||||
spBone.FindPropertyRelative(nameof(HVRPosableBone.OtherUp)).vector3Value = targetAxis2;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
so.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
private void ValidateMirrorSettings(HVRPosableHand hand)
|
||||
{
|
||||
for (var i = 0; i < hand.Fingers.Length; i++)
|
||||
@@ -514,9 +577,8 @@ namespace HurricaneVR
|
||||
" The default order matches most hand rigs. If your hand has less than 5 fingers, set those slots to 'None'\r\n" +
|
||||
"\r\n3. Update the bone count for each finger.\r\n" +
|
||||
"\r\n4. Some hand rigs may have an uneven hierarchy, update the Root Offset field with the # of bones between the parent and first bone.\r\n" +
|
||||
"\r\n5. If the finger has Tip / End transforms already, enable 'Has Tip', otherwise they will be auto generated on the last bone.\r\n" +
|
||||
"\r\n6. Press Setup and verify each HVRPosableHand fingers have the proper Root, Tip, and Bone counts assigned. Move the tip transforms to the center of the finger pad.\r\n" +
|
||||
"\r\n7. Move the 'Palm' transforms that were added to the hands to the center of the palm (barely touching the surface) with the forward (blue) axis facing out of the palm.", helpBoxStyle);
|
||||
"\r\n5. Press Setup and verify each HVRPosableHand fingers have the proper Root, Tip, and Bone counts assigned. Move the tip transforms to the center of the finger pad.\r\n" +
|
||||
"\r\n6. Move the 'Palm' transforms that were added to the hands to the center of the palm (barely touching the surface) with the forward (blue) axis facing out of the palm.", helpBoxStyle);
|
||||
|
||||
//int i = 0;
|
||||
//bool up = false;
|
||||
@@ -532,7 +594,6 @@ namespace HurricaneVR
|
||||
HVREditorExtensions.EnumField("Finger", ref s.Finger);
|
||||
HVREditorExtensions.IntField("Bones", ref s.BoneCount);
|
||||
HVREditorExtensions.IntField("Root Offset", ref s.BoneOffset);
|
||||
HVREditorExtensions.Toggle("Has Tip", ref s.HasTip);
|
||||
|
||||
//if (GUILayout.Button("^"))
|
||||
//{
|
||||
@@ -673,7 +734,6 @@ namespace HurricaneVR
|
||||
|
||||
|
||||
animator.DefaultPoseHand = false;
|
||||
animator.PoseHand = true;
|
||||
animator.PhysicsPoser = physicsPoser;
|
||||
animator.Hand = hand;
|
||||
animator.DefaultPoser = poser;
|
||||
@@ -725,35 +785,25 @@ namespace HurricaneVR
|
||||
|
||||
if (finger.Bones.Count > 0)
|
||||
{
|
||||
if (!s.HasTip)
|
||||
var last = finger.Bones.Last();
|
||||
var tipName = s.Finger.ToString() + " Tip";
|
||||
var existing = last.Transform.Find(tipName);
|
||||
|
||||
if (!existing)
|
||||
{
|
||||
var last = finger.Bones.Last();
|
||||
var tipName = s.Finger.ToString() + " Tip";
|
||||
var existing = last.Transform.Find(tipName);
|
||||
var tip = new GameObject(tipName);
|
||||
tip.transform.parent = last.Transform;
|
||||
tip.transform.ResetLocalProps();
|
||||
finger.Tip = tip.transform;
|
||||
|
||||
if (!existing)
|
||||
{
|
||||
var tip = new GameObject(tipName);
|
||||
tip.transform.parent = last.Transform;
|
||||
tip.transform.ResetLocalProps();
|
||||
finger.Tip = tip.transform;
|
||||
|
||||
Undo.RegisterCreatedObjectUndo(tip, $"Add {tipName} to {last.Transform.name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
finger.Tip = existing;
|
||||
}
|
||||
Undo.RegisterCreatedObjectUndo(tip, $"Add {tipName} to {last.Transform.name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var last = finger.Bones.Last();
|
||||
if (s.HasTip && last.Transform.childCount > 0)
|
||||
{
|
||||
finger.Tip = last.Transform.GetChild(0);
|
||||
}
|
||||
finger.Tip = existing;
|
||||
}
|
||||
|
||||
|
||||
finger.Root = finger.Bones[0].Transform;
|
||||
}
|
||||
|
||||
@@ -825,7 +875,6 @@ namespace HurricaneVR
|
||||
public Finger Finger;
|
||||
public int BoneCount = 3;
|
||||
public int BoneOffset = 0;
|
||||
public bool HasTip = false;
|
||||
public int Index;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace HurricaneVR.Editor
|
||||
private const string URLHandGrabber = "https://cloudwalker2020.github.io/HurricaneVR-Docs/manual/hands.html";
|
||||
private const string URLSockets = "https://cloudwalker2020.github.io/HurricaneVR-Docs/manual/sockets.html";
|
||||
private const string URLSetup = "https://cloudwalker2020.github.io/HurricaneVR-Docs/manual/setup.html";
|
||||
|
||||
private const string URLCustomHand = "https://cloudwalker2020.github.io/HurricaneVR-Docs/manual/hand_setup.html";
|
||||
private const string URLDoor = "https://cloudwalker2020.github.io/HurricaneVR-Docs/manual/components/door.html";
|
||||
private const string URLDiscord = "https://discord.com/invite/7QUXEcuwKY";
|
||||
|
||||
private const string DEFINESteamVR = "HVR_STEAMVR";
|
||||
@@ -116,6 +117,8 @@ namespace HurricaneVR.Editor
|
||||
SetupUrl("btnHandGrabber", URLHandGrabber);
|
||||
SetupUrl("btnDiscord", URLDiscord);
|
||||
SetupUrl("btnSetup", URLSetup);
|
||||
SetupUrl("btnCustomHand", URLCustomHand);
|
||||
SetupUrl("btnDoorSetup", URLDoor);
|
||||
//SetupUrl("BtnPatreon", URLPatreon);
|
||||
|
||||
UpdatePanel(notesPanel);
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using HurricaneVR.Framework.Core.Grabbers;
|
||||
using HurricaneVR.Framework.Core.Sockets;
|
||||
using HurricaneVR.Framework.Core.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HurricaneVR.Editor
|
||||
{
|
||||
[CustomEditor(typeof(HVRSocketable), editorForChildClasses: true)]
|
||||
public class HVRSocketableEditor : UnityEditor.Editor
|
||||
{
|
||||
private bool _expand;
|
||||
private HVRSocket _socket;
|
||||
private HVRSocketable component;
|
||||
|
||||
private Vector3 _pos;
|
||||
private Quaternion _rot;
|
||||
|
||||
private static Dictionary<HVRSocketable, HVRSocket> _cache = new Dictionary<HVRSocketable, HVRSocket>();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
component = target as HVRSocketable;
|
||||
if (_cache.TryGetValue(component, out var socket))
|
||||
{
|
||||
_socket = socket;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
// _expand = EditorGUILayout.Foldout(_expand, "Posing Interface");
|
||||
EditorGUILayout.LabelField("Posing:");
|
||||
//if (_expand)
|
||||
{
|
||||
var temp = _socket;
|
||||
HVREditorExtensions.ObjectField("Socket", ref _socket);
|
||||
|
||||
|
||||
|
||||
if (_socket)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_socket.PoseTag))
|
||||
{
|
||||
EditorGUILayout.HelpBox("Socket's PoseTag field is not assigned.", MessageType.Warning);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if (GUILayout.Button("Snapshot Transform"))
|
||||
// {
|
||||
// _pos = component.transform.position;
|
||||
// _rot = component.transform.rotation;
|
||||
// }
|
||||
//
|
||||
// if (GUILayout.Button("Restore Transform"))
|
||||
// {
|
||||
// Undo.RecordObject(component.transform, "Restore Socketable");
|
||||
// component.transform.SetPositionAndRotation(_pos, _rot);
|
||||
// }
|
||||
|
||||
if (_socket.ScaleGrabbable)
|
||||
{
|
||||
if (GUILayout.Button("Apply Socket Scale"))
|
||||
{
|
||||
Undo.RecordObject(component.transform, "Editor Socket Scale");
|
||||
component.transform.localScale = _socket.ComputeScale(component);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Reset Scale"))
|
||||
{
|
||||
Undo.RecordObject(component.transform, "Editor Socket Scale");
|
||||
component.transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (GUILayout.Button("Move to Socket"))
|
||||
{
|
||||
Undo.RecordObject(component.transform, "Move to Socket");
|
||||
component.transform.position = _socket.transform.position;
|
||||
component.transform.rotation = _socket.transform.rotation;
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Save Pose"))
|
||||
{
|
||||
var poses = serializedObject.FindProperty("Poses");
|
||||
var i = component.Poses.FindIndex(e => e.SocketTag == _socket.PoseTag);
|
||||
if (i < 0)
|
||||
{
|
||||
i = poses.arraySize;
|
||||
poses.InsertArrayElementAtIndex(i);
|
||||
}
|
||||
|
||||
var pose = poses.GetArrayElementAtIndex(i);
|
||||
pose.FindPropertyRelative("Position").vector3Value = _socket.transform.InverseTransformPoint(component.transform.position);
|
||||
pose.FindPropertyRelative("EulerAngles").vector3Value = (Quaternion.Inverse(_socket.transform.rotation) * component.transform.rotation).eulerAngles;
|
||||
pose.FindPropertyRelative("SocketTag").stringValue = _socket.PoseTag;
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(GUILayout.Button("Find Closest Socket"))
|
||||
{
|
||||
var dist = float.MaxValue;
|
||||
HVRSocket closest = null;
|
||||
foreach (var socket in FindObjectsOfType<HVRSocket>())
|
||||
{
|
||||
if (socket.transform.IsChildOf(component.transform))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var d = Vector3.Distance(component.transform.position, socket.transform.position);
|
||||
if (d < dist)
|
||||
{
|
||||
dist = d;
|
||||
closest = socket;
|
||||
}
|
||||
}
|
||||
|
||||
_socket = closest;
|
||||
}
|
||||
}
|
||||
|
||||
if (temp && !_socket)
|
||||
{
|
||||
_cache[component] = null;
|
||||
}
|
||||
else if (!temp && _socket)
|
||||
{
|
||||
_cache[component] = _socket;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Space();
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50bc40950ea34e579fb36b46f4d10e85
|
||||
timeCreated: 1661143344
|
||||
@@ -8,15 +8,20 @@ namespace HurricaneVR.Editor
|
||||
public class HVRSocketableTagsEditor : UnityEditor.Editor
|
||||
{
|
||||
private HVRSocketableTags tags;
|
||||
private SerializedProperty SPIdentifier;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
tags = target as HVRSocketableTags;
|
||||
SPIdentifier = serializedObject.FindProperty(nameof(HVRSocketableTags.Identifier));
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
|
||||
EditorGUILayout.PropertyField(SPIdentifier);
|
||||
|
||||
GUILayout.Space(5);
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
{
|
||||
"name": "HurricaneVR.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"HurricaneVR.Framework",
|
||||
"Zero"
|
||||
"HurricaneVR.Framework"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:BindableElement name="BlendEditorRoot" style="height: auto; flex-grow: 1;">
|
||||
<ui:BindableElement name="BlendEditorRoot" class="unity-box" style="height: auto; flex-grow: 1;">
|
||||
<Style src="HVRBlendEditor.uss" />
|
||||
<ui:VisualElement style="margin-top: 4px;">
|
||||
<ui:Label text="Label" name="lblSelectedPose" style="font-size: 20px; -unity-font-style: bold; margin-left: 8px;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement class="HandsContainer">
|
||||
<ui:VisualElement name="CurlContainer" class="unity-box CurlContainer" style="flex-grow: 1;">
|
||||
<ui:Label text="Finger Curls:" class="HandLabel" />
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
<ui:ListView name="Poses" style="flex-grow: 5;" />
|
||||
</ui:VisualElement>
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="warning">
|
||||
<ui:Label text="Posing is not available while in Prefab Mode." style="height: 46px; color: rgb(217, 183, 9); -unity-font-style: bold; font-size: 20px; white-space: normal; margin-bottom: 10px;" />
|
||||
</ui:VisualElement>
|
||||
<uie:EnumField label="MirrorAxis" value="X" name="MirrorAxis" binding-path="MirrorAxis" />
|
||||
<ui:Instance template="HandSettingsTemplate" />
|
||||
<ui:Instance template="HandSettingsTemplate" name="boxPreview" />
|
||||
<ui:Instance template="BlendEditorTemplate" />
|
||||
</ui:Box>
|
||||
</ui:UXML>
|
||||
|
||||
+4
-1
@@ -1,6 +1,9 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:VisualElement>
|
||||
<Style src="HVRHandPoserEditor.uss" />
|
||||
<ui:VisualElement name="lblAutoPoseWarning">
|
||||
<ui:Label text="Rigidbody detected, if dynamic posing doesn't work, remove it temporarily." style="font-size: 18px; color: rgb(250, 235, 20); flex-wrap: nowrap; margin-bottom: 10px; height: 50px; white-space: normal;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement class="HandsContainer">
|
||||
<ui:VisualElement name="LeftHandContainer" class="unity-box HandContainer">
|
||||
<ui:Label text="Left Hand:" class="HandLabel" />
|
||||
@@ -25,7 +28,7 @@
|
||||
<ui:Button name="ButtonOpenRight" text="Open" class="HandMirrorButton" style="flex-basis: auto; flex-grow: 1;" />
|
||||
<ui:Button name="ButtonCloseRight" text="Close" class="HandMirrorButton" style="flex-grow: 1; flex-basis: auto;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement style="flex-direction: row; flex-basis: 28px;">
|
||||
<ui:VisualElement style="flex-direction: row; flex-basis: 28px; flex-wrap: wrap;">
|
||||
<ui:Button name="ButtonMirrorLeft" text="Mirror" class="HandMirrorButton" style="flex-basis: auto; flex-grow: 1;" />
|
||||
<ui:Button name="ButtonFocusRight" text="Focus" class="HandMirrorButton" style="flex-grow: 1; flex-basis: auto;" />
|
||||
<ui:Button name="RightExpand" text="+" class="HandMirrorButton" style="flex-grow: 1; flex-basis: auto;" />
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<ui:Button text="Grabbable w/ Pose" name="BtnTutBasicGrabbable" class="tutorial-button docs-button" />
|
||||
<ui:Button text="Sockets" name="btnSockets" class="docs-button" />
|
||||
<ui:Button text="FinalIK (VRIK)" name="BtnVRIKSetup" class="docs-button" />
|
||||
<ui:Button text="Custom Hand Setup" name="btnCustomHand" class="docs-button" />
|
||||
<ui:Button text="Door Setup" name="btnDoorSetup" class="docs-button" />
|
||||
<ui:Label text="Other" style="padding-top: 12px;" />
|
||||
<ui:Button text="Discord Server" name="btnDiscord" class="docs-button" />
|
||||
</ui:VisualElement>
|
||||
|
||||
Reference in New Issue
Block a user