99#define loopi(start_l, end_l) for (int i = start_l; i < end_l; ++i)
107#define loopi(start_l, end_l) for (int i = start_l; i < end_l; ++i)
108#define loopj(start_l, end_l) for (int j = start_l; j < end_l; ++j)
116#define loopk(start_l, end_l) for (int k = start_l; k < end_l; ++k)
159 inline vec3f(
const double X,
const double Y,
const double Z)
254 return a.
x *
x + a.
y *
y + a.
z *
z;
267 x = a.
y * b.
z - a.
z * b.
y;
268 y = a.
z * b.
x - a.
x * b.
z;
269 z = a.
x * b.
y - a.
y * b.
x;
282 vec3f a = v, b = *
this;
283 double dot = v.
x *
x + v.
y *
y + v.
z *
z;
284 double len = a.
length() * b.length();
287 double input =
dot / len;
292 return (
double)acos(input);
306 vec3f a = v, b = *
this;
307 double dot = a.
x * b.x + a.
y * b.y + a.
z * b.z;
308 double len = a.
length() * b.length();
315 if (plane.
x * a.
x + plane.
y * a.
y + plane.
z * a.
z > 0)
316 return (
double)-acos(
dot / len);
318 return (
double)acos(
dot / len);
330 double yy = cos(a) *
y + sin(a) *
z;
331 double zz = cos(a) *
z - sin(a) *
y;
346 double xx = cos(-a) *
x + sin(-a) *
z;
347 double zz = cos(-a) *
z - sin(-a) *
x;
385 double yy = cos(a) *
y + sin(a) *
x;
386 double xx = cos(a) *
x - sin(a) *
y;
442 return (
double)sqrt(
x *
x +
y *
y +
z *
z);
454 double square = sqrt(
x *
x +
y *
y +
z *
z);
515 double rnf = a * 14.434252 + a * 364.2343 + a * 4213.45352 + a * 2341.43255 + a * 254341.43535 + a * 223454341.3523534245 + 23453.423412;
516 int rni = ((int)rnf) % 100000;
517 return double(rni) / (100000.0f - 1.0f);
551 double d00 = v0.
dot(v0);
552 double d01 = v0.
dot(v1);
553 double d11 = v1.
dot(v1);
554 double d20 = v2.
dot(v0);
555 double d21 = v2.
dot(v1);
556 double denom = d00 * d11 - d01 * d01;
557 double v = (d11 * d20 - d01 * d21) / denom;
558 double w = (d00 * d21 - d01 * d20) / denom;
559 double u = 1.0 - v - w;
560 return vec3f(u, v, w);
579 out = out + attrs[0] * bary.
x;
580 out = out + attrs[1] * bary.
y;
581 out = out + attrs[2] * bary.
z;
591double min(
double v1,
double v2)
619 double m22,
double m23,
double m24,
620 double m33,
double m34,
677 double det(
int a11,
int a12,
int a13,
678 int a21,
int a22,
int a23,
679 int a31,
int a32,
int a33)
681 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];
693 m[4] + n[4],
m[5] + n[5],
m[6] + n[6],
694 m[7] + n[7],
m[8] + n[8],
859 void simplify_mesh(
int target_count,
double agressiveness = 7,
bool verbose =
false)
868 int deleted_triangles = 0;
869 std::vector<int> deleted0, deleted1;
873 for (
int iteration = 0; iteration < 100; iteration++)
875 if (triangle_count - deleted_triangles <= target_count)
879 if (iteration % 5 == 0)
889 double threshold = 0.000000001 * pow(
double(iteration + 3), agressiveness);
892 if ((verbose) && (iteration % 5 == 0))
894 printf(
"iteration %d - triangles %d threshold %g\n", iteration, triangle_count - deleted_triangles, threshold);
901 if (t.
err[3] > threshold)
908 loopj(0, 3)
if (t.
err[j] < threshold)
913 int i1 = t.
v[(j + 1) % 3];
923 deleted0.resize(v0.
tcount);
924 deleted1.resize(v1.
tcount);
926 if (
flipped(p, i0, i1, v0, v1, deleted0))
929 if (
flipped(p, i1, i0, v1, v0, deleted1))
942 int tstart =
refs.size();
947 int tcount =
refs.size() - tstart;
964 if (triangle_count - deleted_triangles <= target_count)
985 int deleted_triangles = 0;
986 std::vector<int> deleted0, deleted1;
989 for (
int iteration = 0; iteration < 9999; iteration++)
996 double threshold = DBL_EPSILON;
999 printf(
"lossless iteration %d\n", iteration);
1006 if (t.
err[3] > threshold)
1013 loopj(0, 3)
if (t.
err[j] < threshold)
1017 int i1 = t.
v[(j + 1) % 3];
1028 deleted0.resize(v0.
tcount);
1029 deleted1.resize(v1.
tcount);
1032 if (
flipped(p, i0, i1, v0, v1, deleted0))
1034 if (
flipped(p, i1, i0, v1, v0, deleted1))
1046 int tstart =
refs.size();
1051 int tcount =
refs.size() - tstart;
1066 if (deleted_triangles <= 0)
1068 deleted_triangles = 0;
1100 int id1 = t.
v[(s + 1) % 3];
1101 int id2 = t.
v[(s + 2) % 3];
1103 if (id1 == i1 || id2 == i1)
1113 if (fabs(d1.
dot(d2)) > 0.999)
1119 if (n.
dot(t.
n) < 0.2)
1177 deleted_triangles++;
1259 std::vector<int> vcount, vids;
1276 int ofs = 0,
id = t.
v[k];
1277 while (ofs < vcount.size())
1279 if (vids[ofs] ==
id)
1283 if (ofs == vcount.size())
1285 vcount.push_back(1);
1292 loopj(0, vcount.size())
if (vcount[j] == 1)
1306 n.
cross(p[1] - p[0], p[2] - p[0]);
1360 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];
1373 double det = q.
det(0, 1, 2, 1, 4, 5, 2, 5, 7);
1374 if (det != 0 && !border)
1378 p_result.
x = -1 / det * (q.
det(1, 2, 3, 4, 5, 6, 5, 7, 8));
1379 p_result.
y = 1 / det * (q.
det(0, 2, 3, 1, 5, 6, 2, 7, 8));
1380 p_result.
z = -1 / det * (q.
det(0, 1, 3, 1, 4, 6, 2, 5, 8));
1388 vec3f p3 = (p1 + p2) / 2;
1394 error =
min(error1,
min(error2, error3));
1395 if (error1 == error)
1397 if (error2 == error)
1399 if (error3 == error)
1409 while (isspace((
unsigned char)*str))
1417 end = str + strlen(str) - 1;
1420 while (
end > str && isspace((
unsigned char)*
end))
1431 void load_obj(
const char *filename,
bool process_uv =
false)
1440 if (filename == NULL)
1442 if ((
char)filename[0] == 0)
1444 if ((
fn = fopen(filename,
"rb")) == NULL)
1446 printf(
"File %s not found!\n", filename);
1452 memset(line, 0, 1000);
1457 std::map<std::string, int> material_map;
1458 std::vector<vec3f> uvs;
1459 std::vector<std::vector<int>> uvMap;
1464 while (fgets(line, 1000,
fn) != NULL)
1472 if (strncmp(line,
"mtllib", 6) == 0)
1480 if (strncmp(line,
"usemtl", 6) == 0)
1483 if (material_map.find(usemtl) == material_map.end())
1485 material_map[usemtl] =
materials.size();
1488 material = material_map[usemtl];
1495 if (line[0] ==
'v' && line[1] ==
't')
1498 if (sscanf(line,
"vt %lf %lf",
1504 else if (sscanf(line,
"vt %lf %lf %lf",
1505 &uv.
x, &uv.
y, &uv.
z) == 3)
1514 else if (line[0] ==
'v')
1517 if (sscanf(line,
"v %lf %lf %lf",
1518 &v.
p.
x, &v.
p.
y, &v.
p.
z) == 3)
1532/ 用于标记三角形数据是否读取正确的布尔变量,初始化为false
1533 bool tri_ok =
false;
1535 bool has_uv =
false;
1537 if (sscanf(line,
"f %d %d %d",
1538 &integers[0], &integers[1], &integers[2]) == 3)
1543 else if (sscanf(line,
"f %d// %d// %d//",
1544 &integers[0], &integers[1], &integers[2]) == 3)
1549 else if (sscanf(line,
"f %d//%d %d//%d %d//%d",
1550 &integers[0], &integers[3],
1551 &integers[1], &integers[4],
1552 &integers[2], &integers[5]) == 6)
1556 else if (sscanf(line,
"f %d/%d/%d %d/%d/%d %d/%d/%d",
1557 &integers[0], &integers[6], &integers[3],
1558 &integers[1], &integers[7], &integers[4],
1559 &integers[2], &integers[8], &integers[5]) == 9)
1565 if (sscanf(line,
"f %d/%d %d/%d %d/%d",
1566 &integers[0], &integers[6],
1567 &integers[1], &integers[7],
1568 &integers[2], &integers[8]) == 6)
1575 printf(
"unrecognized sequence\n");
1576 printf(
"%s\n", line);
1583 t.
v[0] = integers[0] - 1 - vertex_cnt;
1584 t.
v[1] = integers[1] - 1 - vertex_cnt;
1585 t.
v[2] = integers[2] - 1 - vertex_cnt;
1588 if (process_uv && has_uv)
1591 std::vector<int> indices;
1592 indices.push_back(integers[6] - 1 - vertex_cnt);
1593 indices.push_back(integers[7] - 1 - vertex_cnt);
1594 indices.push_back(integers[8] - 1 - vertex_cnt);
1596 uvMap.push_back(indices);
1609 if (process_uv && uvs.size())
1616 .uvs[j] = uvs[uvMap[i][j]];
1630 FILE *file = fopen(filename,
"w");
1632 int cur_material = -1;
1637 printf(
"write_obj: can't write data file \"%s\".\n", filename);
1642 fprintf(file,
"mtllib %s\n",
mtllib.c_str());
auto end() const noexcept
double min(double v1, double v2)
返回两个数中的较小值
#define loopk(start_l, end_l)
定义一个循环宏,使用变量k从start_l迭代到end_l(不包括end_l)。
vec3f interpolate(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c, const vec3f attrs[3])
根据重心坐标插值属性
#define loopj(start_l, end_l)
定义一个循环宏,使用变量j从start_l迭代到end_l(不包括end_l)。
#define loopi(start_l, end_l)
标准输入输出流库
vec3f barycentric(const vec3f &p, const vec3f &a, const vec3f &b, const vec3f &c)
计算点p相对于三角形abc的重心坐标
void simplify_mesh_lossless(bool verbose=false)
无损简化网格
void write_obj(const char *filename)
void update_mesh(int iteration)
更新网格:压缩三角形,并建立引用列表
double calculate_error(int id_v1, int id_v2, vec3f &p_result)
std::string mtllib
材质库的名称。
bool flipped(vec3f p, int i0, int i1, Vertex &v0, Vertex &v1, std::vector< int > &deleted)
检查移除指定边后三角形是否会翻转
std::vector< std::string > materials
存储材质名称的向量。
std::vector< Triangle > triangles
存储三角形的向量。
std::vector< Vertex > vertices
存储顶点的向量。
void update_uvs(int i0, const Vertex &v, const vec3f &p, std::vector< int > &deleted)
更新UV坐标
char * trimwhitespace(char *str)
std::vector< Ref > refs
存储引用的向量。
void load_obj(const char *filename, bool process_uv=false)
void simplify_mesh(int target_count, double agressiveness=7, bool verbose=false)
主简化函数。
void update_triangles(int i0, Vertex &v, std::vector< int > &deleted, int &deleted_triangles)
更新三角形连接和边误差
double vertex_error(SymetricMatrix q, double x, double y, double z)
SymetricMatrix & operator+=(const SymetricMatrix &n)
矩阵加法赋值运算符重载
SymetricMatrix(double a, double b, double c, double d)
使用平面方程的参数构造对称矩阵
double det(int a11, int a12, int a13, int a21, int a22, int a23, int a31, int a32, int a33)
计算矩阵的子行列式
const SymetricMatrix operator+(const SymetricMatrix &n) const
矩阵加法运算符重载
SymetricMatrix(double c=0)
构造函数,使用默认值初始化所有元素
SymetricMatrix(double m11, double m12, double m13, double m14, double m22, double m23, double m24, double m33, double m34, double m44)
构造函数,使用给定的值初始化矩阵
double operator[](int c) const
访问矩阵元素
int tid
三角形的索引和三角形中引用的顶点索引。
double err[4]
误差值数组,用于简化算法。
int deleted
是否被删除的标志、是否需要重新计算的标志和三角形的属性。
int tstart
第一个引用此顶点的三角形的索引和引用此顶点的三角形数量。
SymetricMatrix q
对称矩阵,用于存储顶点信息。
一个包含三维浮点数坐标的向量结构体,提供了一系列向量运算。
vec3f rot_y(double a)
绕Y轴旋转当前向量
vec3f random01_fxyz()
将当前向量的每个分量设置为[0, 1)范围内的随机数
vec3f operator/(const double a) const
向量与标量除法运算符重载,计算当前对象与给定标量相除的结果。
static int random_number
静态成员变量:随机数生成器使用的随机数
vec3f rot_x(double a)
绕X轴旋转当前向量
vec3f operator*(const double a) const
void clamp(double min, double max)
将当前向量的分量限制在最小值和最大值之间
vec3f operator=(const vec3f a)
赋值运算符重载,用于将另一个vec3f对象的值赋给当前对象。
static double random_double()
静态方法:生成一个随机双精度浮点数
vec3f operator*(const vec3f a) const
static void random_init()
静态方法:初始化随机数生成器
double length() const
获取当前向量的长度
vec3f integer()
获取当前向量的整数部分
double angle2(const vec3f &v, const vec3f &w)
计算两个向量之间的角度,考虑第三个向量定义的平面
vec3f invert()
获取当前向量的相反向量
double dot(const vec3f &a) const
计算当前对象与另一个vec3f对象的点积。
vec3f(vector3 a)
拷贝构造函数,从另一个vector3对象构造。
vec3f operator/(const vec3f a) const
向量除法运算符重载,计算当前对象与另一个vec3f对象对应分量相除的结果。
vec3f normalize(double desired_length=1)
将当前向量归一化
vec3f operator=(const vector3 a)
赋值运算符重载,从另一个vec3f对象赋值。
vec3f rot_z(double a)
绕Z轴旋转当前向量
static vec3f normalize(vec3f a)
静态方法:归一化一个向量
vec3f cross(const vec3f &a, const vec3f &b)
计算两个三维向量的叉积
double angle(const vec3f &v)
计算当前向量与另一个向量之间的角度
vec3f operator-(const vec3f &a) const
向量减法运算符重载,计算当前对象与另一个vec3f对象对应分量相减的结果。
double random_double_01(double a)
生成一个[0, 1)范围内的随机双精度浮点数,基于给定的输入进行变换
vec3f operator+(const vec3f &a) const
vec3f(const double X, const double Y, const double Z)
参数化构造函数,从三个浮点数构造。
static vec3f random()
静态方法:生成一个随机三维向量
vec3f operator+=(const vec3f &a) const
一个简单的三维向量结构体,包含x、y、z三个坐标。