You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.7 KiB
C#
188 lines
5.7 KiB
C#
3 weeks ago
|
using System;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace Fusion.Addons.SimpleKCC
|
||
|
{
|
||
|
internal sealed class KCCResolver
|
||
|
{
|
||
|
private sealed class Correction
|
||
|
{
|
||
|
public Vector3 Amount;
|
||
|
|
||
|
public Vector3 Direction;
|
||
|
|
||
|
public float Distance;
|
||
|
|
||
|
public float Error;
|
||
|
}
|
||
|
|
||
|
private int _size;
|
||
|
|
||
|
private int _iterations;
|
||
|
|
||
|
private Correction[] _corrections;
|
||
|
|
||
|
private Vector3 _minCorrection;
|
||
|
|
||
|
private Vector3 _maxCorrection;
|
||
|
|
||
|
private Vector3 _targetCorrection;
|
||
|
|
||
|
public int Size => _size;
|
||
|
|
||
|
public int Iterations => _iterations;
|
||
|
|
||
|
public Vector3 TargetCorrection => _targetCorrection;
|
||
|
|
||
|
public KCCResolver(int maxSize)
|
||
|
{
|
||
|
_corrections = new Correction[maxSize];
|
||
|
for (int i = 0; i < maxSize; i++)
|
||
|
{
|
||
|
_corrections[i] = new Correction();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Reset()
|
||
|
{
|
||
|
_size = 0;
|
||
|
_iterations = 0;
|
||
|
_minCorrection = default(Vector3);
|
||
|
_maxCorrection = default(Vector3);
|
||
|
_targetCorrection = default(Vector3);
|
||
|
}
|
||
|
|
||
|
public void AddCorrection(Vector3 direction, float distance)
|
||
|
{
|
||
|
Correction correction = _corrections[_size];
|
||
|
correction.Amount = direction * distance;
|
||
|
correction.Direction = direction;
|
||
|
correction.Distance = distance;
|
||
|
_minCorrection = Vector3.Min(_minCorrection, correction.Amount);
|
||
|
_maxCorrection = Vector3.Max(_maxCorrection, correction.Amount);
|
||
|
_size++;
|
||
|
}
|
||
|
|
||
|
public Vector3 GetCorrection(int index)
|
||
|
{
|
||
|
return _corrections[index].Amount;
|
||
|
}
|
||
|
|
||
|
public Vector3 GetCorrection(int index, out Vector3 direction)
|
||
|
{
|
||
|
Correction correction = _corrections[index];
|
||
|
direction = correction.Direction;
|
||
|
return correction.Amount;
|
||
|
}
|
||
|
|
||
|
public Vector3 GetCorrection(int index, out Vector3 direction, out float distance)
|
||
|
{
|
||
|
Correction correction = _corrections[index];
|
||
|
direction = correction.Direction;
|
||
|
distance = correction.Distance;
|
||
|
return correction.Amount;
|
||
|
}
|
||
|
|
||
|
public Vector3 CalculateMinMax()
|
||
|
{
|
||
|
_iterations = 0;
|
||
|
_targetCorrection = _minCorrection + _maxCorrection;
|
||
|
return _targetCorrection;
|
||
|
}
|
||
|
|
||
|
public Vector3 CalculateSum()
|
||
|
{
|
||
|
_iterations = 0;
|
||
|
_targetCorrection = default(Vector3);
|
||
|
int i = 0;
|
||
|
for (int size = _size; i < size; i++)
|
||
|
{
|
||
|
_targetCorrection += _corrections[i].Amount;
|
||
|
}
|
||
|
|
||
|
return _targetCorrection;
|
||
|
}
|
||
|
|
||
|
public Vector3 CalculateBinary()
|
||
|
{
|
||
|
if (_size != 2)
|
||
|
{
|
||
|
throw new InvalidOperationException("Size must be 2!");
|
||
|
}
|
||
|
|
||
|
_iterations = 0;
|
||
|
_targetCorrection = _minCorrection + _maxCorrection;
|
||
|
Correction correction = _corrections[0];
|
||
|
Correction correction2 = _corrections[1];
|
||
|
float num = Vector3.Dot(correction.Direction, correction2.Direction);
|
||
|
if (num > 0.999f || num < -0.999f)
|
||
|
{
|
||
|
return _targetCorrection;
|
||
|
}
|
||
|
|
||
|
Vector3 normalized = Vector3.Cross(Vector3.Cross(correction.Direction, correction2.Direction), correction.Direction).normalized;
|
||
|
float num2 = (correction2.Distance - correction.Distance * num) / Mathf.Sqrt(1f - num * num);
|
||
|
_targetCorrection = correction.Amount + normalized * num2;
|
||
|
return _targetCorrection;
|
||
|
}
|
||
|
|
||
|
public Vector3 CalculateGradientDescent(int maxIterations, float maxError)
|
||
|
{
|
||
|
_iterations = 0;
|
||
|
_targetCorrection = _minCorrection + _maxCorrection;
|
||
|
if (_size <= 1)
|
||
|
{
|
||
|
return _targetCorrection;
|
||
|
}
|
||
|
|
||
|
Vector3 targetCorrection = _targetCorrection;
|
||
|
Correction[] corrections = _corrections;
|
||
|
while (_iterations < maxIterations)
|
||
|
{
|
||
|
Vector3 vector = default(Vector3);
|
||
|
float num = 0f;
|
||
|
float num2 = 0f;
|
||
|
int i = 0;
|
||
|
for (int size = _size; i < size; i++)
|
||
|
{
|
||
|
Correction correction = corrections[i];
|
||
|
correction.Error = correction.Direction.x * targetCorrection.x + correction.Direction.y * targetCorrection.y + correction.Direction.z * targetCorrection.z - correction.Distance;
|
||
|
vector += correction.Direction * correction.Error;
|
||
|
}
|
||
|
|
||
|
if (vector.IsAlmostZero(maxError))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
vector.Normalize();
|
||
|
int j = 0;
|
||
|
for (int size2 = _size; j < size2; j++)
|
||
|
{
|
||
|
Correction correction = corrections[j];
|
||
|
float num3 = correction.Direction.x * vector.x + correction.Direction.y * vector.y + correction.Direction.z * vector.z;
|
||
|
num += correction.Error * num3;
|
||
|
num2 = ((!(num3 >= 0f)) ? (num2 - num3) : (num2 + num3));
|
||
|
}
|
||
|
|
||
|
if (num2 < 1E-06f)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
num /= num2;
|
||
|
if (num.IsAlmostZero(maxError))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
targetCorrection -= vector * num;
|
||
|
_iterations++;
|
||
|
}
|
||
|
|
||
|
_targetCorrection = targetCorrection;
|
||
|
return targetCorrection;
|
||
|
}
|
||
|
}
|
||
|
}
|