一、网格上的布尔运算 (6.09)
igl::copyleft::cgal::mesh_boolean(VA,FA,VB,FB,MESH_BOOLEAN_TYPE_UNION,VC,FC);
下图显示了两个网格上的每个布尔运算。
布尔示例对 Cheburashka(红色)和 Knight(绿色)进行布尔运算。从左到右:并集、交集、集合减、对称差 (XOR)、“解析”。底行显示内表面,较深的颜色表示背面的三角形。
并、对称差和“解”的外观相同,但内部结构的处理不同。联合没有内表面:三角形不包含在输出中。对称差异是与“解析”相同的一组三角形,但内表面的方向已反转,表明操作的实体结果。“解析”操作并不是真正的布尔运算,它只是解析所有交点并将重合顶点粘合在一起的结果,保持原始三角形方向。
Libigl 还为软木塞提供了一个包装器 igl::copyleft::cork::mesh_boolean
,它通常速度更快,但并不总是健壮。
#include <igl/readOFF.h> // 引入igl库的readOFF函数,用于读取OFF文件
//#undef IGL_STATIC_LIBRARY
#include <igl/copyleft/cgal/mesh_boolean.h> // 引入igl库的mesh_boolean函数,用于进行网格布尔运算
#include <igl/opengl/glfw/Viewer.h> // 引入igl库的Viewer类,用于创建OpenGL窗口并进行渲染
#include <Eigen/Core> // 引入Eigen库的Core模块,提供了矩阵和向量的基本操作
#include <iostream> // 引入iostream库,提供了用于输入/输出的函数
Eigen::MatrixXd VA,VB,VC; // 定义三个矩阵,用于存储三个网格的顶点坐标
Eigen::VectorXi J,I; // 定义两个向量,用于存储网格布尔运算的结果
Eigen::MatrixXi FA,FB,FC; // 定义三个矩阵,用于存储三个网格的面片索引
igl::MeshBooleanType boolean_type( // 定义一个MeshBooleanType类型的变量,用于指定网格布尔运算的类型
igl::MESH_BOOLEAN_TYPE_UNION); // 初始化为并集运算
const char * MESH_BOOLEAN_TYPE_NAMES[] = // 定义一个字符串数组,用于存储网格布尔运算类型的名称
{
"Union",
"Intersect",
"Minus",
"XOR",
"Resolve",
};
void update(igl::opengl::glfw::Viewer &viewer) // 定义一个函数,用于更新视图
{
igl::copyleft::cgal::mesh_boolean(VA,FA,VB,FB,boolean_type,VC,FC,J); // 对两个网格进行布尔运算,结果存储在VC, FC和J中
Eigen::MatrixXd C(FC.rows(),3); // 定义一个矩阵,用于存储每个面片的颜色
for(size_t f = 0;f<C.rows();f++) // 遍历所有的面片
{
if(J(f)<FA.rows()) // 如果当前面片属于第一个网格
{
C.row(f) = Eigen::RowVector3d(1,0,0); // 设置颜色为红色
}else // 如果当前面片属于第二个网格
{
C.row(f) = Eigen::RowVector3d(0,1,0); // 设置颜色为绿色
}
}
viewer.data().clear(); // 清除当前的数据
viewer.data().set_mesh(VC,FC); // 设置新的网格
viewer.data().set_colors(C); // 设置颜色
std::cout<<"A "<<MESH_BOOLEAN_TYPE_NAMES[boolean_type]<<" B."<<std::endl; // 输出当前的布尔运算类型
}
bool key_down(igl::opengl::glfw::Viewer &viewer, unsigned char key, int mods) // 定义一个函数,用于处理键盘按下的事件
{
switch(key) // 根据按下的键进行判断
{
default:
return false;
case '.': // 如果按下的是'.'
boolean_type = // 切换到下一个布尔运算类型
static_cast<igl::MeshBooleanType>(
(boolean_type+1)% igl::NUM_MESH_BOOLEAN_TYPES);
break;
case ',': // 如果按下的是','
boolean_type = // 切换到上一个布尔运算类型
static_cast<igl::MeshBooleanType>(
(boolean_type+igl::NUM_MESH_BOOLEAN_TYPES-1)%
igl::NUM_MESH_BOOLEAN_TYPES);
break;
case '[': // 如果按下的是'['
viewer.core().camera_dnear -= 0.1; // 将近裁剪面向摄像机方向移动
return true;
case ']': // 如果按下的是']'
viewer.core().camera_dnear += 0.1; // 将近裁剪面向远离摄像机的方向移动
return true;
}
update(viewer); // 更新视图
return true;
}
int main(int argc, char *argv[]) // 主函数
{
using namespace Eigen; // 使用Eigen命名空间
using namespace std; // 使用std命名空间
igl::readOFF(TUTORIAL_SHARED_PATH "/cheburashka.off",VA,FA); // 读取第一个网格
igl::readOFF(TUTORIAL_SHARED_PATH "/decimated-knight.off",VB,FB); // 读取第二个网格
// Plot the mesh with pseudocolors
igl::opengl::glfw::Viewer viewer; // 创建一个Viewer对象
// Initialize
update(viewer); // 初始化视图
viewer.data().show_lines = true; // 显示网格线
viewer.callback_key_down = &key_down; // 设置键盘按下的回调函数
viewer.core().camera_dnear = 3.9; // 设置近裁剪面的位置
cout<<
"Press '.' to switch to next boolean operation type."<<endl<<
"Press ',' to switch to previous boolean operation type."<<endl<<
"Press ']' to push near cutting plane away from camera."<<endl<<
"Press '[' to pull near cutting plane closer to camera."<<endl<<
"Hint: investigate _inside_ the model to see orientation changes."<<endl; // 输出提示信息
viewer.launch(); // 启动视图
}
此段代码展示了使用libigl库进行两个3D网格模型之间的布尔运算,并在igl::opengl::glfw::Viewer中进行展示。布尔运算包括并集、交集、差集、异或和解析等操作。