这次Laplace Deformation的博客分为两个部分,理论和实现
理论(含推导过程):https://blog.csdn.net/z136411501/article/details/107622967
以实现解最简单的拉普拉斯线性方程组为主,不引入加速求解,与旋转不变性,体积不变性。
实现Demo分为两类,基础变形静态的实现,与VR下动态的实现
程序源代码链接:https://pan.baidu.com/s/1R6siadh4vkxRB0tMP6WABg 提取码:hqdq
(两份代码,静态与VR)
编译环境:
- Unity3D 2017.4.34c1
- mathNet
- VR额外配置:SteamVR+LeapMotion
一,实现Demo
静态:初始化一个20x20的mesh网格,将周围的vertex设为固定锚点,中间的单独黄色vertex设为移动锚点,向上移动(0, 1, 0)距离,其余vertex为变形区域。
VR动态:相同的网格,第一步确立改变的范围,将边缘处设为固定锚点,拖拽时,小球半径以内的所有点设为移动锚点。这里变形后的三角形太大,以至于有凹凸感,可加网格细分进行改善。(示意图因gif压缩保存导致色差)
二,代码解析
理论部分见另一篇博客,链接在上边。
采用半边(half-edge)作为mesh的存储数据结构。mathNet作为c#的数学库,用于计算矩阵的转置和逆。
本质是求解方程
然后,以静态demo为例,m为锚点的数目(固定锚点76+移动锚点1 = 77),n为mesh网格顶点的数目(20x20=400),
L是一个400x400的矩阵,为了计算方便,采用其对称形式Ls参与计算,即在方程组里,L=Ls,解不变,下为Ls矩阵的具体value
w是锚点的权,全部初始化为1. I 是一个mxn的类单位矩阵,m为锚点的数目,n为网格顶点的数目,I的每一行只有一个非零元素,表示锚点在网格中的索引,矩阵value类似于下面这样
0 0 0 0 0 0 0 1 0 0 0 .... 0 0 0 0
0 0 0 0 0 0 0 0 1 0 0 .... 0 0 0 0
然后解释方程组的右边项,
δ(x)是一个400x3矩阵,存除这个网格变形前的所有vertex的拉普拉斯坐标,坐标公式计算如下
w是相同的锚点的权,C1:m 为 77x3的矩阵,存每个锚点变化后的坐标值,比如固定锚点的坐标不变,还是变形前的值,移动锚点的坐标改为加上偏移量(0,1, 0)变化后的坐标值。b矩阵示意值如下
至此,所有的矩阵填充完毕,求解变化后的坐标矩阵x(一个400x3矩阵,存变形后的mesh网格顶点的坐标值),
最后一步更新mesh顶点的坐标,注意锚点的更新坐标为c1:m的坐标,而不用计算出来的坐标,因为有些许误差。
额外补充:
VR代码,用的是LeapMotion与HTC VIVE Pro套件,基本算法都一样,在这里,也是paper中强调了三次的一个技巧。
决定了变形区域,在抓着某些点进行拖拽时,红色方框中的矩阵其实是不再改变的,所以只用计算一次就好,
拖拽过程中,不断地修改矩阵b,计算新的vertex位置并更新到mesh。
只有当松手并重新抓点拖拽时,才重新计算一次方框中的矩阵,因为移动锚点可能更新了。