26 #define loopi(start_l, end_l) for (int i = start_l; i < end_l; ++i) 27 #define loopi(start_l, end_l) for (int i = start_l; i < end_l; ++i) 28 #define loopj(start_l, end_l) for (int j = start_l; j < end_l; ++j) 29 #define loopk(start_l, end_l) for (int k = start_l; k < end_l; ++k) 52 inline vec3f(
const double X,
const double Y,
const double Z)
61 return vec3f(x + a.
x, y + a.
y, z + a.
z);
66 return vec3f(x + a.
x, y + a.
y, z + a.
z);
71 return vec3f(x * a, y * a, z * a);
76 return vec3f(x * a.
x, y * a.
y, z * a.
z);
81 return vec3f(x, y, z);
102 return vec3f(x / a.
x, y / a.
y, z / a.
z);
107 return vec3f(x - a.
x, y - a.
y, z - a.
z);
112 return vec3f(x / a, y / a, z / a);
117 return a.
x * x + a.
y * y + a.
z *
z;
122 x = a.
y * b.
z - a.
z * b.
y;
123 y = a.
z * b.
x - a.
x * b.
z;
124 z = a.
x * b.
y - a.
y * b.
x;
130 vec3f a = v, b = *
this;
131 double dot = v.
x * x + v.
y * y + v.
z *
z;
132 double len = a.
length() * b.length();
135 double input = dot / len;
140 return (
double)acos(input);
145 vec3f a = v, b = *
this;
146 double dot = a.
x * b.x + a.
y * b.y + a.
z * b.z;
147 double len = a.
length() * b.length();
154 if (plane.
x * a.
x + plane.
y * a.
y + plane.
z * a.
z > 0)
155 return (
double)-acos(dot / len);
157 return (
double)acos(dot / len);
162 double yy = cos(a) * y + sin(a) *
z;
163 double zz = cos(a) * z - sin(a) *
y;
170 double xx = cos(-a) * x + sin(-a) *
z;
171 double zz = cos(-a) * z - sin(-a) *
x;
193 double yy = cos(a) * y + sin(a) *
x;
194 double xx = cos(a) * x - sin(a) *
y;
224 return (
double)sqrt(x * x + y * y + z * z);
229 double square = sqrt(x * x + y * y + z * z);
245 static void random_init();
246 static double random_double();
247 static vec3f random();
253 double rnf = a * 14.434252 + a * 364.2343 + a * 4213.45352 + a * 2341.43255 + a * 254341.43535 + a * 223454341.3523534245 + 23453.423412;
254 int rni = ((int)rnf) % 100000;
255 return double(rni) / (100000.0f - 1.0f);
260 x = (double)random_double_01(x);
261 y = (double)random_double_01(y);
262 z = (double)random_double_01(z);
272 double d00 = v0.
dot(v0);
273 double d01 = v0.
dot(v1);
274 double d11 = v1.
dot(v1);
275 double d20 = v2.
dot(v0);
276 double d21 = v2.
dot(v1);
277 double denom = d00 * d11 - d01 * d01;
278 double v = (d11 * d20 - d01 * d21) / denom;
279 double w = (d00 * d21 - d01 * d20) / denom;
280 double u = 1.0 - v - w;
281 return vec3f(u, v, w);
288 out = out + attrs[0] * bary.
x;
289 out = out + attrs[1] * bary.
y;
290 out = out + attrs[2] * bary.
z;
294 double min(
double v1,
double v2)
308 double m22,
double m23,
double m24,
309 double m33,
double m34,
344 double det(
int a11,
int a12,
int a13,
345 int a21,
int a22,
int a23,
346 int a31,
int a32,
int a33)
348 double det = m[a11] * m[a22] * m[a33] + m[a13] * m[a21] * m[a32] + m[a12] * m[a23] * m[a31] - m[a13] * m[a22] * m[a31] - m[a11] * m[a23] * m[a32] - m[a12] * m[a21] * m[a33];
354 return SymetricMatrix(m[0] + n[0], m[1] + n[1], m[2] + n[2], m[3] + n[3],
355 m[4] + n[4], m[5] + n[5], m[6] + n[6],
356 m[7] + n[7], m[8] + n[8],
430 void simplify_mesh(
int target_count,
double agressiveness = 7,
bool verbose =
false)
433 loopi(0, triangles.size())
435 triangles[i].deleted = 0;
439 int deleted_triangles = 0;
440 std::vector<int> deleted0, deleted1;
441 int triangle_count = triangles.size();
444 for (
int iteration = 0; iteration < 100; iteration++)
446 if (triangle_count - deleted_triangles <= target_count)
450 if (iteration % 5 == 0)
452 update_mesh(iteration);
456 loopi(0, triangles.size()) triangles[i].dirty = 0;
464 double threshold = 0.000000001 * pow(
double(iteration + 3), agressiveness);
467 if ((verbose) && (iteration % 5 == 0))
469 printf(
"iteration %d - triangles %d threshold %g\n", iteration, triangle_count - deleted_triangles, threshold);
473 loopi(0, triangles.size())
476 if (t.
err[3] > threshold)
483 loopj(0, 3)
if (t.
err[j] < threshold)
487 Vertex &v0 = vertices[i0];
488 int i1 = t.
v[(j + 1) % 3];
489 Vertex &v1 = vertices[i1];
496 calculate_error(i0, i1, p);
497 deleted0.resize(v0.
tcount);
498 deleted1.resize(v1.
tcount);
500 if (flipped(p, i0, i1, v0, v1, deleted0))
503 if (flipped(p, i1, i0, v1, v0, deleted1))
508 update_uvs(i0, v0, p, deleted0);
509 update_uvs(i0, v1, p, deleted1);
515 int tstart = refs.size();
517 update_triangles(i0, v0, deleted0, deleted_triangles);
518 update_triangles(i0, v1, deleted1, deleted_triangles);
520 int tcount = refs.size() - tstart;
526 memcpy(&refs[v0.
tstart], &refs[tstart], tcount *
sizeof(
Ref));
536 if (triangle_count - deleted_triangles <= target_count)
547 loopi(0, triangles.size()) triangles[i].deleted = 0;
550 int deleted_triangles = 0;
551 std::vector<int> deleted0, deleted1;
555 for (
int iteration = 0; iteration < 9999; iteration++)
558 update_mesh(iteration);
560 loopi(0, triangles.size()) triangles[i].dirty = 0;
567 double threshold = DBL_EPSILON;
570 printf(
"lossless iteration %d\n", iteration);
574 loopi(0, triangles.size())
577 if (t.
err[3] > threshold)
584 loopj(0, 3)
if (t.
err[j] < threshold)
587 Vertex &v0 = vertices[i0];
588 int i1 = t.
v[(j + 1) % 3];
589 Vertex &v1 = vertices[i1];
597 calculate_error(i0, i1, p);
599 deleted0.resize(v0.
tcount);
600 deleted1.resize(v1.
tcount);
603 if (flipped(p, i0, i1, v0, v1, deleted0))
605 if (flipped(p, i1, i0, v1, v0, deleted1))
610 update_uvs(i0, v0, p, deleted0);
611 update_uvs(i0, v1, p, deleted1);
617 int tstart = refs.size();
619 update_triangles(i0, v0, deleted0, deleted_triangles);
620 update_triangles(i0, v1, deleted1, deleted_triangles);
622 int tcount = refs.size() - tstart;
628 memcpy(&refs[v0.
tstart], &refs[tstart], tcount *
sizeof(
Ref));
638 if (deleted_triangles <= 0)
640 deleted_triangles = 0;
657 int s = refs[v0.
tstart + k].tvertex;
658 int id1 = t.
v[(s + 1) % 3];
659 int id2 = t.
v[(s + 2) % 3];
661 if (id1 == i1 || id2 == i1)
667 vec3f d1 = vertices[id1].p - p;
669 vec3f d2 = vertices[id2].p - p;
671 if (fabs(d1.
dot(d2)) > 0.999)
677 if (n.
dot(t.
n) < 0.2)
695 vec3f p1 = vertices[t.
v[0]].p;
696 vec3f p2 = vertices[t.
v[1]].p;
697 vec3f p3 = vertices[t.
v[2]].p;
721 t.
err[0] = calculate_error(t.
v[0], t.
v[1], p);
722 t.
err[1] = calculate_error(t.
v[1], t.
v[2], p);
723 t.
err[2] = calculate_error(t.
v[2], t.
v[0], p);
736 loopi(0, triangles.size())
if (!triangles[i].deleted)
738 triangles[dst++] = triangles[i];
740 triangles.resize(dst);
745 loopi(0, vertices.size())
747 vertices[i].tstart = 0;
748 vertices[i].tcount = 0;
751 loopi(0, triangles.size())
754 loopj(0, 3) vertices[t.
v[j]].tcount++;
757 loopi(0, vertices.size())
766 refs.resize(triangles.size() * 3);
767 loopi(0, triangles.size())
789 std::vector<int> vcount, vids;
791 loopi(0, vertices.size())
795 loopi(0, vertices.size())
802 int k = refs[v.
tstart + j].tid;
806 int ofs = 0,
id = t.
v[k];
807 while (ofs < vcount.size())
813 if (ofs == vcount.size())
822 loopj(0, vcount.size())
if (vcount[j] == 1)
827 loopi(0, vertices.size())
831 loopi(0, triangles.size())
835 loopj(0, 3) p[j] = vertices[t.
v[j]].p;
836 n.
cross(p[1] - p[0], p[2] - p[0]);
839 loopj(0, 3) vertices[t.
v[j]].q =
842 loopi(0, triangles.size())
847 loopj(0, 3) t.
err[j] = calculate_error(t.
v[j], t.
v[(j + 1) % 3], p);
858 loopi(0, vertices.size())
860 vertices[i].tcount = 0;
862 loopi(0, triangles.size())
if (!triangles[i].deleted)
865 triangles[dst++] = t;
866 loopj(0, 3) vertices[t.
v[j]].tcount = 1;
868 triangles.resize(dst);
870 loopi(0, vertices.size())
if (vertices[i].tcount)
872 vertices[i].tstart = dst;
873 vertices[dst].p = vertices[i].p;
876 loopi(0, triangles.size())
879 loopj(0, 3) t.
v[j] = vertices[t.
v[j]].tstart;
881 vertices.resize(dst);
888 return q[0] * x * x + 2 * q[1] * x * y + 2 * q[2] * x * z + 2 * q[3] * x + q[4] * y * y + 2 * q[5] * y * z + 2 * q[6] * y + q[7] * z * z + 2 * q[8] * z + q[9];
898 bool border = vertices[id_v1].border & vertices[id_v2].border;
900 double det = q.
det(0, 1, 2, 1, 4, 5, 2, 5, 7);
901 if (det != 0 && !border)
905 p_result.
x = -1 / det * (q.
det(1, 2, 3, 4, 5, 6, 5, 7, 8));
906 p_result.
y = 1 / det * (q.
det(0, 2, 3, 1, 5, 6, 2, 7, 8));
907 p_result.
z = -1 / det * (q.
det(0, 1, 3, 1, 4, 6, 2, 5, 8));
909 error = vertex_error(q, p_result.
x, p_result.
y, p_result.
z);
914 vec3f p1 = vertices[id_v1].p;
915 vec3f p2 = vertices[id_v2].p;
916 vec3f p3 = (p1 + p2) / 2;
917 double error1 = vertex_error(q, p1.
x, p1.
y, p1.
z);
918 double error2 = vertex_error(q, p2.
x, p2.
y, p2.
z);
919 double error3 = vertex_error(q, p3.
x, p3.
y, p3.
z);
920 error =
min(error1,
min(error2, error3));
936 while (isspace((
unsigned char)*str))
943 end = str + strlen(str) - 1;
944 while (end > str && isspace((
unsigned char)*end))
954 void load_obj(
const char *filename,
bool process_uv =
false)
960 if (filename == NULL)
962 if ((
char)filename[0] == 0)
964 if ((fn = fopen(filename,
"rb")) == NULL)
966 printf(
"File %s not found!\n", filename);
970 memset(line, 0, 1000);
973 std::map<std::string, int> material_map;
974 std::vector<vec3f> uvs;
975 std::vector<std::vector<int>> uvMap;
977 while (fgets(line, 1000, fn) != NULL)
982 if (strncmp(line,
"mtllib", 6) == 0)
984 mtllib = trimwhitespace(&line[7]);
986 if (strncmp(line,
"usemtl", 6) == 0)
988 std::string usemtl = trimwhitespace(&line[7]);
989 if (material_map.find(usemtl) == material_map.end())
991 material_map[usemtl] = materials.size();
992 materials.push_back(usemtl);
994 material = material_map[usemtl];
997 if (line[0] ==
'v' && line[1] ==
't')
1000 if (sscanf(line,
"vt %lf %lf",
1006 else if (sscanf(line,
"vt %lf %lf %lf",
1007 &uv.
x, &uv.
y, &uv.
z) == 3)
1012 else if (line[0] ==
'v')
1015 if (sscanf(line,
"v %lf %lf %lf",
1016 &v.
p.
x, &v.
p.
y, &v.
p.
z) == 3)
1018 vertices.push_back(v);
1025 bool tri_ok =
false;
1026 bool has_uv =
false;
1028 if (sscanf(line,
"f %d %d %d",
1029 &integers[0], &integers[1], &integers[2]) == 3)
1033 else if (sscanf(line,
"f %d// %d// %d//",
1034 &integers[0], &integers[1], &integers[2]) == 3)
1038 else if (sscanf(line,
"f %d//%d %d//%d %d//%d",
1039 &integers[0], &integers[3],
1040 &integers[1], &integers[4],
1041 &integers[2], &integers[5]) == 6)
1045 else if (sscanf(line,
"f %d/%d/%d %d/%d/%d %d/%d/%d",
1046 &integers[0], &integers[6], &integers[3],
1047 &integers[1], &integers[7], &integers[4],
1048 &integers[2], &integers[8], &integers[5]) == 9)
1054 if (sscanf(line,
"f %d/%d %d/%d %d/%d",
1055 &integers[0], &integers[6],
1056 &integers[1], &integers[7],
1057 &integers[2], &integers[8]) == 6)
1064 printf(
"unrecognized sequence\n");
1065 printf(
"%s\n", line);
1071 t.
v[0] = integers[0] - 1 - vertex_cnt;
1072 t.
v[1] = integers[1] - 1 - vertex_cnt;
1073 t.
v[2] = integers[2] - 1 - vertex_cnt;
1076 if (process_uv && has_uv)
1078 std::vector<int> indices;
1079 indices.push_back(integers[6] - 1 - vertex_cnt);
1080 indices.push_back(integers[7] - 1 - vertex_cnt);
1081 indices.push_back(integers[8] - 1 - vertex_cnt);
1082 uvMap.push_back(indices);
1088 triangles.push_back(t);
1095 if (process_uv && uvs.size())
1097 loopi(0, triangles.size())
1101 .uvs[j] = uvs[uvMap[i][j]];
1114 FILE *file = fopen(filename,
"w");
1115 int cur_material = -1;
1116 bool has_uv = (triangles.size() && (triangles[0].attr &
TEXCOORD) ==
TEXCOORD);
1120 printf(
"write_obj: can't write data file \"%s\".\n", filename);
1123 if (!mtllib.empty())
1125 fprintf(file,
"mtllib %s\n", mtllib.c_str());
1127 loopi(0, vertices.size())
1130 fprintf(file,
"v %g %g %g\n", vertices[i].p.x, vertices[i].p.y, vertices[i].p.z);
1134 loopi(0, triangles.size())
if (!triangles[i].deleted)
1136 fprintf(file,
"vt %g %g\n", triangles[i].uvs[0].
x, triangles[i].uvs[0].
y);
1137 fprintf(file,
"vt %g %g\n", triangles[i].uvs[1].x, triangles[i].uvs[1].y);
1138 fprintf(file,
"vt %g %g\n", triangles[i].uvs[2].x, triangles[i].uvs[2].y);
1142 loopi(0, triangles.size())
if (!triangles[i].deleted)
1146 fprintf(file,
"f %d/%d %d/%d %d/%d\n", triangles[i].v[0] + 1, uv, triangles[i].v[1] + 1, uv + 1, triangles[i].v[2] + 1, uv + 2);
1151 fprintf(file,
"f %d %d %d\n", triangles[i].v[0] + 1, triangles[i].v[1] + 1, triangles[i].v[2] + 1);
vec3f normalize(double desired_length=1)
double vertex_error(SymetricMatrix q, double x, double y, double z)
SymetricMatrix(double a, double b, double c, double d)
double operator[](int c) const
void clamp(double min, double max)
vec3f operator*(const double a) const
vec3f(const double X, const double Y, const double Z)
SymetricMatrix & operator+=(const SymetricMatrix &n)
vec3f barycentric(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c)
char * trimwhitespace(char *str)
vec3f operator/(const double a) const
std::vector< Vertex > vertices
#define loopj(start_l, end_l)
const SymetricMatrix operator+(const SymetricMatrix &n) const
vec3f operator*(const vec3f a) const
std::vector< Triangle > triangles
vec3f operator+=(const vec3f &a) const
vec3f operator+(const vec3f &a) const
vec3f operator-(const vec3f &a) const
double random_double_01(double a)
#define loopk(start_l, end_l)
double min(double v1, double v2)
vec3f operator=(const vector3 a)
void load_obj(const char *filename, bool process_uv=false)
void update_uvs(int i0, const Vertex &v, const vec3f &p, std::vector< int > &deleted)
double calculate_error(int id_v1, int id_v2, vec3f &p_result)
void simplify_mesh(int target_count, double agressiveness=7, bool verbose=false)
SymetricMatrix(double c=0)
vec3f cross(const vec3f &a, const vec3f &b)
void update_triangles(int i0, Vertex &v, std::vector< int > &deleted, int &deleted_triangles)
void simplify_mesh_lossless(bool verbose=false)
vec3f interpolate(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c, const vec3f attrs[3])
double det(int a11, int a12, int a13, int a21, int a22, int a23, int a31, int a32, int a33)
bool flipped(vec3f p, int i0, int i1, Vertex &v0, Vertex &v1, std::vector< int > &deleted)
void update_mesh(int iteration)
vec3f operator/(const vec3f a) const
vec3f operator=(const vec3f a)
double angle2(const vec3f &v, const vec3f &w)
double dot(const vec3f &a) const
double angle(const vec3f &v)
std::vector< std::string > materials
SymetricMatrix(double m11, double m12, double m13, double m14, double m22, double m23, double m24, double m33, double m34, double m44)
void write_obj(const char *filename)
#define loopi(start_l, end_l)