Bezier Patch

No fanfare, no lengthy preamble, just the code to a bezier patch generator:
// Bezier.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <3DIO/3DIO.h> #include <vector> #include <string> using namespace tdio_library; using namespace std; void create_patch(float step); void save_patch(const string &name); void load_bez(const string &name); vector<vector3> pts; vector3 ctrlPts[4][4]; vector<std::vector<int>> faces; int main(int argc, char* argv[]) { load_bez("config.txt"); if(argc >= 2)create_patch(atof(argv[1])); else create_patch(0.2); save_patch("test.obj"); return 0; } void load_bez(const string &name){ FILE *stream = fopen(name.c_str(),"r"); char buffer[256]; int ct = 0; while(!feof(stream)){ if(fgets(buffer,256,stream)==NULL)break; float x[4],y[4],z[4]; char ch; if(buffer[0] == 'c'){ sscanf(buffer,"%c %f %f %f %f %f %f %f %f %f %f %f %f",&ch,&x[0],&y[0],&z[0],&x[1],&y[1],&z[1],&x[2],&y[2],&z[2],&x[3],&y[3],&z[3]); ctrlPts[ct][0] = vector3(x[0],y[0],z[0]); ctrlPts[ct][1] = vector3(x[1],y[1],z[1]); ctrlPts[ct][2] = vector3(x[2],y[2],z[2]); ctrlPts[ct][3] = vector3(x[3],y[3],z[3]); ct++; } if(ct >= 4)break; } if(ct != 4){ printf(" - Warning, read %d control lines. Should be 4\n",ct); } fclose(stream); } void save_patch(const string &name){ FILE *stream = fopen(name.c_str(),"w"); for(int v = 0; v < pts.size(); v++){ fprintf(stream,"v %f %f %f\n",pts[v].x,pts[v].y,pts[v].z); } for(int f = 0; f < faces.size(); f++){ fprintf(stream,"f %d %d %d\n",faces[f][0]+1,faces[f][1]+1,faces[f][2]+1); } fclose(stream); } vector3 get_bez_pt(float u, float v){ double tmp = 0; double c[4] = {1,3,3,1}; vector3 ret(0,0,0); for(int i = 0; i < 4; i++){ for(int j = 0; j < 4; j++){ tmp = c[i]*c[j] * pow(u,i) * pow(1-u,3-i)*pow(v,j)*pow(1-v,3-j); ret.x += ctrlPts[i][j].cell[0] *tmp; ret.y += ctrlPts[i][j].cell[1] *tmp; ret.z += ctrlPts[i][j].cell[2] *tmp; } } return ret; } void create_patch(float step){ printf("-- Create Patch--\n"); printf(" - Step: %f\n",step); for(float x = 0; x < 3; x+=step){ for(float z = 0; z < 3; z+=step){ vector3 pt = get_bez_pt(x/3,z/3); pts.push_back(pt); } } printf(" - nPts: %d\n",pts.size()); int width = (float)(3.0f/step + 1.0); int height = width; printf(" - Height/Width: %d\n",height); int f = 0; for(int v = 0; v < pts.size(); v++){ if(v+width+1 >= pts.size())break; if((v+1) % (int)width != 0 || v ==0){ std::vector<int> tmp; faces.push_back(tmp); faces[f].push_back(v); faces[f].push_back(v+1); faces[f].push_back(v+width); f++; faces.push_back(tmp); faces[f].push_back(v+1); faces[f].push_back(v+width+1); faces[f].push_back(v+width); f++; } } printf(" - %d faces created\n",faces.size()); }
The 3DIO.h file can be found my open source repository. The function ‘create_patch()’ creates a uniform patch of triangles between 0 & 3 in the X and Z axes. Gradients should be chosen to be between this range, I recommend 0.09. Control points are loaded in the function ‘load_bez()’ from a configuration file that looks like so:
#row 0
c 0 5 0 0 0 1 0 0 2 0 0 3#row 2 of control pts
c 1 0 0 1 10 1 1 -15 2 1 0 3#row 3 of control pts
c 2 0 0 2 -5 1 2 25 2 2 0 3#row 4 of control pts
c 0 0 0 3 0 1 3 0 2 3 0 3
Each row controls 4 control points. You can ignore the ‘c’ value and concentrate on the following 16 floating point values. Like so: c x1 y1 z1 x2 y2 z2…… I recommend modifying the Y values first. Messing with X/Z can have weird consequences. Output is saves as a very basic .obj file.
The code, as always, is provided “as is”, with little explanation. I suggest reading up on Bezier patches to get an idea of what the code is doing. I’m happy to answer questions like usual but do your homework.