using System;
using UnityEngine;
using UnityEngine.Splines;
namespace Unity.Splines.Examples
{
///
/// A simple example showing how to pass Spline data to the GPU using SplineComputeBufferScope.
///
[RequireComponent(typeof(LineRenderer), typeof(SplineContainer))]
public class SplineRendererCompute : MonoBehaviour
{
// Use with Shader/InterpolateSpline.compute
[SerializeField]
ComputeShader m_ComputeShader;
[SerializeField, Range(16, 512)]
int m_Segments = 128;
Spline m_Spline;
LineRenderer m_Line;
bool m_Dirty;
SplineComputeBufferScope m_SplineBuffers;
Vector3[] m_Positions;
ComputeBuffer m_PositionsBuffer;
int m_GetPositionsKernel;
void Awake()
{
m_Spline = GetComponent().Spline;
// Set up the LineRenderer
m_Line = GetComponent();
m_Line.positionCount = m_Segments;
m_GetPositionsKernel = m_ComputeShader.FindKernel("GetPositions");
// Set up the spline evaluation compute shader. We'll use SplineComputeBufferScope to simplify the process.
// Note that SplineComputeBufferScope is optional, you can manage the Curve, Lengths, and Info properties
// yourself if preferred.
m_SplineBuffers = new SplineComputeBufferScope(m_Spline);
m_SplineBuffers.Bind(m_ComputeShader, m_GetPositionsKernel, "info", "curves", "curveLengths");
// Set the compute shader properties necessary for accessing spline information. Most Spline functions in
// Spline.cginc require the info, curves, and curve length properties. This is equivalent to:
// m_ComputeShader.SetVector("info", m_SplineBuffers.Info);
// m_ComputeShader.SetBuffer(m_GetPositionsKernel, "curves", m_SplineBuffers.Curves);
// m_ComputeShader.SetBuffer(m_GetPositionsKernel, "curveLengths", m_SplineBuffers.CurveLengths);
m_SplineBuffers.Upload();
// m_Positions will be used to read back evaluated positions from the GPU
m_Positions = new Vector3[m_Segments];
// Set up our input and readback buffers. In this example we'll evaluate a set of positions along the spline
m_PositionsBuffer = new ComputeBuffer(m_Segments, sizeof(float) * 3);
m_PositionsBuffer.SetData(m_Positions);
m_ComputeShader.SetBuffer(m_GetPositionsKernel, "positions", m_PositionsBuffer);
m_ComputeShader.SetFloat("positionsCount", m_Segments);
// Subscribe to Spline.changed to be notified when the spline is modified
m_Spline.changed += () => m_Dirty = true;
m_Dirty = true;
}
void OnDestroy()
{
m_PositionsBuffer?.Dispose();
m_SplineBuffers.Dispose();
}
void Update()
{
if (!m_Dirty)
return;
// Once initialized, call SplineComputeBufferScope.Upload() to update the GPU copies of spline data. This
// is only necessary here because we're constantly updating the Spline in this example. If the Spline is
// static, there is no need to call Upload every frame.
m_SplineBuffers.Upload();
m_ComputeShader.GetKernelThreadGroupSizes(m_GetPositionsKernel, out var threadSize, out _, out _);
m_ComputeShader.Dispatch(m_GetPositionsKernel, (int) threadSize, 1, 1);
m_PositionsBuffer.GetData(m_Positions);
m_Line.loop = m_Spline.Closed;
m_Line.SetPositions(m_Positions);
}
}
}