I've portet a C implementation for (uniform) B-spline surfaces into unity(c#), since i didnt find a ready to go C# version. (it is not optimized for runtime manipulation yet (deBor etc.)) Here it is: BSplineSurface.cs Code (csharp): using UnityEngine; using System.Collections; using System.Collections.Generic; public class BSplineSurface { /* * THESE VALUES MUST BE SET BEFORE CALCULATING */ //size of the control net (e.g. 3x4 net) public int NI = 4; //setting these to high can crash unity public int NJ = 4; //Grid of control points public Vector3[,] controlGrid; //The degree in each direction public int TI = 3; public int TJ = 3; //output GRID resolution (e.g. 30x40) public int RESOLUTIONI = 150; //setting these to high can crash unity public int RESOLUTIONJ = 150; //the output Grid public Vector3[,] outputGrid; /* * INTERNAL VALUES */ //internal knots in each direction private int[] knotsI; private int[] knotsJ; //internal variables private int i, j, ki, kj; private float intervalI, incrementI, intervalJ, incrementJ, bi, bj; //FUNCTIONS private BSplineMath bmath = new BSplineMath(); //constructor public BSplineSurface() { Init(); } //MUST BE CALLED FIRST public void Init () { controlGrid = new Vector3[NI+1,NJ+1]; outputGrid = new Vector3[RESOLUTIONI, RESOLUTIONJ]; //init step size (the increment steps) incrementI = (NI-TI+2) / ((float)RESOLUTIONI - 1); incrementJ = (NJ-TJ+2) / ((float)RESOLUTIONJ - 1); //Calculate KNOTS knotsI = bmath.SplineKnots(NI, TI); knotsJ = bmath.SplineKnots(NJ, TJ); } // Use this for random initialization public void InitRandomGrid () { //init control points (random z) for(i=0; i<=NI; i++) { for(j=0; j<=NJ; j++) { controlGrid[i, j].x = i; controlGrid[i, j].y = j; controlGrid[i, j].z = Random.value; } } } // Use this for grid input (remember to set NI and NJ before(the grid size) and call Init) public void InitGrid (Vector3[,] inputGrid) { //init control points (random z) for(i=0; i<=NI; i++) { for(j=0; j<=NJ; j++) { controlGrid[i, j] = inputGrid[i, j]; } } } public void Calculate() { //MAIN CALCULATIONS intervalI = 0; for(i = 0; i < RESOLUTIONI-1; i++) { intervalJ = 0; for(j = 0; j < RESOLUTIONJ-1; j++) { outputGrid[i, j] = Vector3.zero; for(ki = 0; ki <= NI; ki++) { for(kj = 0; kj <= NJ; kj++) { bi = bmath.SplineBlend(ki, TI, knotsI, intervalI); bj = bmath.SplineBlend(kj, TJ, knotsJ, intervalJ); outputGrid[i, j].x += (controlGrid[ki, kj].x * bi * bj); outputGrid[i, j].y += (controlGrid[ki, kj].y * bi * bj); outputGrid[i, j].z += (controlGrid[ki, kj].z * bi * bj); } } intervalJ += incrementJ; } intervalI += incrementI; } intervalI = 0; for(i = 0; i < RESOLUTIONI-1; i++) { outputGrid[i, RESOLUTIONJ-1] = Vector3.zero; for(ki = 0; ki <= NI; ki++) { bi = bmath.SplineBlend(ki, TI, knotsI, intervalI); outputGrid[i, RESOLUTIONJ-1].x += (controlGrid[ki, NJ].x * bi); outputGrid[i, RESOLUTIONJ-1].y += (controlGrid[ki, NJ].y * bi); outputGrid[i, RESOLUTIONJ-1].z += (controlGrid[ki, NJ].z * bi); } intervalI += incrementI; } outputGrid[i, RESOLUTIONJ-1] = controlGrid[NI, NJ]; intervalJ = 0; for(j = 0; j < RESOLUTIONJ-1; j++) { outputGrid[RESOLUTIONI-1, j] = Vector3.zero; for(kj = 0; kj <= NJ; kj++) { bj = bmath.SplineBlend(kj, TJ, knotsJ, intervalJ); outputGrid[RESOLUTIONI-1, j].x += (controlGrid[NI, kj].x * bj); outputGrid[RESOLUTIONI-1, j].y += (controlGrid[NI, kj].y * bj); outputGrid[RESOLUTIONI-1, j].z += (controlGrid[NI, kj].z * bj); } intervalJ += incrementJ; } outputGrid[RESOLUTIONI-1, j] = controlGrid[NI, NJ]; } } BSplineMath.cs Code (csharp): using UnityEngine; using System.Collections; public class BSplineMath { //constructor public BSplineMath() { } public int[] SplineKnots(int n, int t) { int[] u = new int[n+t+1]; for(int j=0; j<n+t; j++) { if(j < t) u[j] = 0; else if(j <= n) u[j] = j - t + 1; else if(j > n) u[j] = n - t + 2; } return u; } public float SplineBlend(int k, int t, int[] u, float v) { float rvalue = 0; if(t == 1) { if((u[k] <= v) (v < u[k+1])) rvalue = 1; else rvalue = 0; }else{ if ((u[k+t-1] == u[k]) (u[k+t] == u[k+1])) rvalue = 0; else if (u[k+t-1] == u[k]) rvalue = (u[k+t] - v) / (u[k+t] - u[k+1]) * SplineBlend(k+1,t-1,u,v); else if (u[k+t] == u[k+1]) rvalue = (v - u[k]) / (u[k+t-1] - u[k]) * SplineBlend(k,t-1,u,v); else rvalue = (v - u[k]) / (u[k+t-1] - u[k]) * SplineBlend(k,t-1,u,v) + (u[k+t] - v) / (u[k+t] - u[k+1]) * SplineBlend(k+1,t-1,u,v); } return rvalue; } } USAGE EXAMPLE Code (csharp): using UnityEngine; using System; using System.Collections; using System.Collections.Generic; public class testSplines : MonoBehaviour { BSplineSurface mySurface; public Vector3[,] resultGrid; public Vector3[,] controlGrid; // Use this for initialization void Start () { mySurface = new BSplineSurface(); mySurface.InitRandomGrid(); mySurface.Calculate(); resultGrid = mySurface.outputGrid; controlGrid = mySurface.controlGrid; generateMesh(); updateMesh(); } // Update is called once per frame void Update () { int j = 0; //CONTROL DRAWS for(int i=0; i<mySurface.NI; i++) { for(j=0; j<mySurface.NJ; j++) { Debug.DrawLine(controlGrid[i, j], controlGrid[i+1, j], Color.red); Debug.DrawLine(controlGrid[i, j], controlGrid[i, j+1], Color.red); } Debug.DrawLine(controlGrid[i, j], controlGrid[i+1, j], Color.red); } for(int i=0; i<mySurface.NJ; i++) { Debug.DrawLine(controlGrid[mySurface.NI, i], controlGrid[mySurface.NI, i+1], Color.red); } } //generate a Mesh private void generateMesh() { Mesh mesh = GetComponent<MeshFilter>().mesh; int width = mySurface.RESOLUTIONI; int height = mySurface.RESOLUTIONJ; int y = 0; int x = 0; // Build vertices and UVs Vector3[] vertices = new Vector3[height * width]; Vector2[] uv = new Vector2[height * width]; for (y=0;y<height;y++) { for (x=0;x<width;x++) { vertices[y*width + x] = new Vector3 (x, 0, y); uv[y*width + x] = new Vector2(x, y); } } // Assign them to the mesh mesh.vertices = vertices; mesh.uv = uv; // Build triangle indices: 3 indices into vertex array for each triangle int[] triangles = new int[(height - 1) * (width - 1) * 6]; int index = 0; for (y=0;y<height-1;y++) { for (x=0;x<width-1;x++) { // For each grid cell output two triangles triangles[index++] = (y * width) + x; triangles[index++] = ((y+1) * width) + x; triangles[index++] = (y * width) + x + 1; triangles[index++] = ((y+1) * width) + x; triangles[index++] = ((y+1) * width) + x + 1; triangles[index++] = (y * width) + x + 1; } } // And assign them to the mesh mesh.triangles = triangles; // Auto-calculate vertex normals from the mesh mesh.RecalculateNormals(); } private void updateMesh() { Mesh mesh = GetComponent<MeshFilter>().mesh; int width = mySurface.RESOLUTIONI; int height = mySurface.RESOLUTIONJ; int y = 0; int x = 0; // Build vertices and UVs Vector3[] vertices = new Vector3[height * width]; for (y=0;y<height;y++) { for (x=0;x<width;x++) { vertices[y*width + x] = resultGrid[x, y]; } } mesh.vertices = vertices; mesh.RecalculateNormals(); MeshCollider mcol = GetComponent<MeshCollider>(); mcol.sharedMesh = null; mcol.sharedMesh = mesh; } }
I get: The class named 'BSplineSurface' is not derived from MonoBehaviour or ScriptableObject! Thanks for help
For those of you who are still interested in this, the original C Implentation is available here: http://paulbourke.net/geometry/spline/
The problem is the script "BSplineMath.cs", I've fix it like this : line 37: if((u[k] <= v) && (v < u[k+1])) line 43: if ((u[k+t-1] == u[k]) && (u[k+t] == u[k+1]))