103 lines
3.3 KiB
C#
103 lines
3.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Splines;
|
|
using Unity.Mathematics;
|
|
|
|
namespace JBooth.MicroVerseCore
|
|
{
|
|
[ExecuteAlways]
|
|
public class SplineRelativeTransform : MonoBehaviour
|
|
{
|
|
public SplineContainer splineContainer;
|
|
public float3 offset;
|
|
[HideInInspector] public Quaternion rotOffset;
|
|
[HideInInspector] public float T;
|
|
|
|
|
|
public bool keepUpright = false;
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
private void OnSplineModified(Spline spline, int knot, SplineModification mod)
|
|
{
|
|
if (Application.isPlaying)
|
|
return;
|
|
if (splineContainer != null)
|
|
{
|
|
foreach (var s in splineContainer.Splines)
|
|
{
|
|
if (ReferenceEquals(spline, s))
|
|
{
|
|
if (mod == SplineModification.KnotInserted || mod == SplineModification.KnotRemoved)
|
|
CaptureOffset();
|
|
Refresh();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (splineContainer != null)
|
|
{
|
|
if (transform.hasChanged)
|
|
{
|
|
CaptureOffset();
|
|
|
|
transform.hasChanged = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
Spline.Changed += OnSplineModified;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
Spline.Changed -= OnSplineModified;
|
|
}
|
|
#endif
|
|
|
|
public void CaptureOffset()
|
|
{
|
|
if (splineContainer != null)
|
|
{
|
|
float3 localPos = splineContainer.transform.worldToLocalMatrix.MultiplyPoint(transform.position);
|
|
SplineUtility.GetNearestPoint(splineContainer[0], localPos, out var nearest, out T, 128, 128);
|
|
SplineUtility.Evaluate(splineContainer[0], T, out var pos, out var tang, out var up);
|
|
tang = math.normalizesafe(tang);
|
|
up = math.normalizesafe(up);
|
|
Quaternion quat = Quaternion.LookRotation(math.cross(tang, up), up);
|
|
Matrix4x4 mtx = Matrix4x4.TRS(pos, quat, Vector3.one);
|
|
offset = mtx.inverse.MultiplyPoint(localPos);
|
|
|
|
// rotate offset by spline direction
|
|
rotOffset = transform.rotation * Quaternion.Inverse(quat);
|
|
}
|
|
}
|
|
|
|
public void Refresh()
|
|
{
|
|
splineContainer[0].Evaluate(T, out var position, out var tangent, out var up);
|
|
up = math.normalizesafe(up);
|
|
tangent = math.normalizesafe(tangent);
|
|
Quaternion quat = Quaternion.LookRotation(Vector3.Cross(tangent, up), up);
|
|
Matrix4x4 mtx = Matrix4x4.TRS(position, quat, Vector3.one);
|
|
var localPos = mtx.MultiplyPoint(offset);
|
|
transform.position = splineContainer.transform.localToWorldMatrix.MultiplyPoint(localPos);
|
|
transform.rotation = rotOffset * quat;
|
|
|
|
if (keepUpright)
|
|
{
|
|
var euler = transform.rotation.eulerAngles;
|
|
euler.x = 0;
|
|
euler.z = 0;
|
|
transform.rotation = Quaternion.Euler(euler);
|
|
}
|
|
}
|
|
}
|
|
}
|