1. 概述
本教程提供了使用AMCAXMeshing三角网格算法的基本用法。
1.1 TriangleSoup
AMCAXMeshing使用TriangleSoup对网格数据进行存储。TriSoup 主要包含网格点的坐标与面的索引信息,是网格算法依赖的模板参数。
class TriSoupTraits_Coord
{
public:
using PointT = VecProxy<3, double>;
using VecT = VecProxy<3, double>;
using NormalT = VecProxy<3, double>;
using Tex3D = VecProxy<3, double>;
using Color = VecProxy<3, float>;
using Triangle = VecProxy<3, int>;
using Points = std::vector<PointT>;
using Normals = std::vector<NormalT>;
using Tex3Ds = std::vector<Tex3D>;
using Colors = std::vector<Color>;
using Triangles = std::vector<Triangle>;
};
1.2 命名空间
为了示例代码清晰,使用命名空间
AMCAX Meshing 模块提供的所有接口所在的命名空间。
定义 misc.docu:35
AMCAX 内核提供的所有接口所在的命名空间。
定义 misc.docu:8
1.3 网格输入/输出
AMCAXMeshing目前提供了obj, stl常用网格文件格式的读写。
网格读写头文件
2. 算法示例
2.1 网格简化算法
#include <cfloat>
#include <thread>
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Remeshing;
void Remeshing_FastQEM()
{
bool first = true;
int stage, current, total;
[&first, &stage, ¤t, &total](int _stage, int _current, int _total,
AMCAXMeshing_UNUSED bool& cancel) -> void
{
stage = _stage;
current = _current;
total = _total;
if (!first)
std::cout << "\r\033[K"; std::cout << "stage: " << _stage << "/"
<< FastQEM<TriSoupTraits_Coord>::Total << ", process: " << current
<< "/" << total;
first = false;
if (stage == FastQEM<TriSoupTraits_Coord>::Stage::Total)
std::cout << std::endl;
};
io_options.vertex_has_point = true;
obj_reader.
read(
"./data/32770_sf.obj", io_options);
for (double ratio : {0.01, 0.1, 0.3, 0.6})
{
first = true;
std::thread simplify_thread(
[&]()
{
fast_qem.simplify(
size_t(obj_reader.
m_triangles.size() * ratio), 0.1f, 20, pro_fn);
});
simplify_thread.join();
Logger::info("FastQEM: ratio " + std::to_string(ratio) + "; time " + std::to_string(elapsed.count()) + " s");
obj_writer.
m_points = std::move(fast_qem.m_points);
obj_writer.
m_triangles = std::move(fast_qem.m_triangles);
std::string out_filename = "FastQEM_" + std::to_string(ratio) + ".obj";
obj_writer.
write(out_filename, io_options, 10);
}
}
int main()
{
Remeshing_FastQEM();
}
Fast QEM simplification algorithm.
static AMCAXMeshing_API void elapse_reset()
reset elapsed time.
AMCAXMeshing_NODISCARD static AMCAXMeshing_API std::chrono::duration< double > elapsed()
return the elapsed time since the last reset.
Options about pre-described properties in mesh IO.
定义 IOOptions.hpp:19
Read triangle soup from an OBJ file.
定义 OBJReader.hpp:38
Points m_points
point position
定义 OBJReader.hpp:125
Triangles m_triangles
triangle faces
定义 OBJReader.hpp:130
AMCAXMeshing_API bool read(const std::string &filename, IOOptions &opt)
Read triangle soup from the file. results will be stored in member variables of reader,...
Write triangle soup to an OBJ file.
定义 OBJWriter.hpp:38
AMCAXMeshing_API void clear()
Clear data stored in writer
Triangles m_triangles
triangle faces
定义 OBJWriter.hpp:131
AMCAXMeshing_API bool write(const std::string &filename, IOOptions &opt, std::streamsize precision)
Write triangle soup to file with given options and precison.
Points m_points
point position
定义 OBJWriter.hpp:126
Implement a fast QEM simplification algorithm based on triangle soup.
定义 TriSoup_FastQEM.hpp:32
std::function< void(int stage, int current, int total, bool &cancel)> ProFn
function that reports process
定义 TriSoup_FastQEM.hpp:87
点击这里example1可获得以上示例完整源码,大家根据学习需要自行下载。
2.2 网格布尔算法
using EIAC = AMCAX::Meshing::Geometry::EIAC;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
using Points = typename TriSoupTraits::Points;
using Triangles = typename TriSoupTraits::Triangles;
void read_mesh(
const std::string& filename, Points& points, Triangles& triangles,
IOOptions& io_options
)
{
if (AMCAX::Meshing::ends_with(filename, ".obj"))
{
reader.
read(filename, io_options);
}
else if (AMCAX::Meshing::ends_with(filename, ".stl"))
{
reader.
read(filename, io_options);
}
}
void write_mesh(
const std::string& filename,
const Points& points,
const Triangles& triangles,
IOOptions& io_options)
{
writer.
write(filename, io_options, 10);
};
void MeshBoolean_MeshBoolean()
{
io_options.vertex_has_point = true;
Points points1, points2, result_points;
Triangles triangles1, triangles2, result_triangles;
read_mesh("./data/bunny25k.obj", points1, triangles1, io_options);
read_mesh("./data/cow.obj", points2, triangles2, io_options);
MeshBoolean boolean(true);
boolean.addTriMeshAsInput(points1, triangles1);
boolean.addTriMeshAsInput(points2, triangles2);
std::vector<std::pair<MeshBoolean::iPoints, MeshBoolean::iTriangles>> result_meshes;
result_meshes.emplace_back(result_points, result_triangles);
boolean.setTriMeshAsOutput(result_meshes);
boolean.computeLabels();
{
boolean.Union();
std::cout << "Union results: " << result_meshes.size() << " meshes" << std::endl;
for (size_t i = 0; i < result_meshes.size(); ++i) {
std::string filename = "AMCAXMeshing_Union_" + std::to_string(i) + ".obj";
write_mesh(filename.c_str(), result_meshes[i].first, result_meshes[i].second, io_options);
}
}
{
boolean.Intersection();
std::cout << "Intersection results: " << result_meshes.size() << " meshes" << std::endl;
for (size_t i = 0; i < result_meshes.size(); ++i) {
std::string filename = "AMCAXMeshing_Intersection_" + std::to_string(i) + ".obj";
write_mesh(filename.c_str(), result_meshes[i].first, result_meshes[i].second, io_options);
}
}
{
boolean.Xor();
std::cout << "Xor results: " << result_meshes.size() << " meshes" << std::endl;
for (size_t i = 0; i < result_meshes.size(); ++i) {
std::string filename = "AMCAXMeshing_Xor" + std::to_string(i) + ".obj";
write_mesh(filename.c_str(), result_meshes[i].first, result_meshes[i].second, io_options);
}
}
{
boolean.Subtraction();
std::cout << "Subtraction results: " << result_meshes.size() << " meshes" << std::endl;
for (size_t i = 0; i < result_meshes.size(); ++i) {
std::string filename = "AMCAXMeshing_Subtraction_" + std::to_string(i) + ".obj";
write_mesh(filename.c_str(), result_meshes[i].first, result_meshes[i].second, io_options);
}
}
}
int main() {
MeshBoolean_MeshBoolean();
}
reader triangle soup from STL file.
This file implement writer for STL file.
Repair triangle mesh to clean mesh.
Read triangle soup from an STL file.
定义 STLReader.hpp:33
AMCAXMeshing_API bool read(const std::string &filename, IOOptions &opt)
Read triangle soup from the file.
Points m_points
vertex position
定义 STLReader.hpp:67
Triangles m_triangles
triangles
定义 STLReader.hpp:68
Write mesh to an STL file.
定义 STLWriter.hpp:33
点击这里example2可获得以上示例完整源码,大家根据学习需要自行下载。
2.3 网格修复算法
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::MeshTools;
void MeshRepair_MeshRepair()
{
bool first = true;
int stage;
[&first, &stage](int _stage, AMCAXMeshing_UNUSED bool& cancel) -> void
{
stage = _stage;
if (!first)
std::cout << "\r\033[K";
std::cout << "stage: " << _stage << "/" << AMCAX::Meshing::MeshTools::TriMeshRepair<TriSoupTraits_Coord>::Total;
first = false;
TriSoupTraits_Coord>::Stage::Total)
std::cout << std::endl;
};
io_options.vertex_has_point = true;
io_options.face_has_normal = true;
TriSoupTraits_Coord::Points result_points;
TriSoupTraits_Coord::Triangles result_triangles;
stl_reader.
read(
"./data/CamelBox.stl", io_options);
repair.repair(true, pro_fn);
io_options.stl_binary = true;
stl_writer.
write(
"repaired.stl", io_options, 10);
obj_writer.
write(
"repaired.obj", io_options, 10);
}
int main() {
MeshRepair_MeshRepair();
}
Interfaces of mesh arrangements.
Triangles m_triangles
triangles
定义 STLWriter.hpp:90
AMCAXMeshing_API bool write(const std::string &filename, IOOptions &opt, std::streamsize precision=6)
Write mesh to file with given options and precison.
Points m_points
vertex position
定义 STLWriter.hpp:89
点击这里example3可获得以上示例完整源码,大家根据学习需要自行下载。
2.4 网格细分算法
2.4.1 ButterFly细分
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Subdivision;
using namespace AMCAX::Meshing::Remeshing;
void Subdivision_TriSoup_ButterFly()
{
io_options.vertex_has_point = true;
obj_reader.
read(
"./data/kelan.obj", io_options);
for (double ratio : {2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.})
{
size_t sub_times = size_t(std::ceil(ratio / 4.0) + 0.1);
for (size_t i = 0; i < sub_times; i++)
subdivider.subdivide();
if (
size_t(obj_reader.
m_triangles.size() * ratio + fast_qem.m_triangles.size() * 0.01) < fast_qem.m_triangles.size())
fast_qem.simplify(
size_t(obj_reader.
m_triangles.size() * ratio), FLT_MAX, 20);
Logger::info("ButterFly: ratio " + std::to_string(ratio) + "; time " + std::to_string(elapsed.count()) + " s");
obj_writer.
m_points = std::move(fast_qem.m_points);
obj_writer.
m_triangles = std::move(fast_qem.m_triangles);
std::string out_filename = "TriSoupModifiedButterFly_" + std::to_string(ratio) + ".obj";
obj_writer.
write(out_filename, io_options, 10);
}
}
int main()
{
Subdivision_TriSoup_ButterFly();
}
Implement ButterFly subdivision algorithm.
Modified butterfly subdivision for triangle mesh. Interpolating subdivision for meshes with arbitrary...
定义 TriSoup_ButterFlySubdivision.hpp:35
点击这里example4可获得以上示例完整源码,大家根据学习需要自行下载。
2.4.2 Loop细分
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Remeshing;
using namespace AMCAX::Meshing::Subdivision;
void Subdivision_TriSoup_LoopSubdivision()
{
io_options.vertex_has_point = true;
obj_reader.
read(
"./data/kelan.obj", io_options);
for (double ratio : {2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12.})
{
size_t sub_times = size_t(std::ceil(ratio / 4.0) + 0.1);
for (size_t i = 0; i < sub_times; i++)
subdivider.subdivide();
if (
size_t(obj_reader.
m_triangles.size() * ratio + fast_qem.m_triangles.size() * 0.01) < fast_qem.m_triangles.size())
fast_qem.simplify(
size_t(obj_reader.
m_triangles.size() * ratio), FLT_MAX, 12);
Logger::info("Loop: ratio " + std::to_string(ratio) + "; time " + std::to_string(elapsed.count()) + " s");
obj_writer.
m_points = std::move(fast_qem.m_points);
obj_writer.
m_triangles = std::move(fast_qem.m_triangles);
std::string out_filename = "TriSoupLoopSub_" + std::to_string(ratio) + ".obj";
obj_writer.
write(out_filename, io_options, 10);
}
}
int main()
{
Subdivision_TriSoup_LoopSubdivision();
}
Implement loop subdivision algorithm.
Loop subdivision for triangle mesh.
定义 TriSoup_LoopSubdivision.hpp:80
点击这里example5可获得以上示例完整源码,大家根据学习需要自行下载。
2.5 重网格化
2.5.1 增量式重网格化
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Remeshing;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
void incremental_remesh_test()
{
std::string inputfilename = "./data/filename_1.obj";
io_options.vertex_has_point = true;
TriSoupTraits::Points input_points, output_points;
TriSoupTraits::Triangles input_triangles, output_triangles;
reader.
read(inputfilename, io_options);
input_points = std::move(reader.
m_points);
output_points = input_points;
output_triangles = input_triangles;
params.featurePreserved = true;
params.isAdaptive = true;
params.iterNum = 10;
params.Max_error = 0.0005;
params.targetEdgeLength = 0.1;
std::string outputfilename = std::to_string(params.iterNum) + ".obj";
writer.
m_points = std::move(output_points);
writer.
write(outputfilename, io_options, 15);
}
int main()
{
incremental_remesh_test();
}
Interfaces of triMesh incremental remeshing.
定义 TriMesh_IncrementalRemeshing.hpp:24
AMCAXMeshing_API void setReferenceMesh(const iPoints &points, const iTriangles &triangles)
add a triangle mesh (triangle soup) as one input.
AMCAXMeshing_API void setVariableMesh(iPoints &points, iTriangles &triangles)
Set the triangle mesh (triangle soup) as output destination.
AMCAXMeshing_API void remesh(Params params)
Adaptive/Isotropic remeshing controled by the control parameters
constexpr double pi
数学常数 Pi,圆的周长与直径之比
定义 Constants.hpp:42
the parameters that control the remeshing
定义 TriMesh_IncrementalRemeshing.hpp:40
点击这里example6可获得以上示例完整源码,大家根据学习需要自行下载。
2.6 网格参数化算法
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Parameterization;
void Parameterization_Bijective()
{
io_options.vertex_has_point = true;
obj_reader.
read(
"./data/cow.obj", io_options);
para.parameterization();
std::string out_filename = "res_parameterization.obj";
obj_writer.
write(out_filename, io_options, 10);
}
int main()
{
Parameterization_Bijective();
}
Bijective parameterization algorithm.
定义 MeshParameterization.hpp:23
点击这里example7可获得以上示例完整源码,大家根据学习需要自行下载。
2.7 网格切割算法
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Parameterization;
using Points = typename TriSoupTraits_Coord::Points;
using Triangles = typename TriSoupTraits_Coord::Triangles;
void Parameterization_With_MeshCut()
{
io_options.vertex_has_point = true;
std::string in_filename = "./data/bunny25k.obj";
std::string out_cut_filename = "bunny_cut.obj";
std::string out_para_filename ="bunny_parameterization.obj";
obj_reader.
read(in_filename, io_options);
Points i_points = std::move(obj_reader.
m_points);
Triangles i_triangles = std::move(obj_reader.
m_triangles);
Points cut_points;
Triangles cut_triangles;
mesh_cut.cut(cut_points, cut_triangles);
obj_writer.
write(out_cut_filename, io_options, 10);
Points para_points;
para.parameterization();
obj_writer.
m_points = std::move(para_points);
obj_writer.
write(out_para_filename, io_options, 10);
}
int main()
{
Parameterization_With_MeshCut();
}
Greedy cut algorithm for triangle mesh.
点击这里example8可获得以上示例完整源码,大家根据学习需要自行下载。