从四面体细分生成一个球网格的小代码。
参考opengl redbook 的第二章。
#include <cstdio>
#include <cmath>
#include <fstream>
#include <iostream>
using std::ofstream;
typedef float FLOAT;
struct Point3{
FLOAT c[3];
FLOAT& operator[](int i) { return c[i]; }
const FLOAT operator[](int i) const { return c[i]; }
};
struct Triangle3{
int t[3];
int& operator[](int i) { return t[i]; }
const int operator[](int i) const { return t[i]; }
};
void normalize(Point3 &v){
FLOAT d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
if (d == 0.0) {
printf("zero length vector\n");
return;
}
v[0] /= d; v[1] /= d; v[2] /= d;
}
#include <vector>
using std::vector;
vector<Point3> points;
vector<Triangle3> triangles;
vector<Point3> points_old;
vector<Triangle3> triangles_old;
int insert(const Point3 &v,vector<Point3> &points){
Point3 P;
FLOAT error;
for(int i = 0 ; i<points.size();i++){
P = points[i];
error = sqrt((P[0]-v[0])*(P[0]-v[0])+(P[1]-v[1])*(P[1]-v[1])
+(P[2]-v[2])*(P[2]-v[2]));
if(error<1e-5)
return i;
}
points.push_back(v);
return points.size()-1;
}
void genTriangle(Point3 &v1, Point3 &v2, Point3 &v3){
int i = insert(v1,points);
int j = insert(v2,points);
int k = insert(v3,points);
Triangle3 T;
T[0] = i; T[1] = j; T[2] = k;
triangles.push_back(T);
}
void subdivide(Point3 &v1, Point3 &v2, Point3 &v3)
{
Point3 v12, v23, v31;
// FLOAT v12[3], v23[3], v31[3];
int i;
for (i = 0; i < 3; i++) {
v12[i] = v1[i]+v2[i];
v23[i] = v2[i]+v3[i];
v31[i] = v3[i]+v1[i];
}
normalize(v12);
normalize(v23);
normalize(v31);
genTriangle(v1, v12, v31);
genTriangle(v2, v23, v12);
genTriangle(v3, v31, v23);
genTriangle(v12, v23, v31);
}
void copy(const vector<Point3> &points,vector<Point3> &dst_points){
dst_points.clear();
for(int i = 0 ; i<points.size();i++){
dst_points.push_back(points[i]);
}
}
void copy(const vector<Triangle3> &triangles,vector<Triangle3> &dst_triangles){
dst_triangles.clear();
for(int i = 0 ; i<triangles.size();i++){
dst_triangles.push_back(triangles[i]);
}
}
//#define OFF_FORMAT
void genSphere(){
Point3 P;
Triangle3 T;
P[0] = 1; P[1] = 0; P[2] = 0;
points.push_back(P);
P[0] = -1; P[1] = 0; P[2] = 0;
points.push_back(P);
P[0] = 0; P[1] = 1; P[2] = 0;
points.push_back(P);
P[0] = 0; P[1] = -1; P[2] = 0;
points.push_back(P);
P[0] = 0; P[1] = 0; P[2] = 1;
points.push_back(P);
P[0] = 0; P[1] = 0; P[2] = -1;
points.push_back(P);
T[0] = 0; T[1] = 4; T[2] = 2;
triangles.push_back(T);
T[0] = 2; T[1] = 4; T[2] = 1;
triangles.push_back(T);
T[0] = 1; T[1] = 4; T[2] = 3;
triangles.push_back(T);
T[0] = 3; T[1] = 4; T[2] = 0;
triangles.push_back(T);
T[0] = 0; T[1] = 2; T[2] = 5;
triangles.push_back(T);
T[0] = 2; T[1] = 1; T[2] = 5;
triangles.push_back(T);
T[0] = 1; T[1] = 3; T[2] = 5;
triangles.push_back(T);
T[0] = 3; T[1] = 0; T[2] = 5;
triangles.push_back(T);
Point3 v1,v2,v3;
int level = 6;
for(int l = 0 ; l<level;l++){
copy(points,points_old);
copy(triangles,triangles_old);
triangles.clear();
for(int j =0; j<triangles_old.size();j++){
T[0] = triangles_old[j][0];
T[1] = triangles_old[j][1];
T[2] = triangles_old[j][2];
v1 = points_old[T[0]];
v2 = points_old[T[1]];
v3 = points_old[T[2]];
subdivide(v1,v2,v3);
}
std::cout<<"vertices: "<<points.size()<<" triangles: "<<triangles.size()<<std::endl;
}
//output
std::cout<<"start to write to sphere.txt...\n";
#ifdef OFF_FORMAT
ofstream oF("sphere.off");
if(!oF) return;
oF<<"OFF\n";
oF<<points.size()<<" "<<triangles.size()<<" 0\n";
#else
ofstream oF("sphere.txt");
if(!oF) return;
oF<<points.size()<<" "<<triangles.size()<<"\n";
#endif
for(int i = 0 ; i<points.size();i++)
oF<<points[i][0]<<" "<<points[i][1]<<" "<<points[i][2]<<"\n";
for(int i = 0 ; i<triangles.size();i++)
#ifdef OFF_FORMAT
oF<<"3 "<<triangles[i][0]<<" "<<triangles[i][1]<<" "<<triangles[i][2]<<"\n";
#else
oF<<triangles[i][0]<<" "<<triangles[i][1]<<" "<<triangles[i][2]<<"\n";
#endif
oF.close();
std::cout<<"finished writing!\n";
}