Archive

Posts Tagged ‘bezier’

Bezier Patch

December 21st, 2009 admin No comments

bezier
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.

Categories: Coding Tags: , , ,