166 lines
5.9 KiB
C#
166 lines
5.9 KiB
C#
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
|
|||
|
namespace BNG {
|
|||
|
|
|||
|
public class VelocityTracker : MonoBehaviour {
|
|||
|
|
|||
|
public enum VelocityTrackingType {
|
|||
|
Device, // Velocity is retrieved using XR Controller Velocity if it is supported. Will fall back to PerFrame if not.
|
|||
|
PerFrame // Calculate velocity per frame based on prior position / rotation
|
|||
|
}
|
|||
|
|
|||
|
[Tooltip("This setting determines how retrieve the velocity. If 'Device' is selected and ControllerHand is specified, then velocity will be retrieved from the connected physical controller. Otherwise velocity is calculated on a per frame basis.")]
|
|||
|
public VelocityTrackingType trackingType = VelocityTrackingType.Device;
|
|||
|
|
|||
|
[Tooltip("If ControllerHand is specified as Left or Right then velocity will attempt to be retrieved from the physical controller. If None, velocity will be calculated per frame.")]
|
|||
|
public ControllerHand controllerHand = ControllerHand.None;
|
|||
|
|
|||
|
[Tooltip("How many frames to use when averaging retrieving velocity using GetAveragedVelocity / GetAveragedAngularVelocity")]
|
|||
|
public float AverageVelocityCount = 3;
|
|||
|
|
|||
|
// Values used to manually track velocity
|
|||
|
private Vector3 _velocity;
|
|||
|
private Vector3 _angularVelocity;
|
|||
|
|
|||
|
// Used for manual velocity tracking
|
|||
|
private Vector3 _lastPosition;
|
|||
|
private Quaternion _lastRotation;
|
|||
|
|
|||
|
List<Vector3> previousVelocities = new List<Vector3>();
|
|||
|
List<Vector3> previousAngularVelocities = new List<Vector3>();
|
|||
|
|
|||
|
// Used in out variables to calculate angleaxis
|
|||
|
float angle;
|
|||
|
Vector3 axis;
|
|||
|
|
|||
|
// Used for tracking playspace rotation which may be needed to determine velocity of thrown objects
|
|||
|
GameObject playSpace;
|
|||
|
|
|||
|
void Start() {
|
|||
|
playSpace = GameObject.Find("TrackingSpace");
|
|||
|
}
|
|||
|
|
|||
|
void FixedUpdate() {
|
|||
|
UpdateVelocities();
|
|||
|
|
|||
|
// Save our last position / rotation so we can use it for velocity calculations
|
|||
|
_lastPosition = transform.position;
|
|||
|
_lastRotation = transform.rotation;
|
|||
|
}
|
|||
|
|
|||
|
public virtual void UpdateVelocities() {
|
|||
|
UpdateVelocity();
|
|||
|
UpdateAngularVelocity();
|
|||
|
}
|
|||
|
|
|||
|
public virtual void UpdateVelocity() {
|
|||
|
// Update velocity based on current and previous position
|
|||
|
_velocity = (transform.position - _lastPosition) / Time.deltaTime;
|
|||
|
|
|||
|
// Add Linear Velocity
|
|||
|
previousVelocities.Add(GetVelocity());
|
|||
|
|
|||
|
// Shrink list if necessary
|
|||
|
if (previousVelocities.Count > AverageVelocityCount) {
|
|||
|
previousVelocities.RemoveAt(0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public virtual void UpdateAngularVelocity() {
|
|||
|
// Update our current angular velocity
|
|||
|
Quaternion deltaRotation = transform.rotation * Quaternion.Inverse(_lastRotation);
|
|||
|
deltaRotation.ToAngleAxis(out angle, out axis);
|
|||
|
angle *= Mathf.Deg2Rad;
|
|||
|
|
|||
|
_angularVelocity = axis * angle * (1.0f / Time.deltaTime);
|
|||
|
|
|||
|
// Add Angular Velocity
|
|||
|
previousAngularVelocities.Add(GetAngularVelocity());
|
|||
|
|
|||
|
// Shrink list if necessary
|
|||
|
if (previousAngularVelocities.Count > AverageVelocityCount) {
|
|||
|
previousAngularVelocities.RemoveAt(0);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public virtual Vector3 GetVelocity() {
|
|||
|
|
|||
|
// Return velocity straight away if set to per frame velocity check. No need to check device.
|
|||
|
if(trackingType == VelocityTrackingType.PerFrame) {
|
|||
|
return _velocity;
|
|||
|
}
|
|||
|
|
|||
|
// Try XR Input Velocity First
|
|||
|
Vector3 vel = InputBridge.Instance.GetControllerVelocity(controllerHand);
|
|||
|
|
|||
|
// Fall back to tracking velocity on a per frame basis if current velocity is unknown
|
|||
|
if (vel == null || vel == Vector3.zero) {
|
|||
|
return _velocity;
|
|||
|
}
|
|||
|
else {
|
|||
|
// Add the playspace rotation in if necessary
|
|||
|
if(playSpace != null) {
|
|||
|
return playSpace.transform.rotation * vel;
|
|||
|
}
|
|||
|
|
|||
|
return vel;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public virtual Vector3 GetAveragedVelocity() {
|
|||
|
return GetAveragedVector(previousVelocities);
|
|||
|
}
|
|||
|
|
|||
|
public virtual Vector3 GetAngularVelocity() {
|
|||
|
|
|||
|
// Device Angular Velocity appears to have some issues when being used in the editor. Sticking with per-frame angular Velocity for now as it is more reliable.
|
|||
|
return _angularVelocity;
|
|||
|
|
|||
|
// Try XR Input AngularVelocity First
|
|||
|
//Vector3 angularVel = InputBridge.Instance.GetControllerAngularVelocity(controllerHand);
|
|||
|
|
|||
|
//// Fall back to tracking velocity on a per frame basis if current velocity is unknown
|
|||
|
//if (angularVel == null || angularVel == Vector3.zero) {
|
|||
|
// return _angularVelocity;
|
|||
|
//}
|
|||
|
//else {
|
|||
|
// // Add the playspace rotation in if necessary
|
|||
|
// if (playSpace != null) {
|
|||
|
// return playSpace.transform.rotation * angularVel;
|
|||
|
// }
|
|||
|
|
|||
|
// return angularVel;
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
public virtual Vector3 GetAveragedAngularVelocity() {
|
|||
|
return GetAveragedVector(previousAngularVelocities);
|
|||
|
}
|
|||
|
|
|||
|
public virtual Vector3 GetAveragedVector(List<Vector3> vectors) {
|
|||
|
|
|||
|
if (vectors != null) {
|
|||
|
|
|||
|
int count = vectors.Count;
|
|||
|
float x = 0;
|
|||
|
float y = 0;
|
|||
|
float z = 0;
|
|||
|
|
|||
|
for (int i = 0; i < count; i++) {
|
|||
|
Vector3 v = vectors[i];
|
|||
|
x += v.x;
|
|||
|
y += v.y;
|
|||
|
z += v.z;
|
|||
|
}
|
|||
|
|
|||
|
return new Vector3(x / count, y / count, z / count);
|
|||
|
}
|
|||
|
|
|||
|
return Vector3.zero;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|