diff --git a/CustomAvatar-Editor/CustomAvatar-Editor.csproj b/CustomAvatar-Editor/CustomAvatar-Editor.csproj index 9c8fbe9..7810c8d 100644 --- a/CustomAvatar-Editor/CustomAvatar-Editor.csproj +++ b/CustomAvatar-Editor/CustomAvatar-Editor.csproj @@ -140,6 +140,7 @@ - copy "$(TargetDir)$(TargetName).dll" "$(BeatSaberUnityProject)\Assets\" + + \ No newline at end of file diff --git a/CustomAvatar/AvatarBehaviour.cs b/CustomAvatar/AvatarBehaviour.cs index 29cc29d..8062990 100644 --- a/CustomAvatar/AvatarBehaviour.cs +++ b/CustomAvatar/AvatarBehaviour.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using System; +using UnityEngine; namespace CustomAvatar { @@ -8,54 +9,101 @@ public class AvatarBehaviour : MonoBehaviour private Transform _head; private Transform _body; - private Transform _left; - private Transform _right; + private Transform _leftHand; + private Transform _rightHand; + private Transform _leftLeg; + private Transform _rightLeg; + private Transform _pelvis; private Vector3 _prevBodyPos; + private Vector3 _prevLeftLegPos = default(Vector3); + private Vector3 _prevRightLegPos = default(Vector3); + private Quaternion _prevLeftLegRot = default(Quaternion); + private Quaternion _prevRightLegRot = default(Quaternion); + + private Vector3 _prevPelvisPos = default(Vector3); + private Quaternion _prevPelvisRot = default(Quaternion); + public void Init(IAvatarInput avatarInput) { _avatarInput = avatarInput; _head = GetHeadTransform(); _body = gameObject.transform.Find("Body"); - _left = gameObject.transform.Find("LeftHand"); - _right = gameObject.transform.Find("RightHand"); + _leftHand = gameObject.transform.Find("LeftHand"); + _rightHand = gameObject.transform.Find("RightHand"); + _leftLeg = gameObject.transform.Find("LeftLeg"); + _rightLeg = gameObject.transform.Find("RightLeg"); + _pelvis = gameObject.transform.Find("Pelvis"); } private void LateUpdate() { - var headPosRot = _avatarInput.HeadPosRot; - var leftPosRot = _avatarInput.LeftPosRot; - var rightPosRot = _avatarInput.RightPosRot; - - _head.position = headPosRot.Position; - _head.rotation = headPosRot.Rotation; - - _left.position = leftPosRot.Position; - _left.rotation = leftPosRot.Rotation; - - _right.position = rightPosRot.Position; - _right.rotation = rightPosRot.Rotation; - - var vrPlatformHelper = PersistentSingleton.instance; - - vrPlatformHelper.AdjustPlatformSpecificControllerTransform(_left); - vrPlatformHelper.AdjustPlatformSpecificControllerTransform(_right); - - if (_body == null) return; - _body.position = _head.position - (_head.transform.up * 0.1f); - - var vel = new Vector3(_body.transform.localPosition.x - _prevBodyPos.x, 0.0f, - _body.localPosition.z - _prevBodyPos.z); - - var rot = Quaternion.Euler(0.0f, _head.localEulerAngles.y, 0.0f); - var tiltAxis = Vector3.Cross(gameObject.transform.up, vel); - _body.localRotation = Quaternion.Lerp(_body.localRotation, - Quaternion.AngleAxis(vel.magnitude * 1250.0f, tiltAxis) * rot, - Time.deltaTime * 10.0f); - - _prevBodyPos = _body.transform.localPosition; + try + { + var headPosRot = _avatarInput.HeadPosRot; + var leftPosRot = _avatarInput.LeftPosRot; + var rightPosRot = _avatarInput.RightPosRot; + + _head.position = headPosRot.Position; + _head.rotation = headPosRot.Rotation; + + _leftHand.position = leftPosRot.Position; + _leftHand.rotation = leftPosRot.Rotation; + + _rightHand.position = rightPosRot.Position; + _rightHand.rotation = rightPosRot.Rotation; + + if (_leftLeg != null && _rightLeg != null && _avatarInput is IAvatarFullBodyInput) + { + var _fbinput = _avatarInput as IAvatarFullBodyInput; + var leftLegPosRot = _fbinput.LeftLegPosRot; + var rightLegPosRot = _fbinput.RightLegPosRot; + _prevLeftLegPos = Vector3.Lerp(_prevLeftLegPos, leftLegPosRot.Position, 15 * Time.deltaTime); + _prevLeftLegRot = Quaternion.Slerp(_prevLeftLegRot, leftLegPosRot.Rotation, 10 * Time.deltaTime); + _leftLeg.position = _prevLeftLegPos; + _leftLeg.rotation = _prevLeftLegRot; + + _prevRightLegPos = Vector3.Lerp(_prevRightLegPos, rightLegPosRot.Position, 15 * Time.deltaTime); + _prevRightLegRot = Quaternion.Slerp(_prevRightLegRot, rightLegPosRot.Rotation, 10 * Time.deltaTime); + _rightLeg.position = _prevRightLegPos; + _rightLeg.rotation = _prevRightLegRot; + } + + if(_pelvis != null && _avatarInput is IAvatarFullBodyInput) + { + var _fbinput = _avatarInput as IAvatarFullBodyInput; + var pelvisPosRot = _fbinput.PelvisPosRot; + + _prevPelvisPos = Vector3.Lerp(_prevPelvisPos, pelvisPosRot.Position, 17 * Time.deltaTime); + _prevPelvisRot = Quaternion.Slerp(_prevPelvisRot, pelvisPosRot.Rotation, 13 * Time.deltaTime); + _pelvis.position = _prevPelvisPos; + _pelvis.rotation = _prevPelvisRot; + } + + var vrPlatformHelper = PersistentSingleton.instance; + + vrPlatformHelper.AdjustPlatformSpecificControllerTransform(_leftHand); + vrPlatformHelper.AdjustPlatformSpecificControllerTransform(_rightHand); + + if (_body == null) return; + _body.position = _head.position - (_head.transform.up * 0.1f); + + var vel = new Vector3(_body.transform.localPosition.x - _prevBodyPos.x, 0.0f, + _body.localPosition.z - _prevBodyPos.z); + + var rot = Quaternion.Euler(0.0f, _head.localEulerAngles.y, 0.0f); + var tiltAxis = Vector3.Cross(gameObject.transform.up, vel); + _body.localRotation = Quaternion.Lerp(_body.localRotation, + Quaternion.AngleAxis(vel.magnitude * 1250.0f, tiltAxis) * rot, + Time.deltaTime * 10.0f); + + _prevBodyPos = _body.transform.localPosition; + } catch(Exception e) + { + Console.WriteLine("{0}\n{1}", e.Message, e.StackTrace); + } } private Transform GetHeadTransform() @@ -69,4 +117,4 @@ private Transform GetHeadTransform() return gameObject.transform.Find("Head"); } } -} \ No newline at end of file +} diff --git a/CustomAvatar/AvatarEventsPlayer.cs b/CustomAvatar/AvatarEventsPlayer.cs index e861741..e8ff650 100644 --- a/CustomAvatar/AvatarEventsPlayer.cs +++ b/CustomAvatar/AvatarEventsPlayer.cs @@ -1,18 +1,18 @@ using System; using System.Linq; -using System.Reflection; using UnityEngine; +using UnityEngine.SceneManagement; namespace CustomAvatar { - public class AvatarEventsPlayer : MonoBehaviour - { - private EventManager _eventManager; - - private ScoreController _scoreController; - private ObstacleSaberSparkleEffectManager _saberCollisionManager; - private GameEnergyCounter _gameEnergyCounter; - private BeatmapObjectCallbackController _beatmapObjectCallbackController; + public class AvatarEventsPlayer : MonoBehaviour + { + private EventManager _eventManager; + + private ScoreController _scoreController; + private ObstacleSaberSparkleEffectManager _saberCollisionManager; + private GameEnergyCounter _gameEnergyCounter; + private BeatmapObjectCallbackController _beatmapObjectCallbackController; private BeatmapDataModel _beatmapDataModel; private int _lastNoteId = -1; @@ -24,69 +24,95 @@ public void Restart() private void _Restart() { - OnDestroy(); - Start(); + CleanUp(); } - private void Start() - { - _eventManager = gameObject.GetComponent(); - if (_eventManager == null) - _eventManager = gameObject.AddComponent(); + private void OnEnable() + { + SceneManager.sceneLoaded += SceneManagerOnSceneLoaded; + + _eventManager = gameObject.GetComponent(); + } + + private void OnDisable() + { + SceneManager.sceneLoaded -= SceneManagerOnSceneLoaded; + } + + private void OnDestroy() + { + CleanUp(); + } + + private void CleanUp() + { + if (_scoreController) + { + _scoreController.noteWasCutEvent -= SliceCallBack; + _scoreController.noteWasMissedEvent -= NoteMissCallBack; + _scoreController.multiplierDidChangeEvent -= MultiplierCallBack; + _scoreController.comboDidChangeEvent -= ComboChangeEvent; + } + + if (_saberCollisionManager) + { + _saberCollisionManager.sparkleEffectDidStartEvent -= SaberStartCollide; + _saberCollisionManager.sparkleEffectDidEndEvent -= SaberEndCollide; + } + + if (_gameEnergyCounter) + _gameEnergyCounter.gameEnergyDidReach0Event -= FailLevelCallBack; + + if (_beatmapObjectCallbackController) + _beatmapObjectCallbackController.beatmapEventDidTriggerEvent -= OnBeatmapEventDidTriggerEvent; + + if (_beatmapDataModel) + _beatmapDataModel.beatmapDataDidChangeEvent -= BeatmapDataChangedCallback; + } + + private void SceneManagerOnSceneLoaded(Scene newScene, LoadSceneMode mode) + { + _eventManager = gameObject.GetComponent(); + if (_eventManager == null) + _eventManager = gameObject.AddComponent(); _scoreController = Resources.FindObjectsOfTypeAll().FirstOrDefault(); - if (_scoreController == null) return; + if (_scoreController == null) return; //_eventManager.OnLevelStart?.Invoke(); // replaced by LevelStartedEvent() _saberCollisionManager = - Resources.FindObjectsOfTypeAll().FirstOrDefault(); - _gameEnergyCounter = Resources.FindObjectsOfTypeAll().FirstOrDefault(); - _beatmapObjectCallbackController = Resources.FindObjectsOfTypeAll().FirstOrDefault(); + Resources.FindObjectsOfTypeAll().FirstOrDefault(); + _gameEnergyCounter = Resources.FindObjectsOfTypeAll().FirstOrDefault(); + _beatmapObjectCallbackController = Resources.FindObjectsOfTypeAll().FirstOrDefault(); _beatmapDataModel = Resources.FindObjectsOfTypeAll().FirstOrDefault(); - _scoreController.noteWasCutEvent += SliceCallBack; - _scoreController.noteWasMissedEvent += NoteMissCallBack; - _scoreController.multiplierDidChangeEvent += MultiplierCallBack; - _scoreController.comboDidChangeEvent += ComboChangeEvent; + _scoreController.noteWasCutEvent += SliceCallBack; + _scoreController.noteWasMissedEvent += NoteMissCallBack; + _scoreController.multiplierDidChangeEvent += MultiplierCallBack; + _scoreController.comboDidChangeEvent += ComboChangeEvent; - if (_saberCollisionManager != null) - { - _saberCollisionManager.sparkleEffectDidStartEvent += SaberStartCollide; - _saberCollisionManager.sparkleEffectDidEndEvent += SaberEndCollide; - } + if (_saberCollisionManager) + { + _saberCollisionManager.sparkleEffectDidStartEvent += SaberStartCollide; + _saberCollisionManager.sparkleEffectDidEndEvent += SaberEndCollide; + } - if (_gameEnergyCounter != null) _gameEnergyCounter.gameEnergyDidReach0Event += FailLevelCallBack; + if (_gameEnergyCounter) _gameEnergyCounter.gameEnergyDidReach0Event += FailLevelCallBack; - if (_beatmapObjectCallbackController != null) + if (_beatmapObjectCallbackController) _beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTriggerEvent; _lastNoteId = -1; - if (_beatmapDataModel != null) + if (_beatmapDataModel) { _beatmapDataModel.beatmapDataDidChangeEvent += BeatmapDataChangedCallback; BeatmapDataChangedCallback(); } } - private void OnDestroy() - { - if (_scoreController == null) return; - _scoreController.noteWasCutEvent -= SliceCallBack; - _scoreController.noteWasMissedEvent -= NoteMissCallBack; - _scoreController.multiplierDidChangeEvent -= MultiplierCallBack; - _scoreController.comboDidChangeEvent -= ComboChangeEvent; - - _saberCollisionManager.sparkleEffectDidStartEvent -= SaberStartCollide; - _saberCollisionManager.sparkleEffectDidEndEvent -= SaberEndCollide; - - _gameEnergyCounter.gameEnergyDidReach0Event -= FailLevelCallBack; - _beatmapObjectCallbackController.beatmapEventDidTriggerEvent -= OnBeatmapEventDidTriggerEvent; - _beatmapDataModel.beatmapDataDidChangeEvent -= BeatmapDataChangedCallback; - } - private void BeatmapDataChangedCallback() { if (_beatmapDataModel.beatmapData == null) return; @@ -98,80 +124,80 @@ private void BeatmapDataChangedCallback() } private void SliceCallBack(NoteData noteData, NoteCutInfo noteCutInfo, int multiplier) - { - if (!noteCutInfo.allIsOK) - { - _eventManager.OnComboBreak?.Invoke(); - } - else - { - _eventManager.OnSlice?.Invoke(); - } + { + if (!noteCutInfo.allIsOK) + { + _eventManager?.OnComboBreak?.Invoke(); + } + else + { + _eventManager?.OnSlice?.Invoke(); + } if (noteData.id == _lastNoteId) { - _eventManager.OnLevelFinish?.Invoke(); + _eventManager?.OnLevelFinish?.Invoke(); } - } - - private void NoteMissCallBack(NoteData noteData, int multiplier) - { - if (noteData.noteType != NoteType.Bomb) - { - _eventManager.OnComboBreak?.Invoke(); - } - } - - private void MultiplierCallBack(int multiplier, float progress) - { - if (multiplier > 1 && progress < 0.1f) - { - _eventManager.MultiplierUp?.Invoke(); - } - } - - private void SaberStartCollide(Saber.SaberType saber) - { - _eventManager.SaberStartColliding?.Invoke(); - } - - private void SaberEndCollide(Saber.SaberType saber) - { - _eventManager.SaberStopColliding?.Invoke(); - } - - private void FailLevelCallBack() - { - _eventManager.OnLevelFail?.Invoke(); - } - - private void OnBeatmapEventDidTriggerEvent (BeatmapEventData beatmapEventData) - { - if ((int) beatmapEventData.type >= 5) return; - - if (beatmapEventData.value > 0 && beatmapEventData.value < 4) - { - _eventManager.OnBlueLightOn?.Invoke(); - } - - if (beatmapEventData.value > 4 && beatmapEventData.value < 8) - { - _eventManager.OnRedLightOn?.Invoke(); - } - } - - private void ComboChangeEvent(int combo) - { - _eventManager.OnComboChanged?.Invoke(combo); + } + + private void NoteMissCallBack(NoteData noteData, int multiplier) + { + if (noteData.noteType != NoteType.Bomb) + { + _eventManager?.OnComboBreak?.Invoke(); + } + } + + private void MultiplierCallBack(int multiplier, float progress) + { + if (multiplier > 1 && progress < 0.1f) + { + _eventManager?.MultiplierUp?.Invoke(); + } + } + + private void SaberStartCollide(Saber.SaberType saber) + { + _eventManager?.SaberStartColliding?.Invoke(); + } + + private void SaberEndCollide(Saber.SaberType saber) + { + _eventManager?.SaberStopColliding?.Invoke(); + } + + private void FailLevelCallBack() + { + _eventManager?.OnLevelFail?.Invoke(); + } + + private void OnBeatmapEventDidTriggerEvent(BeatmapEventData beatmapEventData) + { + if (beatmapEventData == null || (int) beatmapEventData.type >= 5) return; + + if (beatmapEventData.value > 0 && beatmapEventData.value < 4) + { + _eventManager?.OnBlueLightOn?.Invoke(); + } + + if (beatmapEventData.value > 4 && beatmapEventData.value < 8) + { + _eventManager?.OnRedLightOn?.Invoke(); + } + } + + private void ComboChangeEvent(int combo) + { + _eventManager?.OnComboChanged?.Invoke(combo); } public void MenuEnteredEvent() { - _eventManager.OnMenuEnter?.Invoke(); + _eventManager?.OnMenuEnter?.Invoke(); } public void LevelStartedEvent() { - _eventManager.OnLevelStart?.Invoke(); + _eventManager?.OnLevelStart?.Invoke(); } } } diff --git a/CustomAvatar/AvatarSpawner.cs b/CustomAvatar/AvatarSpawner.cs index bedc31a..fadbd50 100644 --- a/CustomAvatar/AvatarSpawner.cs +++ b/CustomAvatar/AvatarSpawner.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; namespace CustomAvatar { @@ -26,4 +26,4 @@ public static SpawnedAvatar SpawnAvatar(CustomAvatar customAvatar, IAvatarInput return spawnedAvatar; } } -} \ No newline at end of file +} diff --git a/CustomAvatar/CustomAvatar.cs b/CustomAvatar/CustomAvatar.cs index 3d5ee13..dd31838 100644 --- a/CustomAvatar/CustomAvatar.cs +++ b/CustomAvatar/CustomAvatar.cs @@ -1,4 +1,4 @@ -using System; +using System; using UnityEngine; namespace CustomAvatar @@ -104,4 +104,4 @@ void Loaded(AvatarLoadResult result) _assetBundle.LoadAssetBundle(Loaded); } } -} \ No newline at end of file +} diff --git a/CustomAvatar/CustomAvatar.csproj b/CustomAvatar/CustomAvatar.csproj index 53a5c9b..ad23eba 100644 --- a/CustomAvatar/CustomAvatar.csproj +++ b/CustomAvatar/CustomAvatar.csproj @@ -51,31 +51,27 @@ PLUGIN - - - - - + + + False + E:\Steam7\steamapps\common\Beat Saber\Plugins\BeatSaberCustomUI.dll + - - False - - - - - - - - - - False - - - + + + + + + + + + + + @@ -93,6 +89,7 @@ + @@ -103,6 +100,7 @@ + diff --git a/CustomAvatar/EventManager.cs b/CustomAvatar/EventManager.cs index ef16241..08904da 100644 --- a/CustomAvatar/EventManager.cs +++ b/CustomAvatar/EventManager.cs @@ -4,25 +4,25 @@ namespace CustomAvatar { - public class EventManager : MonoBehaviour - { - public UnityEvent OnSlice; - public UnityEvent OnComboBreak; - public UnityEvent MultiplierUp; - public UnityEvent SaberStartColliding; - public UnityEvent SaberStopColliding; - public UnityEvent OnMenuEnter; - public UnityEvent OnLevelStart; - public UnityEvent OnLevelFail; + public class EventManager : MonoBehaviour + { + public UnityEvent OnSlice; + public UnityEvent OnComboBreak; + public UnityEvent MultiplierUp; + public UnityEvent SaberStartColliding; + public UnityEvent SaberStopColliding; + public UnityEvent OnMenuEnter; + public UnityEvent OnLevelStart; + public UnityEvent OnLevelFail; public UnityEvent OnLevelFinish; public UnityEvent OnBlueLightOn; - public UnityEvent OnRedLightOn; + public UnityEvent OnRedLightOn; - [Serializable] - public class ComboChangedEvent : UnityEvent - { - } + [Serializable] + public class ComboChangedEvent : UnityEvent + { + } - public ComboChangedEvent OnComboChanged = new ComboChangedEvent(); - } + public ComboChangedEvent OnComboChanged = new ComboChangedEvent(); + } } diff --git a/CustomAvatar/IAvatarFullBodyInput.cs b/CustomAvatar/IAvatarFullBodyInput.cs new file mode 100644 index 0000000..c76fb36 --- /dev/null +++ b/CustomAvatar/IAvatarFullBodyInput.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CustomAvatar +{ + interface IAvatarFullBodyInput:IAvatarInput + { + PosRot LeftLegPosRot { get; } + PosRot RightLegPosRot { get; } + PosRot PelvisPosRot { get; } + } +} diff --git a/CustomAvatar/IAvatarInput.cs b/CustomAvatar/IAvatarInput.cs index afba6f0..6288e9e 100644 --- a/CustomAvatar/IAvatarInput.cs +++ b/CustomAvatar/IAvatarInput.cs @@ -1,4 +1,4 @@ -namespace CustomAvatar +namespace CustomAvatar { public interface IAvatarInput { @@ -6,4 +6,4 @@ public interface IAvatarInput PosRot LeftPosRot { get; } PosRot RightPosRot { get; } } -} \ No newline at end of file +} diff --git a/CustomAvatar/PlayerAvatarInput.cs b/CustomAvatar/PlayerAvatarInput.cs index 57be21a..9ff05ea 100644 --- a/CustomAvatar/PlayerAvatarInput.cs +++ b/CustomAvatar/PlayerAvatarInput.cs @@ -1,9 +1,16 @@ -using UnityEngine.XR; +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.XR; namespace CustomAvatar { - public class PlayerAvatarInput : IAvatarInput + public class PlayerAvatarInput : IAvatarFullBodyInput { + public PlayerAvatarInput() + { + } + public PosRot HeadPosRot { get { return GetXRNodeWorldPosRot(XRNode.Head); } @@ -11,12 +18,70 @@ public PosRot HeadPosRot public PosRot LeftPosRot { - get { return GetXRNodeWorldPosRot(XRNode.LeftHand); } + get + { + if(Plugin.IsTrackerAsHand && Plugin.Trackers.Count >= 2) + return GetTrackerWorldPosRot(Plugin.Trackers[0]); + else + return GetXRNodeWorldPosRot(XRNode.LeftHand); + } } public PosRot RightPosRot { - get { return GetXRNodeWorldPosRot(XRNode.RightHand); } + get + { + if (Plugin.IsTrackerAsHand && Plugin.Trackers.Count >= 2) + return GetTrackerWorldPosRot(Plugin.Trackers[1]); + else + return GetXRNodeWorldPosRot(XRNode.RightHand); + } + } + + public PosRot LeftLegPosRot + { + get + { + if (Plugin.FullBodyTrackingType >= Plugin.TrackingType.Feet && Plugin.Trackers.Count >= 2) + { + return GetTrackerWorldPosRot(Plugin.Trackers[0]); + } + else + return new PosRot(new Vector3(), new Quaternion()); + } + } + + public PosRot RightLegPosRot + { + get + { + if (Plugin.FullBodyTrackingType >= Plugin.TrackingType.Feet && Plugin.Trackers.Count >= 2) + { + return GetTrackerWorldPosRot(Plugin.Trackers[1]); + } + else + return new PosRot(new Vector3(), new Quaternion()); + } + } + + public PosRot PelvisPosRot + { + get + { + if (Plugin.FullBodyTrackingType == Plugin.TrackingType.Hips && Plugin.Trackers.Count >= 1) + { + return GetTrackerWorldPosRot(Plugin.Trackers[0]); + } + else + { + if (Plugin.FullBodyTrackingType == Plugin.TrackingType.Full && Plugin.Trackers.Count >= 3) + { + return GetTrackerWorldPosRot(Plugin.Trackers[2]); + } + else + return new PosRot(new Vector3(), new Quaternion()); + } + } } private static PosRot GetXRNodeWorldPosRot(XRNode node) @@ -31,5 +96,34 @@ private static PosRot GetXRNodeWorldPosRot(XRNode node) rot = roomRotation * rot; return new PosRot(pos, rot); } + + private static PosRot GetTrackerWorldPosRot(XRNodeState tracker) + { + Vector3 pos = new Vector3(); + Quaternion rot = new Quaternion(); + try + { + var notes = new List(); + InputTracking.GetNodeStates(notes); + foreach (XRNodeState note in notes) + { + if (note.uniqueID != tracker.uniqueID) + continue; + if (note.TryGetPosition(out pos) && note.TryGetRotation(out rot)) + { + var roomCenter = BeatSaberUtil.GetRoomCenter(); + var roomRotation = BeatSaberUtil.GetRoomRotation(); + pos = roomRotation * pos; + pos += roomCenter; + rot = roomRotation * rot; + } + } + } + catch (Exception e) + { + Console.WriteLine(e.Message + "\n" + e.StackTrace); + } + return new PosRot(pos, rot); + } } -} \ No newline at end of file +} diff --git a/CustomAvatar/PlayerAvatarManager.cs b/CustomAvatar/PlayerAvatarManager.cs index ccf5313..24e5dec 100644 --- a/CustomAvatar/PlayerAvatarManager.cs +++ b/CustomAvatar/PlayerAvatarManager.cs @@ -51,6 +51,11 @@ public CustomAvatar GetCurrentAvatar() return CurrentPlayerAvatar; } + public SpawnedAvatar GetSpawnedAvatar() + { + return _currentSpawnedPlayerAvatar; + } + public void SwitchToAvatar(CustomAvatar customAvatar) { CurrentPlayerAvatar = customAvatar; @@ -148,8 +153,8 @@ private void SceneManagerOnSceneLoaded(Scene newScene, LoadSceneMode mode) { ResizePlayerAvatar(); OnFirstPersonEnabledChanged(Plugin.Instance.FirstPersonEnabled); - _currentSpawnedPlayerAvatar?.GameObject.GetComponentInChildren()?.Restart(); - } + _currentSpawnedPlayerAvatar?.GameObject.GetComponentInChildren()?.Restart(); + } public void OnSceneTransitioned(Scene newScene) { diff --git a/CustomAvatar/Plugin.cs b/CustomAvatar/Plugin.cs index 5c4bb18..eca95de 100644 --- a/CustomAvatar/Plugin.cs +++ b/CustomAvatar/Plugin.cs @@ -6,6 +6,7 @@ using IllusionPlugin; using UnityEngine; using UnityEngine.SceneManagement; +using UnityEngine.XR; namespace CustomAvatar { @@ -22,6 +23,62 @@ public class Plugin : IPlugin private WaitForSecondsRealtime _sceneLoadWait = new WaitForSecondsRealtime(0.1f); private GameScenesManager _scenesManager; + private static bool _isTrackerAsHand; + + public static List Trackers = new List(); + public static bool IsTrackerAsHand + { + get { return _isTrackerAsHand; } + set + { + _isTrackerAsHand = value; + List notes = new List(); + Trackers = new List(); + InputTracking.GetNodeStates(notes); + foreach (XRNodeState note in notes) + { + if (note.nodeType != XRNode.HardwareTracker || !InputTracking.GetNodeName(note.uniqueID).Contains("LHR-")) + continue; + Trackers.Add(note); + } + if (Trackers.Count == 0) + _isTrackerAsHand = false; + Console.WriteLine("IsTrackerAsHand : " + IsTrackerAsHand); + } + } + + public static bool IsFullBodyTracking + { + get { return Plugin.FullBodyTrackingType != Plugin.TrackingType.None; ; } + set + { + List notes = new List(); + Trackers = new List(); + InputTracking.GetNodeStates(notes); + foreach (XRNodeState note in notes) + { + if (note.nodeType != XRNode.HardwareTracker || !InputTracking.GetNodeName(note.uniqueID).Contains("LHR-")) + continue; + Trackers.Add(note); + } + if (Trackers.Count >= 0 && Trackers.Count <= 3) + Plugin.FullBodyTrackingType = (Plugin.TrackingType)Plugin.Trackers.Count; + else + Plugin.FullBodyTrackingType = Plugin.TrackingType.None; + var currentAvatar = Instance.PlayerAvatarManager.GetSpawnedAvatar(); + if (currentAvatar != null) + { + var _IKManagerAdvanced = currentAvatar.GameObject.GetComponentInChildren(true); + if (_IKManagerAdvanced != null) + { + _IKManagerAdvanced.CheckFullBodyTracking(); + } + } + bool isFullBodyTracking = Plugin.IsFullBodyTracking; + Console.WriteLine(string.Concat("IsFullBodyTracking : ", isFullBodyTracking.ToString())); + Console.WriteLine(string.Concat("FullBodyTrackingType: ", FullBodyTrackingType.ToString())); + } + } public Plugin() { @@ -60,6 +117,20 @@ public bool FirstPersonEnabled } } + public enum TrackingType + { + None, + Hips, + Feet, + Full + } + + public static Plugin.TrackingType FullBodyTrackingType + { + get; + set; + } + public bool RotatePreviewEnabled { get { return AvatarPreviewRotation.rotatePreview; } @@ -87,7 +158,7 @@ public string Name public string Version { - get { return "4.4.2"; } + get { return "4.6.0"; } } public static void Log(object message) @@ -143,6 +214,7 @@ private void AvatarsLoaded(IReadOnlyList loadedAvatars) PlayerAvatarManager = new PlayerAvatarManager(AvatarLoader, AvatarTailor, previousAvatar); PlayerAvatarManager.AvatarChanged += PlayerAvatarManagerOnAvatarChanged; + IsFullBodyTracking = true; } private void SceneManagerOnSceneLoaded(Scene newScene, LoadSceneMode mode) @@ -159,7 +231,11 @@ private void SceneManagerOnSceneLoaded(Scene newScene, LoadSceneMode mode) private void SceneTransitionDidFinish() { Camera mainCamera = Camera.main; - SetCameraCullingMask(mainCamera); + + if (mainCamera) + { + SetCameraCullingMask(mainCamera); + } PlayerAvatarManager?.OnSceneTransitioned(SceneManager.GetActiveScene()); } @@ -167,6 +243,7 @@ private void SceneTransitionDidFinish() private void PlayerAvatarManagerOnAvatarChanged(CustomAvatar newAvatar) { PlayerPrefs.SetString(PreviousAvatarKey, newAvatar.FullPath); + IsFullBodyTracking = IsFullBodyTracking; } public void OnUpdate() @@ -207,6 +284,14 @@ public void OnUpdate() { PlayerAvatarManager.IncrementPlayerGripOffsetZ(-1); } + else if (Input.GetKeyDown(KeyCode.F6)) + { + IsTrackerAsHand = !IsTrackerAsHand; + } + else if (Input.GetKeyDown(KeyCode.F5)) + { + IsFullBodyTracking = !IsFullBodyTracking; + } } private void SetCameraCullingMask(Camera camera) diff --git a/CustomAvatar/Properties/AssemblyInfo.cs b/CustomAvatar/Properties/AssemblyInfo.cs index 32eaeef..30299c3 100644 --- a/CustomAvatar/Properties/AssemblyInfo.cs +++ b/CustomAvatar/Properties/AssemblyInfo.cs @@ -23,13 +23,13 @@ // Version information for an assembly consists of the following four values: // -// Major Version -// Minor Version -// Build Number -// Revision +// Major Version +// Minor Version +// Build Number +// Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("4.4.2.0")] -[assembly: AssemblyFileVersion("4.4.2.0")] +[assembly: AssemblyVersion("4.6.0.0")] +[assembly: AssemblyFileVersion("4.6.0.0")] diff --git a/CustomAvatar/UI/AvatarCellInfo.cs b/CustomAvatar/UI/AvatarCellInfo.cs new file mode 100644 index 0000000..0911417 --- /dev/null +++ b/CustomAvatar/UI/AvatarCellInfo.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +namespace CustomAvatar +{ + class AvatarCellInfo : IPreviewBeatmapLevel + { + #region Aliases + + public string name { get; set; } + public string subName { get; set; } + public string authorName { get; set; } + + #endregion + + #region Properties + + public string levelID => null; + public string songName => name; + public string songSubName => subName; + public string songAuthorName => authorName; + public string levelAuthorName => null; + public float beatsPerMinute => 0f; + public float songTimeOffset => 0f; + public float shuffle => 0f; + public float shufflePeriod => 0f; + public AudioClip previewAudioClip => null; + public float previewStartTime => 0f; + public float previewDuration => 0f; + public float songDuration => 0f; + public Sprite coverImage { get; set; } + public SceneInfo environmentSceneInfo => null; + public BeatmapCharacteristicSO[] beatmapCharacteristics => new BeatmapCharacteristicSO[0]; + + #endregion + } +} diff --git a/CustomAvatar/UI/AvatarListViewController.cs b/CustomAvatar/UI/AvatarListViewController.cs index 2249932..df598d1 100644 --- a/CustomAvatar/UI/AvatarListViewController.cs +++ b/CustomAvatar/UI/AvatarListViewController.cs @@ -73,9 +73,9 @@ private void OnAvatarChanged(CustomAvatar avatar) private void SelectRowWithAvatar(CustomAvatar avatar, bool reload, bool scroll) { int currentRow = Plugin.Instance.AvatarLoader.IndexOf(avatar); - if (scroll) _tableView.ScrollToRow(currentRow, false); + if (scroll) _tableView.ScrollToCellWithIdx(currentRow, TableView.ScrollPositionType.Center, false); if (reload) _tableView.ReloadData(); - _tableView.SelectRow(currentRow); + _tableView.SelectCellWithIdx(currentRow); } public void LoadAllAvatars() @@ -167,7 +167,7 @@ private void FirstActivation() _tableView.SetPrivateField("_isInitialized", false); _tableView.dataSource = this; - _tableView.didSelectRowEvent += _TableView_DidSelectRowEvent; + _tableView.didSelectCellWithIdxEvent += _TableView_DidSelectRowEvent; tableViewObject.SetActive(true); @@ -219,38 +219,49 @@ public void DestroyPreview() Destroy(_previewParent); } - TableCell TableView.IDataSource.CellForRow(int row) + TableCell TableView.IDataSource.CellForIdx(int row) { LevelListTableCell tableCell = _tableView.DequeueReusableCellForIdentifier("AvatarListCell") as LevelListTableCell; if (tableCell == null) { tableCell = Instantiate(_tableCellTemplate); + + // remove level type icons + tableCell.transform.Find("LevelTypeIcon0").gameObject.SetActive(false); + tableCell.transform.Find("LevelTypeIcon1").gameObject.SetActive(false); + tableCell.transform.Find("LevelTypeIcon2").gameObject.SetActive(false); + tableCell.reuseIdentifier = "AvatarListCell"; } + + var cellInfo = new AvatarCellInfo(); + if (__AvatarLoadResults[row] != AvatarLoadResult.Completed) { - tableCell.songName = System.IO.Path.GetFileName(AvatarList[row].FullPath) +" failed to load"; - tableCell.author = "Make sure it's not a duplicate avatar."; - tableCell.coverImage = null; - return tableCell; + cellInfo.name = System.IO.Path.GetFileName(AvatarList[row].FullPath) +" failed to load"; + cellInfo.authorName = "Make sure it's not a duplicate avatar."; + cellInfo.coverImage = null; } else { try { - tableCell.songName = __AvatarNames[row]; - tableCell.author = __AvatarAuthors[row]; - tableCell.coverImage = __AvatarCovers[row] ?? Sprite.Create(Texture2D.blackTexture, new Rect(), Vector2.zero); + cellInfo.name = __AvatarNames[row]; + cellInfo.authorName = __AvatarAuthors[row]; + cellInfo.coverImage = __AvatarCovers[row] ?? Sprite.Create(Texture2D.blackTexture, new Rect(), Vector2.zero); } catch (Exception e) { - tableCell.songName = "If you see this yell at Assistant"; - tableCell.author = "because she fucked up"; - tableCell.coverImage = null; + cellInfo.name = "If you see this yell at Assistant"; + cellInfo.authorName = "because she fucked up"; + cellInfo.coverImage = null; Console.WriteLine(e); } - return tableCell; } + + tableCell.SetDataFromLevel(cellInfo); + + return tableCell; } @@ -271,7 +282,7 @@ public void GeneratePreview(int AvatarIndex) PreviewAvatar = __AvatarPrefabs[AvatarIndex]; _previewParent = new GameObject(); - _previewParent.transform.Translate(2f, 0, 1f); + _previewParent.transform.Translate(2, 0, 1.15f); _previewParent.transform.Rotate(0, -120, 0); _avatarPreview = Instantiate(PreviewAvatar, _previewParent.transform); @@ -317,7 +328,7 @@ public void GeneratePreview(int AvatarIndex) } - _previewParent.transform.Translate(0, 0.85f - (_previewHeightOffset), 0); + _previewParent.transform.Translate(0, 1 - (_previewHeightOffset), 0); _previewParent.transform.localScale = new Vector3(_previewScale, _previewScale, _previewScale); Destroy(_avatarPreview); @@ -350,14 +361,14 @@ public void GeneratePreview(int AvatarIndex) PreviewStatus = false; } - int TableView.IDataSource.NumberOfRows() + int TableView.IDataSource.NumberOfCells() { return AvatarList.Count; } - float TableView.IDataSource.RowHeight() + float TableView.IDataSource.CellSize() { - return 10f; + return 8.5f; } } } diff --git a/CustomAvatar/UI/AvatarUI.cs b/CustomAvatar/UI/AvatarUI.cs index b8d2986..f0b4e94 100644 --- a/CustomAvatar/UI/AvatarUI.cs +++ b/CustomAvatar/UI/AvatarUI.cs @@ -26,7 +26,7 @@ public AvatarUI() private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { - if (scene.name == "Menu") + if (scene.name == "MenuCore") { if (Plugin.Instance.AvatarLoader.Avatars.Count == 0) { diff --git a/CustomAvatar/VRIK/AxisTools.cs b/CustomAvatar/VRIK/AxisTools.cs index f069028..2df2638 100644 --- a/CustomAvatar/VRIK/AxisTools.cs +++ b/CustomAvatar/VRIK/AxisTools.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; namespace AvatarScriptPack { diff --git a/CustomAvatar/VRIK/DynamicBone.cs b/CustomAvatar/VRIK/DynamicBone.cs index 784a08d..a02162e 100644 --- a/CustomAvatar/VRIK/DynamicBone.cs +++ b/CustomAvatar/VRIK/DynamicBone.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using UnityEngine; diff --git a/CustomAvatar/VRIK/DynamicBoneCollider.cs b/CustomAvatar/VRIK/DynamicBoneCollider.cs index 42b261b..e1f3fa6 100644 --- a/CustomAvatar/VRIK/DynamicBoneCollider.cs +++ b/CustomAvatar/VRIK/DynamicBoneCollider.cs @@ -1,4 +1,4 @@ -using System; +using System; using UnityEngine; // Token: 0x02000004 RID: 4 diff --git a/CustomAvatar/VRIK/Hierarchy.cs b/CustomAvatar/VRIK/Hierarchy.cs index 0897848..5c75824 100644 --- a/CustomAvatar/VRIK/Hierarchy.cs +++ b/CustomAvatar/VRIK/Hierarchy.cs @@ -1,4 +1,4 @@ -using System; +using System; using UnityEngine; namespace AvatarScriptPack diff --git a/CustomAvatar/VRIK/IKManager.cs b/CustomAvatar/VRIK/IKManager.cs index b1046b8..924bed6 100644 --- a/CustomAvatar/VRIK/IKManager.cs +++ b/CustomAvatar/VRIK/IKManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,22 +6,22 @@ namespace AvatarScriptPack { - class IKManager : MonoBehaviour - { - public Transform HeadTarget; - public Transform LeftHandTarget; - public Transform RightHandTarget; + class IKManager : MonoBehaviour + { + public Transform HeadTarget; + public Transform LeftHandTarget; + public Transform RightHandTarget; - public void Start() - { - var vrik = this.gameObject.GetComponent(); + public void Start() + { + var vrik = this.gameObject.GetComponent(); - if (vrik != null) - { - vrik.solver.spine.headTarget = HeadTarget; - vrik.solver.leftArm.target = LeftHandTarget; - vrik.solver.rightArm.target = RightHandTarget; - } - } - } + if (vrik != null) + { + vrik.solver.spine.headTarget = HeadTarget; + vrik.solver.leftArm.target = LeftHandTarget; + vrik.solver.rightArm.target = RightHandTarget; + } + } + } } diff --git a/CustomAvatar/VRIK/IKManagerAdvanced.cs b/CustomAvatar/VRIK/IKManagerAdvanced.cs index f7bb2bc..31ded60 100644 --- a/CustomAvatar/VRIK/IKManagerAdvanced.cs +++ b/CustomAvatar/VRIK/IKManagerAdvanced.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -9,310 +9,379 @@ namespace AvatarScriptPack { - class IKManagerAdvanced : MonoBehaviour - { - [Tooltip("The head target.")] - public Transform HeadTarget; - [Tooltip("The hand target")] - public Transform LeftHandTarget; - [Tooltip("The hand target")] - public Transform RightHandTarget; + class IKManagerAdvanced : MonoBehaviour + { + [Space(5)] + [Header("IK Targets")] + [Tooltip("The head target.")] + public Transform HeadTarget; + [Tooltip("The hand target.")] + public Transform LeftHandTarget; + [Tooltip("The hand target.")] + public Transform RightHandTarget; + [Space(5)] + [Header("Full Body Tracking")] + [Tooltip("The pelvis target, useful with seated rigs.")] + public Transform Spine_pelvisTarget; + [Range(0f, 1f), Tooltip("Positional weight of the pelvis target.")] + public float Spine_pelvisPositionWeight; + [Range(0f, 1f), Tooltip("Rotational weight of the pelvis target.")] + public float Spine_pelvisRotationWeight; - [Space(20)] + [Tooltip("The toe/foot target.")] + public Transform LeftLeg_target; + [Range(0f, 1f), Tooltip("Positional weight of the toe/foot target.")] + public float LeftLeg_positionWeight; + [Range(0f, 1f), Tooltip("Rotational weight of the toe/foot target.")] + public float LeftLeg_rotationWeight; - /******************* - * Spine - ******************/ + [Tooltip("The toe/foot target.")] + public Transform RightLeg_target; + [Range(0f, 1f), Tooltip("Positional weight of the toe/foot target.")] + public float RightLeg_positionWeight; + [Range(0f, 1f), Tooltip("Rotational weight of the toe/foot target.")] + public float RightLeg_rotationWeight; - [Tooltip("The pelvis target, useful with seated rigs.")] - public Transform Spine_pelvisTarget; + [Space(20)] - [Range(0f, 1f), Tooltip("Positional weight of the head target.")] - public float Spine_positionWeight = 1f; + /******************* + * Spine + ******************/ - [Range(0f, 1f), Tooltip("Rotational weight of the head target.")] - public float Spine_rotationWeight = 1f; + [Range(0f, 1f), Tooltip("Positional weight of the head target.")] + public float Head_positionWeight = 1f; - [Range(0f, 1f), Tooltip("Positional weight of the pelvis target.")] - public float Spine_pelvisPositionWeight; + [Range(0f, 1f), Tooltip("Rotational weight of the head target.")] + public float Head_rotationWeight = 1f; - [Range(0f, 1f), Tooltip("Rotational weight of the pelvis target.")] - public float Spine_pelvisRotationWeight; + [Tooltip("If 'Chest Goal Weight' is greater than 0, the chest will be turned towards this Transform.")] + public Transform Spine_chestGoal; - [Tooltip("If 'Chest Goal Weight' is greater than 0, the chest will be turned towards this Transform.")] - public Transform Spine_chestGoal; + [Range(0f, 1f), Tooltip("Rotational weight of the chest target.")] + public float Spine_chestGoalWeight; - [Range(0f, 1f), Tooltip("Rotational weight of the chest target.")] - public float Spine_chestGoalWeight; + [Tooltip("Minimum height of the head from the root of the character.")] + public float Spine_minHeadHeight = 0.8f; - [Tooltip("Minimum height of the head from the root of the character.")] - public float Spine_minHeadHeight = 0.8f; + [Range(0f, 1f), Tooltip("Determines how much the body will follow the position of the head.")] + public float Spine_bodyPosStiffness = 0.55f; - [Range(0f, 1f), Tooltip("Determines how much the body will follow the position of the head.")] - public float Spine_bodyPosStiffness = 0.55f; + [Range(0f, 1f), Tooltip("Determines how much the body will follow the rotation of the head.")] + public float Spine_bodyRotStiffness = 0.1f; - [Range(0f, 1f), Tooltip("Determines how much the body will follow the rotation of the head.")] - public float Spine_bodyRotStiffness = 0.1f; + [Range(0f, 1f), FormerlySerializedAs("chestRotationWeight"), Tooltip("Determines how much the chest will rotate to the rotation of the head.")] + public float Spine_neckStiffness = 0.2f; - [Range(0f, 1f), FormerlySerializedAs("chestRotationWeight"), Tooltip("Determines how much the chest will rotate to the rotation of the head.")] - public float Spine_neckStiffness = 0.2f; + [Range(0f, 1f), Tooltip("Clamps chest rotation.")] + public float Spine_chestClampWeight = 0.5f; - [Range(0f, 1f), Tooltip("Clamps chest rotation.")] - public float Spine_chestClampWeight = 0.5f; + [Range(0f, 1f), Tooltip("Clamps head rotation.")] + public float Spine_headClampWeight = 0.6f; - [Range(0f, 1f), Tooltip("Clamps head rotation.")] - public float Spine_headClampWeight = 0.6f; + [Range(0f, 1f), Tooltip("How much will the pelvis maintain it's animated position?")] + public float Spine_maintainPelvisPosition = 0.2f; - [Range(0f, 1f), Tooltip("How much will the pelvis maintain it's animated position?")] - public float Spine_maintainPelvisPosition = 0.2f; + [Range(0f, 180f), Tooltip("Will automatically rotate the root of the character if the head target has turned past this angle.")] + public float Spine_maxRootAngle = 25f; - [Range(0f, 180f), Tooltip("Will automatically rotate the root of the character if the head target has turned past this angle.")] - public float Spine_maxRootAngle = 25f; + [Space(20)] - [Space(20)] + /******************* + * Left Arm + ******************/ - /******************* - * Left Arm - ******************/ + [Tooltip("The elbow will be bent towards this Transform if 'Bend Goal Weight' > 0.")] + public Transform LeftArm_bendGoal; - [Tooltip("The elbow will be bent towards this Transform if 'Bend Goal Weight' > 0.")] - public Transform LeftArm_bendGoal; + [Range(0f, 1f), Tooltip("Positional weight of the hand target.")] + public float LeftArm_positionWeight = 1f; - [Range(0f, 1f), Tooltip("Positional weight of the hand target.")] - public float LeftArm_positionWeight = 1f; + [Range(0f, 1f), Tooltip("Rotational weight of the hand target")] + public float LeftArm_rotationWeight = 1f; - [Range(0f, 1f), Tooltip("Rotational weight of the hand target")] - public float LeftArm_rotationWeight = 1f; + [Tooltip("Different techniques for shoulder bone rotation.")] + public IKSolverVR.Arm.ShoulderRotationMode LeftArm_shoulderRotationMode; - [Tooltip("Different techniques for shoulder bone rotation.")] - public IKSolverVR.Arm.ShoulderRotationMode LeftArm_shoulderRotationMode; + [Range(0f, 1f), Tooltip("The weight of shoulder rotation")] + public float LeftArm_shoulderRotationWeight = 1f; - [Range(0f, 1f), Tooltip("The weight of shoulder rotation")] - public float LeftArm_shoulderRotationWeight = 1f; + [Range(0f, 1f), Tooltip("If greater than 0, will bend the elbow towards the 'Bend Goal' Transform.")] + public float LeftArm_bendGoalWeight; - [Range(0f, 1f), Tooltip("If greater than 0, will bend the elbow towards the 'Bend Goal' Transform.")] - public float LeftArm_bendGoalWeight; + [Range(-180f, 180f), Tooltip("Angular offset of the elbow bending direction.")] + public float LeftArm_swivelOffset; - [Range(-180f, 180f), Tooltip("Angular offset of the elbow bending direction.")] - public float LeftArm_swivelOffset; + [Tooltip("Local axis of the hand bone that points from the wrist towards the palm. Used for defining hand bone orientation.")] + public Vector3 LeftArm_wristToPalmAxis = Vector3.zero; - [Tooltip("Local axis of the hand bone that points from the wrist towards the palm. Used for defining hand bone orientation.")] - public Vector3 LeftArm_wristToPalmAxis = Vector3.zero; + [Tooltip("Local axis of the hand bone that points from the palm towards the thumb. Used for defining hand bone orientation.")] + public Vector3 LeftArm_palmToThumbAxis = Vector3.zero; - [Tooltip("Local axis of the hand bone that points from the palm towards the thumb. Used for defining hand bone orientation.")] - public Vector3 LeftArm_palmToThumbAxis = Vector3.zero; + [Space(20)] - [Space(20)] + /******************* + * Right Arm + ******************/ - /******************* - * Right Arm - ******************/ + [Tooltip("The elbow will be bent towards this Transform if 'Bend Goal Weight' > 0.")] + public Transform RightArm_bendGoal; - [Tooltip("The elbow will be bent towards this Transform if 'Bend Goal Weight' > 0.")] - public Transform RightArm_bendGoal; + [Range(0f, 1f), Tooltip("Positional weight of the hand target.")] + public float RightArm_positionWeight = 1f; - [Range(0f, 1f), Tooltip("Positional weight of the hand target.")] - public float RightArm_positionWeight = 1f; + [Range(0f, 1f), Tooltip("Rotational weight of the hand target")] + public float RightArm_rotationWeight = 1f; - [Range(0f, 1f), Tooltip("Rotational weight of the hand target")] - public float RightArm_rotationWeight = 1f; + [Tooltip("Different techniques for shoulder bone rotation.")] + public IKSolverVR.Arm.ShoulderRotationMode RightArm_shoulderRotationMode; - [Tooltip("Different techniques for shoulder bone rotation.")] - public IKSolverVR.Arm.ShoulderRotationMode RightArm_shoulderRotationMode; + [Range(0f, 1f), Tooltip("The weight of shoulder rotation")] + public float RightArm_shoulderRotationWeight = 1f; - [Range(0f, 1f), Tooltip("The weight of shoulder rotation")] - public float RightArm_shoulderRotationWeight = 1f; + [Range(0f, 1f), Tooltip("If greater than 0, will bend the elbow towards the 'Bend Goal' Transform.")] + public float RightArm_bendGoalWeight; - [Range(0f, 1f), Tooltip("If greater than 0, will bend the elbow towards the 'Bend Goal' Transform.")] - public float RightArm_bendGoalWeight; + [Range(-180f, 180f), Tooltip("Angular offset of the elbow bending direction.")] + public float RightArm_swivelOffset; - [Range(-180f, 180f), Tooltip("Angular offset of the elbow bending direction.")] - public float RightArm_swivelOffset; + [Tooltip("Local axis of the hand bone that points from the wrist towards the palm. Used for defining hand bone orientation.")] + public Vector3 RightArm_wristToPalmAxis = Vector3.zero; - [Tooltip("Local axis of the hand bone that points from the wrist towards the palm. Used for defining hand bone orientation.")] - public Vector3 RightArm_wristToPalmAxis = Vector3.zero; + [Tooltip("Local axis of the hand bone that points from the palm towards the thumb. Used for defining hand bone orientation.")] + public Vector3 RightArm_palmToThumbAxis = Vector3.zero; - [Tooltip("Local axis of the hand bone that points from the palm towards the thumb. Used for defining hand bone orientation.")] - public Vector3 RightArm_palmToThumbAxis = Vector3.zero; + [Space(20)] - [Space(20)] + /******************* + * Left Leg + ******************/ - /******************* - * Left Leg - ******************/ + [Tooltip("The knee will be bent towards this Transform if 'Bend Goal Weight' > 0.")] + public Transform LeftLeg_bendGoal; - [Tooltip("The toe/foot target.")] - public Transform LeftLeg_target; + [Range(0f, 1f), Tooltip("If greater than 0, will bend the knee towards the 'Bend Goal' Transform.")] + public float LeftLeg_bendGoalWeight; - [Tooltip("The knee will be bent towards this Transform if 'Bend Goal Weight' > 0.")] - public Transform LeftLeg_bendGoal; + [Range(-180f, 180f), Tooltip("Angular offset of the knee bending direction.")] + public float LeftLeg_swivelOffset; - [Range(0f, 1f), Tooltip("Positional weight of the toe/foot target.")] - public float LeftLeg_positionWeight; + [Range(-180f, 180f), Tooltip("Rotation of the knee bend normal value.")] + public float LeftLeg_bendRotation; - [Range(0f, 1f), Tooltip("Rotational weight of the toe/foot target.")] - public float LeftLeg_rotationWeight; - [Range(0f, 1f), Tooltip("If greater than 0, will bend the knee towards the 'Bend Goal' Transform.")] - public float LeftLeg_bendGoalWeight; + [Space(20)] - [Range(-180f, 180f), Tooltip("Angular offset of the knee bending direction.")] - public float LeftLeg_swivelOffset; + /******************* + * Right Leg + ******************/ + [Tooltip("The knee will be bent towards this Transform if 'Bend Goal Weight' > 0.")] + public Transform RightLeg_bendGoal; - [Space(20)] + [Range(0f, 1f), Tooltip("If greater than 0, will bend the knee towards the 'Bend Goal' Transform.")] + public float RightLeg_bendGoalWeight; - /******************* - * Right Leg - ******************/ + [Range(-180f, 180f), Tooltip("Angular offset of the knee bending direction.")] + public float RightLeg_swivelOffset; - [Tooltip("The toe/foot target.")] - public Transform RightLeg_target; + [Range(-180f, 180f), Tooltip("Rotation of the knee bend normal value.")] + public float RightLeg_bendRotation; - [Tooltip("The knee will be bent towards this Transform if 'Bend Goal Weight' > 0.")] - public Transform RightLeg_bendGoal; - [Range(0f, 1f), Tooltip("Positional weight of the toe/foot target.")] - public float RightLeg_positionWeight; + [Space(20)] - [Range(0f, 1f), Tooltip("Rotational weight of the toe/foot target.")] - public float RightLeg_rotationWeight; + /******************* + * Locomotion + ******************/ - [Range(0f, 1f), Tooltip("If greater than 0, will bend the knee towards the 'Bend Goal' Transform.")] - public float RightLeg_bendGoalWeight; + [Range(0f, 1f), Tooltip("Used for blending in/out of procedural locomotion.")] + public float Locomotion_weight = 1f; - [Range(-180f, 180f), Tooltip("Angular offset of the knee bending direction.")] - public float RightLeg_swivelOffset; + [Tooltip("Tries to maintain this distance between the legs.")] + public float Locomotion_footDistance = 0.3f; + [Tooltip("Makes a step only if step target position is at least this far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past the 'Angle Threshold'.")] + public float Locomotion_stepThreshold = 0.4f; - [Space(20)] + [Tooltip("Makes a step only if step target position is at least 'Step Threshold' far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past this value.")] + public float Locomotion_angleThreshold = 60f; - /******************* - * Locomotion - ******************/ + [Tooltip("Multiplies angle of the center of mass - center of pressure vector. Larger value makes the character step sooner if losing balance.")] + public float Locomotion_comAngleMlp = 1f; - [Range(0f, 1f), Tooltip("Used for blending in/out of procedural locomotion.")] - public float Locomotion_weight = 1f; + [Tooltip("Maximum magnitude of head/hand target velocity used in prediction.")] + public float Locomotion_maxVelocity = 0.4f; - [Tooltip("Tries to maintain this distance between the legs.")] - public float Locomotion_footDistance = 0.3f; - - [Tooltip("Makes a step only if step target position is at least this far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past the 'Angle Threshold'.")] - public float Locomotion_stepThreshold = 0.4f; - - [Tooltip("Makes a step only if step target position is at least 'Step Threshold' far from the current footstep or the foot does not reach the current footstep anymore or footstep angle is past this value.")] - public float Locomotion_angleThreshold = 60f; - - [Tooltip("Multiplies angle of the center of mass - center of pressure vector. Larger value makes the character step sooner if losing balance.")] - public float Locomotion_comAngleMlp = 1f; - - [Tooltip("Maximum magnitude of head/hand target velocity used in prediction.")] - public float Locomotion_maxVelocity = 0.4f; - - [Tooltip("The amount of head/hand target velocity prediction.")] - public float Locomotion_velocityFactor = 0.4f; - - [Range(0.9f, 1f), Tooltip("How much can a leg be extended before it is forced to step to another position? 1 means fully stretched.")] - public float Locomotion_maxLegStretch = 1f; - - [Tooltip("The speed of lerping the root of the character towards the horizontal mid-point of the footsteps.")] - public float Locomotion_rootSpeed = 20f; - - [Tooltip("The speed of steps.")] - public float Locomotion_stepSpeed = 3f; - - [Tooltip("The height of the foot by normalized step progress (0 - 1).")] - public AnimationCurve Locomotion_stepHeight; - - [Tooltip("The height offset of the heel by normalized step progress (0 - 1).")] - public AnimationCurve Locomotion_heelHeight; - - [Range(0f, 180f), Tooltip("Rotates the foot while the leg is not stepping to relax the twist rotation of the leg if ideal rotation is past this angle.")] - public float Locomotion_relaxLegTwistMinAngle = 20f; - - [Tooltip("The speed of rotating the foot while the leg is not stepping to relax the twist rotation of the leg.")] - public float Locomotion_relaxLegTwistSpeed = 400f; - - [Tooltip("Interpolation mode of the step.")] - public InterpolationMode Locomotion_stepInterpolation = InterpolationMode.InOutSine; - - [Tooltip("Offset for the approximated center of mass.")] - public Vector3 Locomotion_offset; - - [Tooltip("Called when the left foot has finished a step.")] - public UnityEvent Locomotion_onLeftFootstep = new UnityEvent(); - - [Tooltip("Called when the right foot has finished a step")] - public UnityEvent Locomotion_onRightFootstep = new UnityEvent(); - - public void Start() - { - VRIK _VRIK = base.gameObject.GetComponent(); - if (_VRIK != null) - { - _VRIK.solver.spine.headTarget = this.HeadTarget; - _VRIK.solver.leftArm.target = this.LeftHandTarget; - _VRIK.solver.rightArm.target = this.RightHandTarget; - - Type type = this.GetType(); - FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.Public); - foreach (FieldInfo fieldInfo in fieldInfos) - { - string[] propertyName = fieldInfo.Name.Split('_'); - var value = fieldInfo.GetValue(this); - if (propertyName.Count() > 1) - { - if ("Spine" == propertyName[0]) - { - SetProperty(_VRIK.solver.spine, propertyName[1], value); - } - else if ("LeftArm" == propertyName[0]) - { - SetProperty(_VRIK.solver.leftArm, propertyName[1], value); - } - else if ("RightArm" == propertyName[0]) - { - SetProperty(_VRIK.solver.rightArm, propertyName[1], value); - } - else if ("LeftLeg" == propertyName[0]) - { - SetProperty(_VRIK.solver.leftLeg, propertyName[1], value); - } - else if ("RightLeg" == propertyName[0]) - { - SetProperty(_VRIK.solver.rightLeg, propertyName[1], value); - } - else if ("Locomotion" == propertyName[0]) - { - SetProperty(_VRIK.solver.locomotion, propertyName[1], value); - } - } - } - } - } - - public static void SetProperty(object obj, string fieldName, object value) - { - obj.GetType().GetField(fieldName).SetValue(obj, value); - } - - - public void ToggleLeftHandTarget(Transform leftHandTarget) - { - Console.WriteLine("ToggleLeftHandTarget"); - VRIK _VRIK = base.gameObject.GetComponent(); - if ("RightHand".Equals(_VRIK.solver.leftArm.target.parent.name)) - { - _VRIK.solver.leftArm.target = this.LeftHandTarget; - } - else - { - _VRIK.solver.leftArm.target = leftHandTarget; - } - } - } + [Tooltip("The amount of head/hand target velocity prediction.")] + public float Locomotion_velocityFactor = 0.4f; + + [Range(0.9f, 1f), Tooltip("How much can a leg be extended before it is forced to step to another position? 1 means fully stretched.")] + public float Locomotion_maxLegStretch = 1f; + + [Tooltip("The speed of lerping the root of the character towards the horizontal mid-point of the footsteps.")] + public float Locomotion_rootSpeed = 20f; + + [Tooltip("The speed of steps.")] + public float Locomotion_stepSpeed = 3f; + + [Tooltip("The height of the foot by normalized step progress (0 - 1).")] + public AnimationCurve Locomotion_stepHeight; + + [Tooltip("The height offset of the heel by normalized step progress (0 - 1).")] + public AnimationCurve Locomotion_heelHeight; + + [Range(0f, 180f), Tooltip("Rotates the foot while the leg is not stepping to relax the twist rotation of the leg if ideal rotation is past this angle.")] + public float Locomotion_relaxLegTwistMinAngle = 20f; + + [Tooltip("The speed of rotating the foot while the leg is not stepping to relax the twist rotation of the leg.")] + public float Locomotion_relaxLegTwistSpeed = 400f; + + [Tooltip("Interpolation mode of the step.")] + public InterpolationMode Locomotion_stepInterpolation = InterpolationMode.InOutSine; + + [Tooltip("Offset for the approximated center of mass.")] + public Vector3 Locomotion_offset; + + [Tooltip("Called when the left foot has finished a step.")] + public UnityEvent Locomotion_onLeftFootstep = new UnityEvent(); + + [Tooltip("Called when the right foot has finished a step")] + public UnityEvent Locomotion_onRightFootstep = new UnityEvent(); + + public void Start() + { + VRIK _VRIK = base.gameObject.GetComponent(); + if (_VRIK != null) + { + _VRIK.solver.spine.headTarget = this.HeadTarget; + _VRIK.solver.leftArm.target = this.LeftHandTarget; + _VRIK.solver.rightArm.target = this.RightHandTarget; + + Type type = this.GetType(); + FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.Public); + foreach (FieldInfo fieldInfo in fieldInfos) + { + string[] propertyName = fieldInfo.Name.Split('_'); + var value = fieldInfo.GetValue(this); + if (propertyName.Count() > 1) + { + if ("Spine" == propertyName[0]) + { + try + { + SetProperty(_VRIK.solver.spine, propertyName[1], value); + } + catch { } + } + else if ("LeftArm" == propertyName[0]) + { + try + { + SetProperty(_VRIK.solver.leftArm, propertyName[1], value); + } + catch { } + } + else if ("RightArm" == propertyName[0]) + { + try + { + SetProperty(_VRIK.solver.rightArm, propertyName[1], value); + } + catch { } + } + else if ("LeftLeg" == propertyName[0]) + { + try + { + SetProperty(_VRIK.solver.leftLeg, propertyName[1], value); + } + catch { } + } + else if ("RightLeg" == propertyName[0]) + { + try + { + SetProperty(_VRIK.solver.rightLeg, propertyName[1], value); + } + catch { } + } + else if ("Locomotion" == propertyName[0]) + { + try + { + SetProperty(_VRIK.solver.locomotion, propertyName[1], value); + } + catch { } + } + } + } + CheckFullBodyTracking(); + } + } + + public void CheckFullBodyTracking() + { +#if PLUGIN + VRIK _VRIK = base.gameObject.GetComponent(); + + _VRIK.solver.spine.pelvisPositionWeight = 0f; + _VRIK.solver.spine.pelvisRotationWeight = 0f; + _VRIK.solver.leftLeg.positionWeight = 0f; + _VRIK.solver.leftLeg.rotationWeight = 0f; + _VRIK.solver.rightLeg.positionWeight = 0f; + _VRIK.solver.rightLeg.rotationWeight = 0f; + switch (CustomAvatar.Plugin.FullBodyTrackingType) + { + case CustomAvatar.Plugin.TrackingType.Hips: + { + _VRIK.solver.spine.pelvisPositionWeight = this.Spine_pelvisPositionWeight; + _VRIK.solver.spine.pelvisRotationWeight = this.Spine_pelvisRotationWeight; + break; + } + case CustomAvatar.Plugin.TrackingType.Feet: + { + _VRIK.solver.leftLeg.positionWeight = this.LeftLeg_positionWeight; + _VRIK.solver.leftLeg.rotationWeight = this.LeftLeg_rotationWeight; + _VRIK.solver.rightLeg.positionWeight = this.RightLeg_positionWeight; + _VRIK.solver.rightLeg.rotationWeight = this.RightLeg_rotationWeight; + break; + } + case CustomAvatar.Plugin.TrackingType.Full: + { + _VRIK.solver.spine.pelvisPositionWeight = this.Spine_pelvisPositionWeight; + _VRIK.solver.spine.pelvisRotationWeight = this.Spine_pelvisRotationWeight; + _VRIK.solver.leftLeg.positionWeight = this.LeftLeg_positionWeight; + _VRIK.solver.leftLeg.rotationWeight = this.LeftLeg_rotationWeight; + _VRIK.solver.rightLeg.positionWeight = this.RightLeg_positionWeight; + _VRIK.solver.rightLeg.rotationWeight = this.RightLeg_rotationWeight; + break; + } + } +#endif + } + + public static void SetProperty(object obj, string fieldName, object value) + { + obj.GetType().GetField(fieldName).SetValue(obj, value); + } + + + public void ToggleLeftHandTarget(Transform leftHandTarget) + { + Console.WriteLine("ToggleLeftHandTarget"); + VRIK _VRIK = base.gameObject.GetComponent(); + if ("RightHand".Equals(_VRIK.solver.leftArm.target.parent.name)) + { + _VRIK.solver.leftArm.target = this.LeftHandTarget; + } + else + { + _VRIK.solver.leftArm.target = leftHandTarget; + } + } + } } diff --git a/CustomAvatar/VRIK/IKSolverVR.cs b/CustomAvatar/VRIK/IKSolverVR.cs index 5fb761c..e93991d 100644 --- a/CustomAvatar/VRIK/IKSolverVR.cs +++ b/CustomAvatar/VRIK/IKSolverVR.cs @@ -3,35 +3,39 @@ using System; using AvatarScriptPack; -namespace AvatarScriptPack { +namespace AvatarScriptPack +{ /// /// Hybrid %IK solver designed for mapping a character to a VR headset and 2 hand controllers /// [System.Serializable] - public partial class IKSolverVR: IKSolver { + public partial class IKSolverVR : IKSolver + { #region Wrapper /// /// Sets this VRIK up to the specified bone references. /// - public void SetToReferences(VRIK.References references) { - if (!references.isFilled) { + public void SetToReferences(VRIK.References references) + { + if (!references.isFilled) + { Debug.LogError("Invalid references, one or more Transforms are missing."); return; } - + solverTransforms = references.GetTransforms(); - hasChest = solverTransforms [3] != null; + hasChest = solverTransforms[3] != null; hasNeck = solverTransforms[4] != null; hasShoulders = solverTransforms[6] != null && solverTransforms[10] != null; hasToes = solverTransforms[17] != null && solverTransforms[21] != null; - + readPositions = new Vector3[solverTransforms.Length]; readRotations = new Quaternion[solverTransforms.Length]; - + DefaultAnimationCurves(); GuessHandOrientations(references, true); } @@ -39,25 +43,31 @@ public void SetToReferences(VRIK.References references) { /// /// Guesses the hand bones orientations ('Wrist To Palm Axis' and "Palm To Thumb Axis" of the arms) based on the provided references. if onlyIfZero is true, will only guess an orientation axis if it is Vector3.zero. /// - public void GuessHandOrientations(VRIK.References references, bool onlyIfZero) { - if (!references.isFilled) { + public void GuessHandOrientations(VRIK.References references, bool onlyIfZero) + { + if (!references.isFilled) + { Debug.LogWarning("VRIK References are not filled in, can not guess hand orientations. Right-click on VRIK header and slect 'Guess Hand Orientations' when you have filled in the References."); return; } - - if (leftArm.wristToPalmAxis == Vector3.zero || !onlyIfZero) { + + if (leftArm.wristToPalmAxis == Vector3.zero || !onlyIfZero) + { leftArm.wristToPalmAxis = GuessWristToPalmAxis(references.leftHand, references.leftForearm); } - - if (leftArm.palmToThumbAxis == Vector3.zero || !onlyIfZero) { + + if (leftArm.palmToThumbAxis == Vector3.zero || !onlyIfZero) + { leftArm.palmToThumbAxis = GuessPalmToThumbAxis(references.leftHand, references.leftForearm, leftArm.wristToPalmAxis); } - - if (rightArm.wristToPalmAxis == Vector3.zero || !onlyIfZero) { + + if (rightArm.wristToPalmAxis == Vector3.zero || !onlyIfZero) + { rightArm.wristToPalmAxis = GuessWristToPalmAxis(references.rightHand, references.rightForearm); } - - if (rightArm.palmToThumbAxis == Vector3.zero || !onlyIfZero) { + + if (rightArm.palmToThumbAxis == Vector3.zero || !onlyIfZero) + { rightArm.palmToThumbAxis = GuessPalmToThumbAxis(references.rightHand, references.rightForearm, rightArm.wristToPalmAxis); } } @@ -65,15 +75,18 @@ public void GuessHandOrientations(VRIK.References references, bool onlyIfZero) { /// /// Set default values for the animation curves if they have no keys. /// - public void DefaultAnimationCurves() { + public void DefaultAnimationCurves() + { if (locomotion.stepHeight == null) locomotion.stepHeight = new AnimationCurve(); - if (locomotion.heelHeight == null) locomotion.heelHeight = new AnimationCurve (); - - if (locomotion.stepHeight.keys.Length == 0) { + if (locomotion.heelHeight == null) locomotion.heelHeight = new AnimationCurve(); + + if (locomotion.stepHeight.keys.Length == 0) + { locomotion.stepHeight.keys = GetSineKeyframes(0.03f); } - - if (locomotion.heelHeight.keys.Length == 0) { + + if (locomotion.heelHeight.keys.Length == 0) + { locomotion.heelHeight.keys = GetSineKeyframes(0.03f); } } @@ -81,123 +94,145 @@ public void DefaultAnimationCurves() { /// /// Adds position offset to a body part. Position offsets add to the targets in VRIK. /// - public void AddPositionOffset(PositionOffset positionOffset, Vector3 value) { - switch(positionOffset) { - case PositionOffset.Pelvis: spine.pelvisPositionOffset += value; return; - case PositionOffset.Chest: spine.chestPositionOffset += value; return; - case PositionOffset.Head: spine.headPositionOffset += value; return; - case PositionOffset.LeftHand: leftArm.handPositionOffset += value; return; - case PositionOffset.RightHand: rightArm.handPositionOffset += value; return; - case PositionOffset.LeftFoot: leftLeg.footPositionOffset += value; return; - case PositionOffset.RightFoot: rightLeg.footPositionOffset += value; return; - case PositionOffset.LeftHeel: leftLeg.heelPositionOffset += value; return; - case PositionOffset.RightHeel: rightLeg.heelPositionOffset += value; return; + public void AddPositionOffset(PositionOffset positionOffset, Vector3 value) + { + switch (positionOffset) + { + case PositionOffset.Pelvis: spine.pelvisPositionOffset += value; return; + case PositionOffset.Chest: spine.chestPositionOffset += value; return; + case PositionOffset.Head: spine.headPositionOffset += value; return; + case PositionOffset.LeftHand: leftArm.handPositionOffset += value; return; + case PositionOffset.RightHand: rightArm.handPositionOffset += value; return; + case PositionOffset.LeftFoot: leftLeg.footPositionOffset += value; return; + case PositionOffset.RightFoot: rightLeg.footPositionOffset += value; return; + case PositionOffset.LeftHeel: leftLeg.heelPositionOffset += value; return; + case PositionOffset.RightHeel: rightLeg.heelPositionOffset += value; return; } } /// /// Adds rotation offset to a body part. Rotation offsets add to the targets in VRIK /// - public void AddRotationOffset(RotationOffset rotationOffset, Vector3 value) { + public void AddRotationOffset(RotationOffset rotationOffset, Vector3 value) + { AddRotationOffset(rotationOffset, Quaternion.Euler(value)); } /// /// Adds rotation offset to a body part. Rotation offsets add to the targets in VRIK /// - public void AddRotationOffset(RotationOffset rotationOffset, Quaternion value) { - switch(rotationOffset) { - case RotationOffset.Pelvis: spine.pelvisRotationOffset = value * spine.pelvisRotationOffset; return; - case RotationOffset.Chest: spine.chestRotationOffset = value * spine.chestRotationOffset; return; - case RotationOffset.Head: spine.headRotationOffset = value * spine.headRotationOffset; return; + public void AddRotationOffset(RotationOffset rotationOffset, Quaternion value) + { + switch (rotationOffset) + { + case RotationOffset.Pelvis: spine.pelvisRotationOffset = value * spine.pelvisRotationOffset; return; + case RotationOffset.Chest: spine.chestRotationOffset = value * spine.chestRotationOffset; return; + case RotationOffset.Head: spine.headRotationOffset = value * spine.headRotationOffset; return; } } /// /// Call this in each Update if your avatar is standing on a moving platform /// - public void AddPlatformMotion(Vector3 deltaPosition, Quaternion deltaRotation, Vector3 platformPivot) { - locomotion.AddDeltaPosition (deltaPosition); + public void AddPlatformMotion(Vector3 deltaPosition, Quaternion deltaRotation, Vector3 platformPivot) + { + locomotion.AddDeltaPosition(deltaPosition); raycastOriginPelvis += deltaPosition; - locomotion.AddDeltaRotation (deltaRotation, platformPivot); + locomotion.AddDeltaRotation(deltaRotation, platformPivot); spine.faceDirection = deltaRotation * spine.faceDirection; } /// /// Resets all tweens, blendings and lerps. Call this after you have teleported the character. /// - public void Reset() { + public void Reset() + { if (!initiated) return; UpdateSolverTransforms(); Read(readPositions, readRotations, hasChest, hasNeck, hasShoulders, hasToes); - + spine.faceDirection = rootBone.readRotation * Vector3.forward; locomotion.Reset(readPositions, readRotations); raycastOriginPelvis = spine.pelvis.readPosition; } - public override void StoreDefaultLocalState() { - for (int i = 1; i < solverTransforms.Length; i++) { - if (solverTransforms[i] != null) { + public override void StoreDefaultLocalState() + { + for (int i = 1; i < solverTransforms.Length; i++) + { + if (solverTransforms[i] != null) + { defaultLocalPositions[i - 1] = solverTransforms[i].localPosition; defaultLocalRotations[i - 1] = solverTransforms[i].localRotation; } } } - - public override void FixTransforms() { + + public override void FixTransforms() + { if (!initiated) return; - for (int i = 1; i < solverTransforms.Length; i++) { - if (solverTransforms[i] != null) { + for (int i = 1; i < solverTransforms.Length; i++) + { + if (solverTransforms[i] != null) + { bool isPelvis = i == 1; bool isArm = i > 5 && i < 14; - if (isPelvis || isArm) { + if (isPelvis || isArm) + { solverTransforms[i].localPosition = defaultLocalPositions[i - 1]; } solverTransforms[i].localRotation = defaultLocalRotations[i - 1]; } } } - - public override IKSolver.Point[] GetPoints() { + + public override IKSolver.Point[] GetPoints() + { Debug.LogError("GetPoints() is not applicable to IKSolverVR."); return null; } - - public override IKSolver.Point GetPoint(Transform transform) { + + public override IKSolver.Point GetPoint(Transform transform) + { Debug.LogError("GetPoint is not applicable to IKSolverVR."); return null; } - - public override bool IsValid(ref string message) { - if (solverTransforms == null || solverTransforms.Length == 0) { + + public override bool IsValid(ref string message) + { + if (solverTransforms == null || solverTransforms.Length == 0) + { message = "Trying to initiate IKSolverVR with invalid bone references."; return false; } - - if (leftArm.wristToPalmAxis == Vector3.zero) { + + if (leftArm.wristToPalmAxis == Vector3.zero) + { message = "Left arm 'Wrist To Palm Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the wrist towards the palm. If the arrow points away from the palm, axis must be negative."; return false; } - - if (rightArm.wristToPalmAxis == Vector3.zero) { + + if (rightArm.wristToPalmAxis == Vector3.zero) + { message = "Right arm 'Wrist To Palm Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the wrist towards the palm. If the arrow points away from the palm, axis must be negative."; return false; } - - if (leftArm.palmToThumbAxis == Vector3.zero) { + + if (leftArm.palmToThumbAxis == Vector3.zero) + { message = "Left arm 'Palm To Thumb Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the palm towards the thumb. If the arrow points away from the thumb, axis must be negative."; return false; } - - if (rightArm.palmToThumbAxis == Vector3.zero) { + + if (rightArm.palmToThumbAxis == Vector3.zero) + { message = "Right arm 'Palm To Thumb Axis' needs to be set in VRIK. Please select the hand bone, set it to the axis that points from the palm towards the thumb. If the arrow points away from the thumb, axis must be negative."; return false; } - + return true; } @@ -210,32 +245,38 @@ public override bool IsValid(ref string message) { //private Vector3 defaultPelvisLocalPosition; private Quaternion[] defaultLocalRotations = new Quaternion[21]; private Vector3[] defaultLocalPositions = new Vector3[21]; - - private Vector3 GetNormal(Transform[] transforms) { + + private Vector3 GetNormal(Transform[] transforms) + { Vector3 normal = Vector3.zero; Vector3 centroid = Vector3.zero; - for (int i = 0; i < transforms.Length; i++) { + for (int i = 0; i < transforms.Length; i++) + { centroid += transforms[i].position; } centroid /= transforms.Length; - for (int i = 0; i < transforms.Length - 1; i++) { + for (int i = 0; i < transforms.Length - 1; i++) + { normal += Vector3.Cross(transforms[i].position - centroid, transforms[i + 1].position - centroid).normalized; } - + return normal; } - private Vector3 GuessWristToPalmAxis(Transform hand, Transform forearm) { - Vector3 toForearm = forearm.position -hand.position; + private Vector3 GuessWristToPalmAxis(Transform hand, Transform forearm) + { + Vector3 toForearm = forearm.position - hand.position; Vector3 axis = AxisTools.ToVector3(AxisTools.GetAxisToDirection(hand, toForearm)); if (Vector3.Dot(toForearm, hand.rotation * axis) > 0f) axis = -axis; return axis; } - private Vector3 GuessPalmToThumbAxis(Transform hand, Transform forearm, Vector3 wristToPalmAxis) { - if (hand.childCount == 0) { + private Vector3 GuessPalmToThumbAxis(Transform hand, Transform forearm, Vector3 wristToPalmAxis) + { + if (hand.childCount == 0) + { Debug.LogWarning("Hand " + hand.name + " does not have any fingers, VRIK can not guess the hand bone's orientation. Please assign 'Wrist To Palm Axis' and 'Palm To Thumb Axis' manually for both arms in VRIK settings.", hand); return Vector3.zero; } @@ -243,9 +284,11 @@ private Vector3 GuessPalmToThumbAxis(Transform hand, Transform forearm, Vector3 float closestSqrMag = Mathf.Infinity; int thumbIndex = 0; - for (int i = 0; i < hand.childCount; i++) { - float sqrMag = Vector3.SqrMagnitude(hand.GetChild(i).position -hand.position); - if (sqrMag < closestSqrMag && sqrMag > 0.00001f) { + for (int i = 0; i < hand.childCount; i++) + { + float sqrMag = Vector3.SqrMagnitude(hand.GetChild(i).position - hand.position); + if (sqrMag < closestSqrMag && sqrMag > 0.00001f) + { closestSqrMag = sqrMag; thumbIndex = i; } @@ -259,7 +302,8 @@ private Vector3 GuessPalmToThumbAxis(Transform hand, Transform forearm, Vector3 return axis; } - private static Keyframe[] GetSineKeyframes(float mag) { + private static Keyframe[] GetSineKeyframes(float mag) + { Keyframe[] keys = new Keyframe[3]; keys[0].time = 0f; keys[0].value = 0f; @@ -270,22 +314,28 @@ private static Keyframe[] GetSineKeyframes(float mag) { return keys; } - private void UpdateSolverTransforms() { - for (int i = 0; i < solverTransforms.Length; i++) { - if (solverTransforms[i] != null) { + private void UpdateSolverTransforms() + { + for (int i = 0; i < solverTransforms.Length; i++) + { + if (solverTransforms[i] != null) + { readPositions[i] = solverTransforms[i].position; readRotations[i] = solverTransforms[i].rotation; } } } - protected override void OnInitiate() { + protected override void OnInitiate() + { UpdateSolverTransforms(); Read(readPositions, readRotations, hasChest, hasNeck, hasShoulders, hasToes); } - protected override void OnUpdate() { - if (IKPositionWeight > 0f) { + protected override void OnUpdate() + { + if (IKPositionWeight > 0f) + { UpdateSolverTransforms(); Read(readPositions, readRotations, hasChest, hasNeck, hasShoulders, hasToes); @@ -296,12 +346,16 @@ protected override void OnUpdate() { } } - private void WriteTransforms() { - for (int i = 0; i < solverTransforms.Length; i++) { - if (solverTransforms[i] != null) { + private void WriteTransforms() + { + for (int i = 0; i < solverTransforms.Length; i++) + { + if (solverTransforms[i] != null) + { bool isRootOrPelvis = i < 2; bool isArm = i > 5 && i < 14; - if (isRootOrPelvis || isArm) { + if (isRootOrPelvis || isArm) + { solverTransforms[i].position = V3Tools.Lerp(solverTransforms[i].position, GetPosition(i), IKPositionWeight); } @@ -319,25 +373,31 @@ private void WriteTransforms() { private Vector3 bodyOffset; private int supportLegIndex; - private void Read(Vector3[] positions, Quaternion[] rotations, bool hasChest, bool hasNeck, bool hasShoulders, bool hasToes) { - if (rootBone == null) { - rootBone = new VirtualBone (positions [0], rotations [0]); - } else { - rootBone.Read (positions [0], rotations [0]); + private void Read(Vector3[] positions, Quaternion[] rotations, bool hasChest, bool hasNeck, bool hasShoulders, bool hasToes) + { + if (rootBone == null) + { + rootBone = new VirtualBone(positions[0], rotations[0]); + } + else + { + rootBone.Read(positions[0], rotations[0]); } spine.Read(positions, rotations, hasChest, hasNeck, hasShoulders, hasToes, 0, 1); - leftArm.Read(positions, rotations, hasChest, hasNeck, hasShoulders, hasToes, hasChest? 3: 2, 6); - rightArm.Read(positions, rotations, hasChest, hasNeck, hasShoulders, hasToes, hasChest? 3: 2, 10); + leftArm.Read(positions, rotations, hasChest, hasNeck, hasShoulders, hasToes, hasChest ? 3 : 2, 6); + rightArm.Read(positions, rotations, hasChest, hasNeck, hasShoulders, hasToes, hasChest ? 3 : 2, 10); leftLeg.Read(positions, rotations, hasChest, hasNeck, hasShoulders, hasToes, 1, 14); rightLeg.Read(positions, rotations, hasChest, hasNeck, hasShoulders, hasToes, 1, 18); - for (int i = 0; i < rotations.Length; i++) { + for (int i = 0; i < rotations.Length; i++) + { this.solvedPositions[i] = positions[i]; this.solvedRotations[i] = rotations[i]; } - if (!initiated) { + if (!initiated) + { legs = new Leg[2] { leftLeg, rightLeg }; arms = new Arm[2] { leftArm, rightArm }; @@ -347,7 +407,8 @@ private void Read(Vector3[] positions, Quaternion[] rotations, bool hasChest, bo } } - private void Solve() { + private void Solve() + { // Pre-Solving spine.PreSolve(); foreach (Arm arm in arms) arm.PreSolve(); @@ -360,12 +421,14 @@ private void Solve() { // Spine spine.Solve(rootBone, legs, arms); - if (spine.pelvisPositionWeight > 0f && plantFeet) { + if (spine.pelvisPositionWeight > 0f && plantFeet) + { Warning.Log("If VRIK 'Pelvis Position Weight' is > 0, 'Plant Feet' should be disabled to improve performance and stability.", root); } // Locomotion - if (locomotion.weight > 0f) { + if (locomotion.weight > 0f) + { Vector3 leftFootPosition = Vector3.zero; Vector3 rightFootPosition = Vector3.zero; Quaternion leftFootRotation = Quaternion.identity; @@ -412,7 +475,8 @@ private void Solve() { } // Legs - foreach (Leg leg in legs) { + foreach (Leg leg in legs) + { leg.ApplyOffsets(); } @@ -424,26 +488,33 @@ private void Solve() { spine.InverseTranslateToHead(legs, false, false, bodyOffset, 1f); foreach (Leg leg in legs) leg.TranslateRoot(spine.pelvis.solverPosition, spine.pelvis.solverRotation); - foreach (Leg leg in legs) { + foreach (Leg leg in legs) + { leg.Solve(); } - } else { - for (int i = 0; i < 2; i++) { + } + else + { + for (int i = 0; i < 2; i++) + { spine.InverseTranslateToHead(legs, true, i == 0, bodyOffset, 1f); foreach (Leg leg in legs) leg.TranslateRoot(spine.pelvis.solverPosition, spine.pelvis.solverRotation); - foreach (Leg leg in legs) { + foreach (Leg leg in legs) + { leg.Solve(); } } } // Arms - for (int i = 0; i < arms.Length; i++) { + for (int i = 0; i < arms.Length; i++) + { arms[i].TranslateRoot(spine.chest.solverPosition, spine.chest.solverRotation); } - for (int i = 0; i < arms.Length; i++) { + for (int i = 0; i < arms.Length; i++) + { arms[i].Solve(i == 0); } @@ -461,20 +532,24 @@ private void Solve() { // Find the support leg supportLegIndex = -1; float shortestMag = Mathf.Infinity; - for (int i = 0; i < legs.Length; i++) { + for (int i = 0; i < legs.Length; i++) + { float mag = Vector3.SqrMagnitude(legs[i].lastBone.solverPosition - legs[i].bones[0].solverPosition); - if (mag < shortestMag) { + if (mag < shortestMag) + { supportLegIndex = i; shortestMag = mag; } } } - private Vector3 GetPosition(int index) { + private Vector3 GetPosition(int index) + { return solvedPositions[index]; } - private Quaternion GetRotation(int index) { + private Quaternion GetRotation(int index) + { return solvedRotations[index]; } @@ -538,7 +613,8 @@ private Quaternion GetRotation(int index) { private Vector3 debugPos3; private Vector3 debugPos4; - private void Write() { + private void Write() + { solvedPositions[0] = rootBone.solverPosition; solvedRotations[0] = rootBone.solverRotation; spine.Write(ref solvedPositions, ref solvedRotations); @@ -547,7 +623,8 @@ private void Write() { foreach (Arm arm in arms) arm.Write(ref solvedPositions, ref solvedRotations); } - private Vector3 GetPelvisOffset() { + private Vector3 GetPelvisOffset() + { if (locomotion.weight <= 0f) return Vector3.zero; if (locomotion.blockingLayers == -1) return Vector3.zero; @@ -561,12 +638,17 @@ private Vector3 GetPelvisOffset() { //debugPos4 = sampledOrigin; - if (locomotion.raycastRadius <= 0f) { - if (Physics.Raycast(sampledOrigin, direction, out hit, direction.magnitude * 1.1f, locomotion.blockingLayers)) { + if (locomotion.raycastRadius <= 0f) + { + if (Physics.Raycast(sampledOrigin, direction, out hit, direction.magnitude * 1.1f, locomotion.blockingLayers)) + { origin = hit.point; } - } else { - if (Physics.SphereCast(sampledOrigin, locomotion.raycastRadius * 1.1f, direction, out hit, direction.magnitude, locomotion.blockingLayers)) { + } + else + { + if (Physics.SphereCast(sampledOrigin, locomotion.raycastRadius * 1.1f, direction, out hit, direction.magnitude, locomotion.blockingLayers)) + { origin = sampledOrigin + direction.normalized * hit.distance / 1.1f; } } @@ -577,13 +659,18 @@ private Vector3 GetPelvisOffset() { //debugPos1 = origin; //debugPos2 = position; - if (locomotion.raycastRadius <= 0f) { - if (Physics.Raycast(origin, direction, out hit, direction.magnitude, locomotion.blockingLayers)) { + if (locomotion.raycastRadius <= 0f) + { + if (Physics.Raycast(origin, direction, out hit, direction.magnitude, locomotion.blockingLayers)) + { position = hit.point; } - } else { - if (Physics.SphereCast(origin, locomotion.raycastRadius, direction, out hit, direction.magnitude, locomotion.blockingLayers)) { + } + else + { + if (Physics.SphereCast(origin, locomotion.raycastRadius, direction, out hit, direction.magnitude, locomotion.blockingLayers)) + { position = origin + direction.normalized * hit.distance; } } diff --git a/CustomAvatar/VRIK/IKSolverVRBodyPart.cs b/CustomAvatar/VRIK/IKSolverVRBodyPart.cs index abbae5a..bb21e2f 100644 --- a/CustomAvatar/VRIK/IKSolverVRBodyPart.cs +++ b/CustomAvatar/VRIK/IKSolverVRBodyPart.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using System; using AvatarScriptPack; @@ -97,4 +97,4 @@ public void Visualize() { } } } -} \ No newline at end of file +} diff --git a/CustomAvatar/VRIK/IKSolverVRFootstep.cs b/CustomAvatar/VRIK/IKSolverVRFootstep.cs index 798563e..b792666 100644 --- a/CustomAvatar/VRIK/IKSolverVRFootstep.cs +++ b/CustomAvatar/VRIK/IKSolverVRFootstep.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using UnityEngine.Events; diff --git a/CustomAvatar/VRIK/IKSolverVRLeg.cs b/CustomAvatar/VRIK/IKSolverVRLeg.cs index ba8bd63..84336c7 100644 --- a/CustomAvatar/VRIK/IKSolverVRLeg.cs +++ b/CustomAvatar/VRIK/IKSolverVRLeg.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using System; using AvatarScriptPack; @@ -257,4 +257,4 @@ public override void ResetOffsets() { } } } -} \ No newline at end of file +} diff --git a/CustomAvatar/VRIK/IKSolverVRLocomotion.cs b/CustomAvatar/VRIK/IKSolverVRLocomotion.cs index cfe795f..3e75c4b 100644 --- a/CustomAvatar/VRIK/IKSolverVRLocomotion.cs +++ b/CustomAvatar/VRIK/IKSolverVRLocomotion.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using UnityEngine.Events; @@ -408,4 +408,4 @@ private static bool GetLineSphereCollision(Vector3 lineStart, Vector3 lineEnd, V } } } -} \ No newline at end of file +} diff --git a/CustomAvatar/VRIK/IKSolverVRSpine.cs b/CustomAvatar/VRIK/IKSolverVRSpine.cs index 3cca42f..2dc1c24 100644 --- a/CustomAvatar/VRIK/IKSolverVRSpine.cs +++ b/CustomAvatar/VRIK/IKSolverVRSpine.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using System; using AvatarScriptPack; @@ -584,4 +584,4 @@ private void Bend(VirtualBone[] bones, int firstIndex, int lastIndex, Quaternion } } } -} \ No newline at end of file +} diff --git a/CustomAvatar/VRIK/IKSolverVRUtilities.cs b/CustomAvatar/VRIK/IKSolverVRUtilities.cs index 6da0d97..672fe57 100644 --- a/CustomAvatar/VRIK/IKSolverVRUtilities.cs +++ b/CustomAvatar/VRIK/IKSolverVRUtilities.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using System; using AvatarScriptPack; diff --git a/CustomAvatar/VRIK/Interp.cs b/CustomAvatar/VRIK/Interp.cs index b2c2d2a..31ed141 100644 --- a/CustomAvatar/VRIK/Interp.cs +++ b/CustomAvatar/VRIK/Interp.cs @@ -1,4 +1,4 @@ -using System; +using System; using UnityEngine; namespace AvatarScriptPack diff --git a/CustomAvatar/VRIK/InterpolationMode.cs b/CustomAvatar/VRIK/InterpolationMode.cs index 7b112e8..bd0f4af 100644 --- a/CustomAvatar/VRIK/InterpolationMode.cs +++ b/CustomAvatar/VRIK/InterpolationMode.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace AvatarScriptPack { diff --git a/CustomAvatar/VRIK/TwistRelaxer.cs b/CustomAvatar/VRIK/TwistRelaxer.cs index 9fd95ff..9f81e26 100644 --- a/CustomAvatar/VRIK/TwistRelaxer.cs +++ b/CustomAvatar/VRIK/TwistRelaxer.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; namespace AvatarScriptPack { @@ -10,17 +10,17 @@ public class TwistRelaxer : MonoBehaviour { public IK ik; - [Tooltip("The child transform to use as a target. If not defined, defaults to first child of current transform or next child of parent.")] - public Transform child; + [Tooltip("The child transform to use as a target. If not defined, defaults to first child of current transform or next child of parent.")] + public Transform child; - [Tooltip("The weight of relaxing the twist of this Transform")] + [Tooltip("The weight of relaxing the twist of this Transform")] [Range(0f, 1f)] public float weight = 1f; [Tooltip("If 0.5, this Transform will be twisted half way from parent to child. If 1, the twist angle will be locked to the child and will rotate with along with it.")] [Range(0f, 1f)] public float parentChildCrossfade = 0.5f; - [Tooltip("Rotation offset around the twist axis.")] - [Range(-180f, 180f)] public float twistAngleOffset; + [Tooltip("Rotation offset around the twist axis.")] + [Range(-180f, 180f)] public float twistAngleOffset; /// /// Rotate this Transform to relax it's twist angle relative to the "parent" and "child" Transforms. @@ -28,9 +28,9 @@ public class TwistRelaxer : MonoBehaviour { public void Relax() { if (weight <= 0f) return; // Nothing to do here - Quaternion rotation = transform.rotation; - Quaternion twistOffset = Quaternion.AngleAxis(twistAngleOffset, rotation * twistAxis); - rotation = twistOffset * rotation; + Quaternion rotation = transform.rotation; + Quaternion twistOffset = Quaternion.AngleAxis(twistAngleOffset, rotation * twistAxis); + rotation = twistOffset * rotation; // Find the world space relaxed axes of the parent and child Vector3 relaxedAxisParent = twistOffset * parent.rotation * axisRelativeToParentDefault; @@ -65,24 +65,24 @@ void Start() { parent = transform.parent; if (child == null) - { - if (transform.childCount == 0) - { - var children = parent.GetComponentsInChildren(); - for (int i = 0; i < children.Length; i++) - { - if (children[i] != transform) - { - child = children[i]; - break; - } - } - } - else - { - child = transform.GetChild(0); - } - } + { + if (transform.childCount == 0) + { + var children = parent.GetComponentsInChildren(); + for (int i = 0; i < children.Length; i++) + { + if (children[i] != transform) + { + child = children[i]; + break; + } + } + } + else + { + child = transform.GetChild(0); + } + } twistAxis = transform.InverseTransformDirection(child.position - transform.position); axis = new Vector3(twistAxis.y, twistAxis.z, twistAxis.x); diff --git a/CustomAvatar/VRIK/V3Tools.cs b/CustomAvatar/VRIK/V3Tools.cs index 64afc90..7f55237 100644 --- a/CustomAvatar/VRIK/V3Tools.cs +++ b/CustomAvatar/VRIK/V3Tools.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; namespace AvatarScriptPack diff --git a/CustomAvatar/VRIK/VRIK.cs b/CustomAvatar/VRIK/VRIK.cs index 7de867d..6eaaed5 100644 --- a/CustomAvatar/VRIK/VRIK.cs +++ b/CustomAvatar/VRIK/VRIK.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; using System.Collections.Generic; @@ -118,7 +118,7 @@ public static bool AutoDetectReferences(Transform root, out References reference references = new References(); var animator = root.GetComponentInChildren(); - Debug.Log("Root: " + root + " " + root.name); + Debug.Log("Root: " + root + " " + root.name); if (animator == null || !animator.isHuman) { Debug.LogWarning("VRIK needs a Humanoid Animator to auto-detect biped references. Please assign references manually."); return false; diff --git a/CustomAvatar/VRIK/Warning.cs b/CustomAvatar/VRIK/Warning.cs index 770943d..2930983 100644 --- a/CustomAvatar/VRIK/Warning.cs +++ b/CustomAvatar/VRIK/Warning.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System.Collections; namespace AvatarScriptPack {