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; } }