思想是需要将隐函数 f : R 3 → R f: R^3\rightarrow R f:R3→R 转换为mesh网格(根据标量场scalar field生成mesh),常用的算法是marching cubes算法(siggraph 87’ 论文链接)。二维的变体是marching squares.
libigl集成了marching cubes算法,也在tutorial中给出了样例:libigl tutorial链接
结合上述样例,自己用libigl绘制了Torus图像:
(
x
2
+
y
2
+
z
2
+
R
2
−
a
2
)
2
−
4
R
2
(
x
2
+
y
2
)
=
0
(x^2+y^2+z^2+R^2-a^2)^2-4R^2(x^2+y^2)=0
(x2+y2+z2+R2−a2)2−4R2(x2+y2)=0
#include <iostream>
#include <cmath>
#include <Eigen/Core>
#include <igl/marching_cubes.h>
#include <igl/sparse_voxel_grid.h>
#include <igl/per_corner_normals.h>
#include <igl/opengl/glfw/Viewer.h>
int main(int argc, char* argv[]){
const std::function<double(const Eigen::RowVector3d & x)> f =
[&](const Eigen::RowVector3d & x)->double
{
double R = 4, a = 1;
return pow(
pow(x[0],2) + pow(x[1],2) + pow(x[2],2) +
pow(R,2) - pow(a,2),
2) - 4*pow(R,2) * (pow(x[0],2) + pow(x[1],2));
};
Eigen::RowVector3d p0(3,4,0);
std::cout <<"[CHECK f(p0)==0] " << f(p0) << std::endl;
// Grid parameters
const Eigen::RowVector3d min_corner(-10,-10,-10);
const Eigen::RowVector3d max_corner(+10,+10,+10);
const int s = 64;
int nx = s+1;
int ny = s+1;
int nz = s+1;
const Eigen::RowVector3d step =
(max_corner-min_corner).array()/(Eigen::RowVector3d(nx,ny,nz).array()-1);
Eigen::MatrixXd GV;
Eigen::VectorXd Gf;
Eigen::Matrix<int,Eigen::Dynamic,8> GI;
igl::sparse_voxel_grid(p0,f,
step(0),16.*pow(step(0),2.),
Gf,GV,GI);
Eigen::MatrixXd mcV,mcN;
Eigen::MatrixXi mcF;
igl::marching_cubes(Gf,GV,GI,0.0,mcV,mcF);
igl::per_corner_normals(mcV,mcF,20,mcN);
// visualize by viewer
igl::opengl::glfw::Viewer vr;
vr.data().set_mesh(mcV,mcF);
vr.data().set_normals(mcN);
vr.launch();
return 0;
}