Forum Discussion
lufinkey
3 years agoProtege
Randomly large velocities from standard velocity calculator, but only in APK
I keep having extremely large values coming from the StandardVelocityCalculator that don't make sense with how the hand is moved. At first i thought it was tangential velocity influence, but turning that down still showed issues. However these issues would ONLY show up when making an APK and building to a device. Has anyone else experienced this?
Note: This can be seen in the TransformerExample scene by just attempting to pick up and release an object (often with no controller movement at all)
8 Replies
Replies have been turned off for this discussion
- Ornlu2Honored Guest
Hi yes I too am experiencing this exact issue. Im still trying to figure out how to fix it? lufinkey have you made any headway on this issue? I looked through the release notes/known issues of the interaction toolkit (we are on v43) and didnt see anything in future releases since that indicate that there is a known issue/bug with this script.
- nic.wiederholdHonored Guest
We're having the same issue. It's extremely inconsistent. Here's a pic of the logs we got of each drop:
inconsistent, gigantic velocities, being applied an interactable object after dropping it while holding it as motionless as possible. Doesn't happen in editor, only in build.
- lufinkeyProtege
I ended up making my own custom IVelocityCalculator implementation. I'll try to remember to share tomorrow when I'm back on my machine. Feel free to remind me if you don't hear back though
- nic.wiederholdHonored Guest
Awesome! That was the thought we had as well. We're also going to try clamping the values in the Oculus VelocityCalculator... Not super amped with that solution though. I appreciate your input for sure! Thanks!!
- lufinkeyProtege
Here's the custom "SimpleVelocityCalculator". The only remaining issue with it is that the poses are currently stored in world space, so any teleport will immediately make velocity really large. In our game, users don't need to hold anything while teleporting, so we just haven't gotten around to fixing it. But there's a small TODO in the code with a bit more detail on the fix that it needs (let me know if you have any questions on that and feel free to share if you make the fix). We also call ResetVelocityHistory in InteractableSelected in our custom "HandGrabInteractor" implementation, but you could probably do this within an event callback if you're using the oculus HandGrabInteractor:
using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using Oculus.Interaction; using Oculus.Interaction.Throw; public class SimpleVelocityCalculator: MonoBehaviour, IVelocityCalculator { public IPoseInputDevice poseInputDevice { get => __poseInputDevice; set { if (__poseInputDevice != value) { __poseInputDevice = value; _poseInputDevice = value as MonoBehaviour; _previousInputPose = GetInputDevicePose(); } } } [SerializeField, Interface(typeof(IPoseInputDevice))] private MonoBehaviour _poseInputDevice; private IPoseInputDevice __poseInputDevice; public float maxVelocityChange { get => _maxVelocityChange; set => _maxVelocityChange = value; } [SerializeField] private float _maxVelocityChange = 10.0f; public float maxAngularVelocityChange { get => _maxAngularVelocityChange; set => _maxAngularVelocityChange = value; } [SerializeField] private float _maxAngularVelocityChange = 20.0f; // IMPORTANT TODO!! store poses relative to a tracking space root, to prevent large velocities when teleporting (and then convert velocity vector to world space in CalculateThrowVelocity) private Pose? _previousInputPose = null; private Pose _previousValidInputPose = Pose.identity; private Vector3 _linearVelocity = Vector3.zero; private Vector3 _angularVelocity = Vector3.zero; private List<ReleaseVelocityInformation> _lastThrowVelocities = new List<ReleaseVelocityInformation>(); #region Unity Events protected void Awake() { __poseInputDevice = _poseInputDevice as IPoseInputDevice; } protected void Update() { UpdateVelocities(); } #endregion #region IVelocityCalculator float IVelocityCalculator.UpdateFrequency => Mathf.Epsilon; void IVelocityCalculator.SetUpdateFrequency(float frequency) { Debug.LogError("Update frequency cannot be modified on SimpleVelocityCalculator"); } public event System.Action<List<ReleaseVelocityInformation>> WhenThrowVelocitiesChanged = delegate { }; public event System.Action<ReleaseVelocityInformation> WhenNewSampleAvailable = delegate { }; IReadOnlyList<ReleaseVelocityInformation> IVelocityCalculator.LastThrowVelocities() => _lastThrowVelocities; public ReleaseVelocityInformation CalculateThrowVelocity(Transform objectThrown) { _lastThrowVelocities.Clear(); ReleaseVelocityInformation releaseInfo = new ReleaseVelocityInformation( _linearVelocity, _angularVelocity, origin: _previousValidInputPose.position, isSelectedVelocity: true); _lastThrowVelocities.Add(releaseInfo); ResetVelocityHistory(); WhenThrowVelocitiesChanged(_lastThrowVelocities); return releaseInfo; } #endregion public Pose? GetInputDevicePose() { var inputDevice = this.poseInputDevice; if (inputDevice == null || !inputDevice.IsInputValid || !inputDevice.IsHighConfidence || !inputDevice.GetRootPose(out Pose referencePose)) { return null; } return referencePose; } public void ResetVelocityHistory() { _previousInputPose = null; _linearVelocity = Vector3.zero; _angularVelocity = Vector3.zero; } private void UpdateVelocities() { var newInputPose = GetInputDevicePose(); var prevInputPose = _previousInputPose; _previousInputPose = newInputPose; if (newInputPose != null) { _previousValidInputPose = newInputPose.Value; } if (newInputPose == null || prevInputPose == null) { return; } var newPoseVal = newInputPose.Value; var prevPoseVal = prevInputPose.Value; var positionDelta = (newPoseVal.position - prevPoseVal.position); var rotationDelta = FromToRotationGlobal(prevPoseVal.rotation, newPoseVal.rotation); Vector3 velocityTarget = (positionDelta / Time.deltaTime); if (!float.IsNaN(velocityTarget.x)) { _linearVelocity = Vector3.MoveTowards(_linearVelocity, velocityTarget, _maxVelocityChange); } rotationDelta.ToAngleAxis(out float angle, out Vector3 axis); angle = NormalizeSignedAngle(angle); if (angle != 0) { Vector3 angularTarget = angle * axis; if (!float.IsNaN(angularTarget.x)) { angularTarget = (angularTarget / Time.deltaTime); _angularVelocity = Vector3.MoveTowards(_angularVelocity, angularTarget, _maxAngularVelocityChange); } } var newReleaseInfo = new ReleaseVelocityInformation(_linearVelocity, _angularVelocity, newPoseVal.position); WhenNewSampleAvailable.Invoke(newReleaseInfo); } private static Quaternion FromToRotationGlobal(Quaternion from, Quaternion to) { return to * Quaternion.Inverse(from); } public static Vector3 NormalizeSignedAngles(Vector3 euler) { euler.x = NormalizeSignedAngle(euler.x); euler.y = NormalizeSignedAngle(euler.y); euler.z = NormalizeSignedAngle(euler.z); return euler; } public static float NormalizeSignedAngle(float angle) { angle %= 360.0f; while (angle > 180.0f) { angle -= 360.0f; } while (angle < -180.0f) { angle += 360.0f; } return angle; } }- simonmersusExplorer
Hey, thanks for the script, it helped me implement a velocity tracker for hand tracking that's working pretty smotthly. I have a question, how do you handle spikes in velocity when tracking is lost ? I tried to implement a frame buffer to discard the first frame after tracking is back but i'm still getting spikes after that (worst scenario is when I'm occluding one of my hand and it is jumping over the place)
- lufinkeyProtege
Within this code? Using Vector3.MoveTowards with a max change in velocity might be what you're looking for
Quick Links
- Horizon Developer Support
- Quest User Forums
- Troubleshooting Forum for problems with a game or app
- Quest Support for problems with your device
Other Meta Support
Related Content
- 3 years ago
- 6 months ago
- 6 months ago
- 5 months ago