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常用网格文件格式的读写。
网格读写头文件
编写"example_utils.h"设置输入与输出路径
#pragma once
#include <filesystem>
#include <fstream>
#include <stack>
#include <string>
#include <vector>
inline bool make_file_writable(const std::string &filename)
{
std::filesystem::path filepath(filename);
if (std::filesystem::exists(filepath) && std::filesystem::is_regular_file(filepath))
return true;
std::filesystem::path parent_path = filepath.parent_path();
if (std::filesystem::exists(parent_path) && std::filesystem::is_directory(parent_path))
return true;
std::filesystem::create_directories(parent_path);
return false;
}
inline bool make_dir_writable(const std::string &dirname)
{
std::filesystem::path dirpath(dirname);
if (std::filesystem::exists(dirpath) && std::filesystem::is_directory(dirpath))
return true;
std::filesystem::create_directories(dirpath);
return false;
}
#define OUTPUT_DIRECTORY(TEST_SUIT_NAME, TEST_NAME) \
std::string outdir = \
"./data/test_output/" #TEST_SUIT_NAME "/" #TEST_NAME "/"; \
make_dir_writable(outdir)
2. 算法示例
2.1 网格简化算法
#include "example_utils.h"
#include <cfloat>
#include <thread>
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Remeshing;
void Remeshing_FastQEM()
{
OUTPUT_DIRECTORY(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;
std::string filename = "32770_sf";
obj_reader.
read(
"./data/" + filename +
".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 =
outdir + filename + "_FastQEM_" + std::to_string(ratio) + ".obj";
obj_writer.
write(out_filename, io_options, 10);
}
}
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 网格布尔算法
#include "example_utils.h"
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,
)
{
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()
{
OUTPUT_DIRECTORY(Boolean, Boolean);
io_options.vertex_has_point = true;
Points points1, points2, result_points;
Triangles triangles1, triangles2, result_triangles;
read_mesh("./data/boolean_data/bunny25k.obj", points1, triangles1, io_options);
read_mesh("./data/boolean_data/cow.obj", points2, triangles2, io_options);
MeshBoolean boolean(true);
boolean.addTriMeshAsInput(points1, triangles1);
boolean.addTriMeshAsInput(points2, triangles2);
boolean.setTriMeshAsOutput(result_points, result_triangles);
boolean.computeLabels();
{
boolean.Union();
make_file_writable(outdir + "AMCAXMeshing_Union.obj");
write_mesh(outdir + "AMCAXMeshing_Union.obj", result_points,
result_triangles, io_options);
}
{
boolean.Intersection();
make_file_writable(outdir + "AMCAXMeshing_Intersection.obj");
write_mesh(outdir + "AMCAXMeshing_Intersection.obj", result_points,
result_triangles, io_options);
}
{
boolean.Xor();
make_file_writable(outdir + "AMCAXMeshing_Xor.obj");
write_mesh(outdir + "AMCAXMeshing_Xor.obj", result_points, result_triangles,
io_options);
}
{
boolean.Subtraction();
make_file_writable(outdir + "AMCAXMeshing_Subtraction.obj");
write_mesh(outdir + "AMCAXMeshing_Subtraction.obj", result_points,
result_triangles, io_options);
}
}
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 网格修复算法
#include "example_utils.h"
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::MeshTools;
void MeshRepair_MeshRepair()
{
OUTPUT_DIRECTORY(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;
std::string modelname = "CamelBox";
TriSoupTraits_Coord::Points result_points;
TriSoupTraits_Coord::Triangles result_triangles;
stl_reader.
read(
"./data/repair_data/" + modelname +
".stl", io_options);
repair.repair(true, pro_fn);
make_file_writable(outdir + modelname + "_repaired.stl");
io_options.stl_binary = true;
stl_writer.
write(outdir + modelname +
"_repaired.stl", io_options, 10);
make_file_writable(outdir + modelname + "_repaired.obj");
obj_writer.
write(outdir + modelname +
"_repaired.obj", io_options, 10);
}
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细分
#include "example_utils.h"
#include <cfloat>
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Subdivision;
using namespace AMCAX::Meshing::Remeshing;
void Subdivision_TriSoup_ButterFly()
{
OUTPUT_DIRECTORY(Subdivision, TriSoup_ButterFly);
io_options.vertex_has_point = true;
std::string filename = "kelan";
obj_reader.
read(
"./data/subdivision_data/" + filename +
".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();
std::move(subdivider.m_triangles));
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 = outdir + filename +
"_TriSoupModifiedButterFly_" +
std::to_string(ratio) + ".obj";
make_file_writable(out_filename);
obj_writer.
write(out_filename, io_options, 10);
}
}
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细分
#include "example_utils.h"
#include <cfloat>
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;
std::string filename = "kelan";
obj_reader.
read(
"./data/subdivision_data/" + filename +
".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();
std::move(subdivider.m_triangles));
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 =
outdir + filename + "_TriSoupLoopSub_" + std::to_string(ratio) + ".obj";
make_file_writable(out_filename);
obj_writer.
write(out_filename, io_options, 10);
}
}
Implement loop subdivision algorithm.
Loop subdivision for triangle mesh.
定义 TriSoup_LoopSubdivision.hpp:78
点击这里example5可获得以上示例完整源码,大家根据学习需要自行下载。
2.5 重网格化
2.5.1 增量式重网格化
#include "example_utils.h"
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/remesh_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;
params.tolAngle = 30. / 180. * M_PI;
std::string outputfilename =
"./data/" + std::to_string(params.iterNum) + ".obj";
writer.
m_points = std::move(output_points);
writer.
write(outputfilename, io_options, 15);
}
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
the parameters that control the remeshing
定义 TriMesh_IncrementalRemeshing.hpp:40
点击这里example6可获得以上示例完整源码,大家根据学习需要自行下载。
2.6 网格参数化算法
#include "example_utils.h"
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Parameterization;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
void Parameterization_Bijective()
{
OUTPUT_DIRECTORY(Parameterization, Bijective);
io_options.vertex_has_point = true;
obj_reader.
read(
"./data/parameterization_data/cow.obj", io_options);
para.parameterization();
std::string out_filename = outdir + "res_parameterization.obj";
obj_writer.
write(out_filename, io_options, 10);
}
Bijective parameterization algorithm.
定义 MeshParameterization.hpp:23
点击这里example7可获得以上示例完整源码,大家根据学习需要自行下载。
2.7 网格切割算法
#include "example_utils.h"
using namespace AMCAX::Meshing::Mesh;
using namespace AMCAX::Meshing::Parameterization;
using TriSoupTraits = AMCAX::Meshing::Mesh::TriSoupTraits_Coord;
using Points = typename TriSoupTraits::Points;
using Triangles = typename TriSoupTraits::Triangles;
void Parameterization_With_MeshCut()
{
OUTPUT_DIRECTORY(Parameterization, Bijective_With_MeshCut);
io_options.vertex_has_point = true;
std::string in_filename = "./data/boolean_data/bunny25k.obj";
std::string out_cut_filename = outdir + "bunny_cut.obj";
std::string out_para_filename = outdir + "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);
i_points, i_triangles, true);
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;
cut_points, cut_triangles, para_points, true);
para.parameterization();
obj_writer.
m_points = std::move(para_points);
obj_writer.
write(out_para_filename, io_options, 10);
}
Greedy cut algorithm for triangle mesh.
点击这里example8可获得以上示例完整源码,大家根据学习需要自行下载。