利用泊松变形实现平面浅浮雕生成
**参考论文:**Zhang Y W , Zhou Y Q , Li X L , et al. Bas-Relief Generation and Shape Editing through Gradient-Based Mesh Deformation[J]. IEEE Transactions on Visualization and Computer Graphics, 2015, 21(3):328-338.
这篇论文主要利用通过求解泊松方程来实现浅浮雕的生成,这是我读研以来实现的第二篇论文,实现的过程中由于数学知识的不足还是遇到了不少的障碍。
准备
- pmp-library :该类库提供了简便的三角形网格框架,除了基本的三角形网格数据结构之外,还提供了许多网格处理有关的算法,如网格简化、remesh等,我在体验之后感到的缺点主要是虽然该库的矩阵系统是基于Eigen的,但是他的矩阵与Eigen的并不兼容,并且他提供的矩阵初始化很麻烦,我在github上和作者反映了这个问题,他说今后会考虑将矩阵系统整个换成Eigen的。
- Eigen:十分有名的C++类库了,提供可线性代数,矩阵和矢量运算以及数值分析等算法。
预处理阶段
-
准备一个三角形网格模型
-
将其放入maya中进行编辑,如图所示
随后手动编辑取一半作为输入,如图所示
-
在代码中调用pmp中提供的remesh方法对网格进行remesh,remesh的参数取网格的平均边长
/** * remesh,取网格的平均边长作为参数 * @param mesh * @return */ Scalar remeshing(SurfaceMesh &mesh) { cout << "正在进行remesh" << endl; SurfaceRemeshing remesh(mesh); Scalar avg_scalar = 0; for (auto e : mesh.edges()) { avg_scalar += mesh.edge_length(e); } avg_scalar /= mesh.n_edges(); cout << "average edge length = " << avg_scalar << endl; remesh.uniform_remeshing(avg_scalar); cout << "remesh完成" << endl; cout << "vertices:" << mesh.n_vertices() << ", edges:" << mesh.n_edges() << ", faces:" << mesh.n_faces() << endl; return avg_scalar; }
-
网格简化,调用pmp的网格简化算法,将面片数大于一定值的网格进行简化
/** * 简化网格,当三角形面片数量大于门限值时对网格进行简化 * @param mesh * @param avg_scalar * @return */ int simplification(SurfaceMesh &mesh, const Scalar avg_scalar) { cout << "正在进行simplification" << endl; SurfaceSimplification simplification1(mesh); simplification1.initialize(5, avg_scalar, 10, 10, 0.001); int n = mesh.n_vertices() <= 10e3 ? mesh.n_vertices() : 5e3 + mesh.n_vertices() / 2; cout << "simplify之后的顶点数量为:" << n << endl; simplification1.simplify(n); cout << "simplify完成" << endl; cout << "vertices:" << mesh.n_vertices() << ", edges:" << mesh.n_edges() << ", faces:" << mesh.n_faces() << endl; return 0; }
利用泊松变形(Poison Deformation)生成浅浮雕
泊松等式
具有狄利克雷条件的泊松等式定义如(1)式:
(1) ∇ 2 f = ∇ ⋅ w , f ∣ ∂ Ω = f ∗ ∣ ∂ Ω \nabla^2f=\nabla \cdot \boldsymbol{w}, \ f|_{\partial\Omega} = f^*|_{\partial\Omega} \tag{1} ∇2f=∇⋅w, f∣∂Ω=f∗∣∂Ω(1)
其中 f f f是一个未知的标量函数, w \boldsymbol w w是一个梯度矢量场, f ∗ f^* f∗为边界约束, ∇ 2 \nabla^2 ∇2为拉普拉斯算子,即梯度的散度,而 ∇ ⋅ w \nabla \cdot \boldsymbol{w} ∇⋅w 为梯度矢量场 w = ( w x , w y , w z ) \boldsymbol w = (w_x,w_y,w_z) w=(wx,wy,wz)的散度,泊松等式的意义在于,一个网格的拉普拉斯坐标值等于其网格面片的梯度场的散度,也就是说我们可以通过操纵网格的梯度场反过来去求出对应网格顶点的位置从而达到变形的目的。表示成矩阵形式就是:
(2) L x = b Lx = b \tag{2} Lx=b(2)
其中L为三角形网格的拉普拉斯矩阵,可以通过下式求得:
(3) L i j = { ∑ ( i , k ) ∈ E w i k i = j − w i j ( i , j ) ∈ E