XRoom_Unity/Assets/Photon/FusionXRHost/Scripts/Utils/VelocitySmoother.cs
2025-05-31 10:20:20 +03:30

109 lines
3.7 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Fusion.XR.Host.Utils
{
/**
* Compute an average velocity.
* Useful when no rigidbody is available, or for very high tick rate (~ 120), as rigidbody regular velocity computed with very short deltaTime values tend to not be relevant anymore for release velocity
*/
public class VelocitySmoother : MonoBehaviour
{
[Tooltip("If false, the velocity won't be computed anymore - to decrease CPU usage")]
public bool istrackingVelocity = true;
[Tooltip("If true (and a rigidbody is present), the returned average velocity will preserve the direction of the rigidbody velocity")]
public bool useRigidbodyVelocityDirection = true;
Rigidbody rb;
NetworkObject no;
#region Velocity estimation
// Velocity computation
const int velocityBufferSize = 5;
Vector3 lastPosition;
Quaternion previousRotation;
Vector3[] lastMoves = new Vector3[velocityBufferSize];
Vector3[] lastAngularVelocities = new Vector3[velocityBufferSize];
float[] lastDeltaTime = new float[velocityBufferSize];
int lastMoveIndex = 0;
public Vector3 AverageVelocity
{
get
{
Vector3 move = Vector3.zero;
float time = 0;
for (int i = 0; i < velocityBufferSize; i++)
{
if (lastDeltaTime[i] != 0)
{
move += lastMoves[i];
time += lastDeltaTime[i];
}
}
if (time == 0) return Vector3.zero;
var averageVelocity = (move / time);
if (rb && useRigidbodyVelocityDirection)
{
averageVelocity = averageVelocity.magnitude * rb.linearVelocity.normalized;
}
return averageVelocity;
}
}
public Vector3 AverageAngularVelocity
{
get
{
Vector3 culmulatedAngularVelocity = Vector3.zero;
int step = 0;
for (int i = 0; i < velocityBufferSize; i++)
{
if (lastDeltaTime[i] != 0)
{
culmulatedAngularVelocity += lastAngularVelocities[i];
step++;
}
}
if (step == 0) return Vector3.zero;
return culmulatedAngularVelocity / step;
}
}
private void Awake()
{
rb = GetComponent<Rigidbody>();
no = GetComponentInParent<NetworkObject>();
}
void TrackVelocity()
{
lastMoves[lastMoveIndex] = transform.position - lastPosition;
lastAngularVelocities[lastMoveIndex] = previousRotation.AngularVelocityChange(transform.rotation, Time.deltaTime);
lastDeltaTime[lastMoveIndex] = Time.deltaTime;
lastMoveIndex = (lastMoveIndex + 1) % 5;
lastPosition = transform.position;
previousRotation = transform.rotation;
}
public void ResetVelocityTracking()
{
for (int i = 0; i < velocityBufferSize; i++) lastDeltaTime[i] = 0;
lastMoveIndex = 0;
}
#endregion
private void Update()
{
if(no && no.Runner && no.Runner.IsResimulation)
{
// We only read velocity during forward ticks, to avoid detecting past positions of the object
return;
}
if(istrackingVelocity) TrackVelocity();
}
}
}