2024-11-01 16:55:46 +08:00

83 lines
2.7 KiB
C#

using System;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.Rendering;
using UnityEngine.Splines;
[ExecuteAlways]
public class WormSplineFollower : MonoBehaviour
{
public SplineContainer Spline;
public bool flipDirection;
public float Distance;
public float PositionOffset;
public float ScaleOffset;
private float m_SplineLength;
// Start is called before the first frame update
private void OnEnable()
{
m_SplineLength = Spline.CalculateLength();
RenderPipelineManager.beginFrameRendering += BeginFrame;
RenderPipelineManager.endFrameRendering += EndFrame;
}
private void OnDisable()
{
RenderPipelineManager.beginFrameRendering -= BeginFrame;
RenderPipelineManager.endFrameRendering -= EndFrame;
}
private void BeginFrame(ScriptableRenderContext arg1, Camera[] arg2)
{
if (Spline == null) return;
foreach (Transform child in transform)
{
var scale = 1 - ScaleOffset * child.GetSiblingIndex();
child.localScale = Vector3.one * scale;
var offset = flipDirection
? Distance + PositionOffset * child.GetSiblingIndex()
: Distance - PositionOffset * child.GetSiblingIndex();
offset = Mathf.Clamp(offset, 0, m_SplineLength - float.MinValue);
var (pos, rot) = GotPositionAndRotation(offset);
child.SetPositionAndRotation(pos, rot);
}
}
private void EndFrame(ScriptableRenderContext arg1, Camera[] arg2)
{
// We dont revert the transform in playmode since this is not serialized, and we would like the playmode logic to see the moved transform.
if (Application.isPlaying) return;
foreach (Transform child in transform)
{
child.SetPositionAndRotation(Vector3.zero, quaternion.identity);
child.localScale = Vector3.one;
}
}
private (Vector3, Quaternion) GotPositionAndRotation(float distance)
{
Profiler.BeginSample("GotPositionAndRotation");
float splineTime = GetSplineTime(distance);
Profiler.BeginSample("EvaluateSpline");
Spline.Evaluate(splineTime, out var position, out var forward, out var up);
Profiler.EndSample();
Quaternion rotation = Quaternion.LookRotation(flipDirection ? -forward : forward, up);
Profiler.EndSample();
return (position, rotation);
}
private float GetSplineTime(float distance)
{
return SplineUtility.GetNormalizedInterpolation(Spline.Spline, distance, PathIndexUnit.Distance);
}
}