150 lines
4.9 KiB
C#
150 lines
4.9 KiB
C#
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.Splines;
|
|
|
|
namespace FrameJosh.SplineImporter
|
|
{
|
|
public class SplinePlus : MonoBehaviour
|
|
{
|
|
public SplineContainer splineContainer;
|
|
|
|
public SplineContainer deformContainer;
|
|
|
|
public int resolution = 1;
|
|
|
|
public void Evaluate(int splineIndex, float anchor, float distance, out float3 position, out quaternion rotation)
|
|
{
|
|
EvaluateSpline(splineContainer.Splines[splineIndex], deformContainer.Spline, anchor, distance, resolution, out position, out rotation);
|
|
}
|
|
|
|
public void Evaluate(int splineIndex, float anchor, float distance, out Vector3 position, out Quaternion rotation)
|
|
{
|
|
Evaluate(splineIndex, anchor, distance, out float3 position1, out quaternion rotation1);
|
|
|
|
position = position1;
|
|
|
|
rotation = rotation1;
|
|
}
|
|
|
|
public void GetNearestPoint(int splineIndex, float3 point, out float3 position, out quaternion rotation, out float t)
|
|
{
|
|
position = float3.zero;
|
|
|
|
rotation = quaternion.identity;
|
|
|
|
t = 0;
|
|
|
|
ISpline spline = splineContainer.Splines[splineIndex];
|
|
|
|
ISpline deform = deformContainer.Spline;
|
|
|
|
float nearestDistance = float.PositiveInfinity;
|
|
|
|
int resolutionScale = (int)math.ceil(spline.GetLength()) * resolution;
|
|
|
|
for (float i = 0; i <= resolutionScale; i++)
|
|
{
|
|
EvaluateSpline(spline, deform, i / resolutionScale, 0, resolution, out float3 thisPosition, out quaternion thisRotation);
|
|
|
|
float thisDistance = math.distance(point, thisPosition);
|
|
|
|
if (thisDistance < nearestDistance)
|
|
{
|
|
position = thisPosition;
|
|
|
|
rotation = thisRotation;
|
|
|
|
t = i / resolutionScale;
|
|
|
|
nearestDistance = thisDistance;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void GetNearestPoint(int splineIndex, Vector3 point, out Vector3 position, out Quaternion rotation, out float t)
|
|
{
|
|
GetNearestPoint(splineIndex, point, out float3 position1, out quaternion rotation1, out t);
|
|
|
|
position = position1;
|
|
|
|
rotation = rotation1;
|
|
}
|
|
|
|
static void EvaluateSpline(ISpline spline, ISpline deform, float anchor, float distance, int resolution, out float3 position, out quaternion rotation)
|
|
{
|
|
float t = anchor + (distance / spline.GetLength());
|
|
|
|
if (deform != null)
|
|
DeformSpline(spline, deform, t, resolution, out position, out rotation);
|
|
else
|
|
{
|
|
spline.Evaluate(t, out float3 position1, out float3 tangent, out float3 upVector);
|
|
|
|
position = position1;
|
|
|
|
rotation = quaternion.LookRotation(tangent, upVector);
|
|
}
|
|
}
|
|
|
|
static void DeformSpline(ISpline spline, ISpline deform, float t, int resolution, out float3 position, out quaternion rotation)
|
|
{
|
|
int resolutionScale = (int)math.ceil(spline.GetLength()) * resolution;
|
|
|
|
position = EvaluatePoint(spline, deform, t);
|
|
|
|
float t1 = math.clamp(t, 0, 1 - (1 / (float)resolutionScale));
|
|
|
|
float3 position0 = EvaluatePoint(spline, deform, t1);
|
|
|
|
float3 position1 = EvaluatePoint(spline, deform, t1 + (1 / (float)resolutionScale));
|
|
|
|
float3 difference = position1 - position0;
|
|
|
|
rotation = quaternion.LookRotationSafe(difference, math.up());
|
|
}
|
|
|
|
static float3 EvaluatePoint(ISpline spline, ISpline deform, float t)
|
|
{
|
|
spline.Evaluate(t, out float3 position, out _, out _);
|
|
|
|
deform.Evaluate(position.x / deform.GetLength(), out float3 deformPosition, out float3 deformTangent, out float3 deformUpVector);
|
|
|
|
float3 right = math.normalize(math.cross(deformTangent, deformUpVector));
|
|
|
|
float3 up = math.normalize(deformUpVector);
|
|
|
|
return deformPosition + (right * position.z) + (up * position.y);
|
|
}
|
|
|
|
void OnDrawGizmosSelected()
|
|
{
|
|
if (!splineContainer || !deformContainer) return;
|
|
|
|
Gizmos.color = Color.green;
|
|
|
|
for (int i = 0; i < splineContainer.Splines.Count; i++)
|
|
{
|
|
Evaluate(0, 0, 0, out float3 position, out _);
|
|
|
|
float3 oldPosition = position;
|
|
|
|
int gizmoResolution = (int)math.ceil(splineContainer.Splines[i].GetLength());
|
|
|
|
for (float j = 1; j <= gizmoResolution; j++)
|
|
{
|
|
Evaluate(0, j / gizmoResolution, 0, out position, out _);
|
|
|
|
Gizmos.DrawLine(oldPosition, position);
|
|
|
|
oldPosition = position;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Reset()
|
|
{
|
|
splineContainer = GetComponentInChildren<SplineContainer>();
|
|
}
|
|
}
|
|
}
|