《Polygon mesh processing》中有很大一部分的章节来介绍曲面变形的方法,包括bla bla bla。。。
其中Laplacian surface Deformation的拉普拉斯一词很容易就勾起了复变函数给我留下的不美好的回忆,抱着下次一定的想法,在3个月后我终于决定要鼓起勇气微笑面对它 囧
认真搜集了一下资料发现这其实是一个蛮简单的内容啦~
先把方程贴出来
func1.png
方程表达的含义很简单:求解满足控制点位置约束和形态约束下的模型位置点。控制点自行定义,模型点的形态约束由拉普拉斯算子决定,其实就是中心点到带权重的连接点重心的差,至于权重的大小可以用均匀权重或者余切权重。
这个方程可以转换成矩阵形式:
func2.png
求导,当导数为0的时候取得方程解:
func3.png
maya中使用python简单实现了一下,效果如下:
maya.png
具体代码:
from maya import cmds
import maya.api.OpenMaya as om
import numpy as np
def GetVertexVertices(mesh):
vIter = om.MItMeshVertex(mesh)
vv = list()
while not vIter.isDone():
vv.append( vIter.getConnectedVertices() )
vIter.next()
return vv
def Fill_L(relation, L):
pcount = len(relation)
if pcount != L.shape[0]:
return False
for i, block in enumerate(relation):
size = 1.0/ len(block)
for v in block:
L[i, v] = size
return True
def main():
sels = om.MGlobal.getActiveSelectionList()
meshDag = sels.getDagPath(0)
deformDag = sels.getDagPath(1)
mesh = om.MFnMesh(meshDag)
vArray = mesh.getPoints()
nArray = np.array(vArray )
relation = GetVertexVertices(meshDag)
pcount = mesh.numVertices
L = -np.identity( pcount )
if not Fill_L(relation, L):
print("data error: pcount not equal")
return False
l = L.dot(nArray)[:, :3]
#fix p 48[0.5, 0, -0.5] p 6[0.5, 0, 0.5]
#dynamic p 42[-0.5, 0, -0.5] p 0[-0.5, 0, 0.5]
P = np.zeros( (pcount, 3) )
P[48] = np.array( [0.5, 0, -0.5] )
P[6] = np.array( [0.5, 0, 0.5] )
P[42] = np.array( [-0.5, 0.5, -0.5] )
P[0] = np.array( [-0.5, 0.5, 0.5] )
S = np.zeros( (pcount, pcount) )
S[48, 48]= 1.0
S[6, 6]= 1.0
S[42, 42]= 1.0
S[0, 0]= 1.0
a = 2
left = L.T.dot(L)+ a* S.T.dot(S)
right = L.T.dot(l) + a* S.T.dot(P)
X = np.linalg.solve(left, right)
deformMash = om.MFnMesh( deformDag )
for i in range(pcount):
v = om.MPoint( X[i, 0], X[i, 1], X[i, 2], 1 )
deformMash.setPoint(i, v)
if __name__ == "__main__":
main()