using System;
using Unity.Collections;
namespace UnityEngine.Splines
{
///
/// SplineComputeBufferScope is a convenient way to extract from a spline the information necessary to evaluate
/// spline values in a ComputeShader.
/// To access Spline evaluation methods in a shader, include the "Splines.cginc" file:
/// #include "Packages/com.unity.splines/Shader/Spline.cginc"
///
/// The type of spline.
public struct SplineComputeBufferScope : IDisposable where T : ISpline
{
T m_Spline;
int m_KnotCount;
ComputeBuffer m_CurveBuffer, m_LengthBuffer;
// Optional shader property bindings
ComputeShader m_Shader;
string m_Info, m_Curves, m_CurveLengths;
int m_Kernel;
///
/// Create a new SplineComputeBufferScope.
///
/// The spline to create GPU data for.
public SplineComputeBufferScope(T spline)
{
m_Spline = spline;
m_KnotCount = 0;
m_CurveBuffer = m_LengthBuffer = null;
m_Shader = null;
m_Info = m_Curves = m_CurveLengths = null;
m_Kernel = 0;
Upload();
}
///
/// Set up a shader with all of the necessary ComputeBuffer and Spline metadata for working with functions found
/// in Spline.cginc.
///
/// The compute shader to bind.
/// The kernel to target.
/// The float4 (typedef to SplineData in Spline.cginc) Spline info.
/// A StructuredBuffer{BezierCurve} or RWStructuredBuffer{BezierCurve}.
/// A StructuredBuffer{float} or RWStructuredBuffer{float}.
/// Thrown if any of the expected properties are invalid.
public void Bind(ComputeShader shader, int kernel, string info, string curves, string lengths)
{
if (shader == null) throw new ArgumentNullException(nameof(shader));
if (string.IsNullOrEmpty(info)) throw new ArgumentNullException(nameof(info));
if (string.IsNullOrEmpty(curves)) throw new ArgumentNullException(nameof(curves));
if (string.IsNullOrEmpty(lengths)) throw new ArgumentNullException(nameof(lengths));
m_Shader = shader;
m_Info = info;
m_Curves = curves;
m_CurveLengths = lengths;
m_Kernel = kernel;
m_Shader.SetVector(m_Info, Info);
m_Shader.SetBuffer(m_Kernel, m_Curves, Curves);
m_Shader.SetBuffer(m_Kernel, m_CurveLengths, CurveLengths);
}
///
/// Free resources allocated by this object.
///
public void Dispose()
{
m_CurveBuffer?.Dispose();
m_LengthBuffer?.Dispose();
}
///
/// Copy Spline curve, info, and length caches to their GPU buffers.
///
public void Upload()
{
int knotCount = m_Spline.Count;
if (m_KnotCount != knotCount)
{
m_KnotCount = m_Spline.Count;
m_CurveBuffer?.Dispose();
m_LengthBuffer?.Dispose();
m_CurveBuffer = new ComputeBuffer(m_KnotCount, sizeof(float) * 3 * 4);
m_LengthBuffer = new ComputeBuffer(m_KnotCount, sizeof(float));
}
var curves = new NativeArray(m_KnotCount, Allocator.Temp);
var lengths = new NativeArray(m_KnotCount, Allocator.Temp);
for (int i = 0; i < m_KnotCount; ++i)
{
curves[i] = m_Spline.GetCurve(i);
lengths[i] = m_Spline.GetCurveLength(i);
}
if(!string.IsNullOrEmpty(m_Info))
m_Shader.SetVector(m_Info, Info);
m_CurveBuffer.SetData(curves);
m_LengthBuffer.SetData(lengths);
curves.Dispose();
lengths.Dispose();
}
///
/// Returns a SplineInfo Vector4.
///
public Vector4 Info => new Vector4(m_Spline.Count, m_Spline.Closed ? 1 : 0, m_Spline.GetLength(), 0);
///
/// A ComputeBuffer containing .
///
public ComputeBuffer Curves => m_CurveBuffer;
///
/// A ComputeBuffer containing the cached length of all spline curves.
///
public ComputeBuffer CurveLengths => m_LengthBuffer;
}
}