9using System.Collections.Generic;
23 [Tooltip(
"Must have at least one more control point than this value.")]
34 private List<Vector3> _pointsBuffer =
new List<Vector3>();
35 private List<float> _knotVectorBuffer =
new List<float>();
37 private List<Vector3> _outputBuffer =
new List<Vector3>();
39 private void Update() {
40 _pointsBuffer.Clear();
43 _pointsBuffer.Add(child.position);
62 if (_pointsBuffer.Count > 1) {
67 var usePolyDegree = Mathf.Min(
polyDegree, _pointsBuffer.Count - 1);
69 _knotVectorBuffer.Clear();
70 calculateKnotVector(usePolyDegree, _pointsBuffer.Count,
isUniform:
true,
71 fillKnotVector: _knotVectorBuffer);
74 _outputBuffer.Clear();
75 for (
float t = 0; t < 1f; t += step) {
76 _outputBuffer.Add(interpolateRationalBSpline(_pointsBuffer,
83 if (_pointsBuffer.Count > 1) {
84 var currFraction = 0f;
85 var fractionStep = 1f / (_outputBuffer.Count - 1);
87 var end = _outputBuffer.Count - 1;
90 start = _outputBuffer.Count - 1;
94 for (
int i = start; i != end; i += dir) {
95 var curr = _outputBuffer[i];
96 var next = _outputBuffer[i + dir];
98 currFraction += fractionStep;
111 private void calculateKnotVector(
int polyDegree,
int numControlPoints,
112 bool isUniform, List<float> fillKnotVector =
null)
114 if (
polyDegree + 1 > numControlPoints || numControlPoints == 0) {
118 StringBuilder outText =
new StringBuilder();
120 int n = numControlPoints;
125 fillKnotVector.Add(0);
127 for (
int i = 1; i < m; i++) {
129 fillKnotVector.Add(1);
130 outText.Append(
", 1");
133 fillKnotVector.Add(i / (
float)divisor);
134 outText.Append(
", " + i.ToString() +
"/" + divisor.ToString());
141 for (
int i = 0; i < m; i++) {
143 fillKnotVector.Add(0);
144 outText.Append(
", 0");
147 fillKnotVector.Add(1);
148 outText.Append(
", 1");
152 fillKnotVector.Add(numerator / (
float)divisor);
153 outText.Append(
", " + numerator.ToString() +
"/" +
160 private Vector3 interpolateBSpline(List<Vector3> controlPoints,
161 int polyDegree, List<float> knotVector,
float t)
163 float x = 0, y = 0, z = 0;
164 for (
int i = 0; i < controlPoints.Count; i++) {
165 var knotWeight = calcKnotWeight(i,
polyDegree, knotVector, t);
166 x += controlPoints[i].x * knotWeight;
167 y += controlPoints[i].y * knotWeight;
168 z += controlPoints[i].z * knotWeight;
173 private Vector3 interpolateRationalBSpline(List<Vector3> controlPoints,
174 List<float> controlPointWeights,
int polyDegree, List<float> knotVector,
177 float x = 0, y = 0, z = 0;
178 float totalWeight = 0f;
180 for (
int i = 0; i < controlPoints.Count; i++) {
181 var knotWeight = calcKnotWeight(i,
polyDegree, knotVector, t) *
182 controlPointWeights[i];
183 totalWeight += knotWeight;
186 for (
int i = 0; i < controlPoints.Count; i++) {
187 var knotWeight = calcKnotWeight(i,
polyDegree, knotVector, t);
188 x += controlPoints[i].x * controlPointWeights[i] * knotWeight /
190 y += controlPoints[i].y * controlPointWeights[i] * knotWeight /
192 z += controlPoints[i].z * controlPointWeights[i] * knotWeight /
199 private float[] N =
new float[128];
200 private float calcKnotWeight(
int i,
int polyDegree, List<float> knotVector,
206 int maxKnotVectorIndex = knotVector.Count - 1;
207 if ((i == 0 && t == knotVector[0]) ||
208 (i == (maxKnotVectorIndex -
polyDegree - 1) &&
209 t == knotVector[maxKnotVectorIndex]))
213 if (t < knotVector[i] || t >= knotVector[i +
polyDegree + 1]) {
218 if (t >= knotVector[i + j] && t < knotVector[i + j + 1]) {
231 saved = ((t - knotVector[i]) * N[0]) /
232 (knotVector[i + k] - knotVector[i]);
235 for (
int j = 0; j <
polyDegree - k + 1; j++) {
236 float knotVectorLeft = knotVector[i + j + 1];
237 float knotVectorRight = knotVector[i + j + k + 1];
244 temp = N[j + 1] / (knotVectorRight - knotVectorLeft);
245 N[j] = saved + (knotVectorRight - t) * temp;
246 saved = (t - knotVectorLeft) * temp;
Simple drawing interface abstraction (intended for debug drawing, not production!) with statically-ac...
static Drawer UnityGizmoDrawer
For use in OnDrawGizmos and OnDrawGizmosSelected.
void Line(Vector3 a, Vector3 b)
void SetRenderFraction(float t)
List< float > _weightsBuffer