Jump to content

RBF Deformer with python issue


DonRomano

Recommended Posts

Hey guys,

I started writing a deformer using rbf (Radial Basis Function) with python, my aim is to reproduce the one made by Artem Smirnov in his reel : https://vimeo.com/338885866

Currently I try to get it working on geometry and then I'll implement it for volumes

I'm experiencing an issue and I don't really know from where it's coming : the deformation is kind of inverted on the other side of the geometry, where the geometry should not move and stay where it is, and I don't know what causes this.

Input 1 is the mesh, Input 2 is the rest lattice and Input 3 is the deformed lattice

 

Here's the code :

import numpy as np

node = hou.pwd()
inputs = node.inputs()

geo1 = node.geometry()
geo2 = inputs[1].geometry()
geo3 = inputs[2].geometry()

radius_parm = float(node.evalParm("radius"))

kernel_parm = node.evalParm("kernels")
kernel_names = "gaussian,thinPlateSpline,linear".split(",")
kernel = kernel_names[kernel_parm]

#####################################################
#distance calculation
def ext_arrs(A,B, precision="float64"):
    nA,dim = A.shape
    A_ext = np.ones((nA,dim*3),dtype=precision)
    A_ext[:,dim:2*dim] = A
    A_ext[:,2*dim:] = A**2

    nB = B.shape[0]
    B_ext = np.ones((dim*3,nB),dtype=precision)
    B_ext[:dim] = (B**2).T
    B_ext[dim:2*dim] = -2.0*B.T
    return A_ext, B_ext

def pdist_squareformed(a, b):
    A_ext, B_ext = ext_arrs(a, b)
    dist = A_ext.dot(B_ext)
    np.fill_diagonal(dist,0)
    return dist
    
def thinPlateSpline(x, r):
    arg = x / r
    result = arg * arg
    result = np.where(arg > 0, result * np.log(arg), result)
    return result 
    
def gaussianSpline(x, r):
    result = np.exp(-(x * x) / (r * r))
    return result 
    
def linear(x, r):
    result = x / r
    return result 
    
def rbf(x, kernel, radius):
    
    if kernel == "gaussian":
        result = gaussianSpline(x, radius)
    
    if kernel == "thinPlateSpline":
        result = thinPlateSpline(x, radius)
        
    if kernel == "linear":
        result = linear(x, radius)

    return result
    

#####################################################
#SETUP GEO POSITIONS MATRICES

numpt1 = len(geo1.iterPoints())    
matrixQ1 = np.zeros((numpt1, 3))  

numpt2 = len(geo2.iterPoints())
matrixQ2 = np.zeros((numpt2, 3))

numpt3 = len(geo3.iterPoints())
matrixQ3 = np.zeros((numpt3, 3))

#geo
i = 0;
for p1 in geo1.points():
    matrixQ1[i, 0] = p1.position()[0]
    matrixQ1[i, 1] = p1.position()[1]
    matrixQ1[i, 2] = p1.position()[2]
    i += 1

#lattice
j = 0;
for p2 in geo2.points():
    matrixQ2[j, 0] = p2.position()[0]
    matrixQ2[j, 1] = p2.position()[1]
    matrixQ2[j, 2] = p2.position()[2]
    j += 1
    
#deformed lattice
k = 0;
for p3 in geo3.points():
    matrixQ3[k, 0] = p3.position()[0]
    matrixQ3[k, 1] = p3.position()[1]
    matrixQ3[k, 2] = p3.position()[2]
    k += 1
    
    
#####################################################
#CALCULATE WEIGHTS

npts, dim = matrixQ2.shape

H = np.zeros((npts + 3 + 1, npts + 3 + 1))

H[:npts, :npts] = rbf(np.sqrt(pdist_squareformed(matrixQ2, matrixQ2)), kernel, radius_parm)

H[npts, :npts] = 1.0
H[:npts, npts] = 1.0
H[:npts, -3:] = matrixQ2
H[-3:, :npts] = matrixQ2.T

RH = np.zeros((npts + 3 + 1, dim))
RH[:npts, :] = matrixQ3

weights = np.linalg.solve(H, RH)


#####################################################
#DEFORMATION

npts2, dim2 = matrixQ1.shape

G = np.zeros((npts2, npts + 3 + 1))
G[:, :npts] = rbf(np.sqrt(pdist_squareformed(matrixQ1, matrixQ2)), kernel, radius_parm)

G[:, :npts] = 1.0
G[:, -3:] = matrixQ1

new_pos = np.asarray(np.dot(G, weights))


#####################################################
#SET POS

s = 0;
for p in geo1.points():
    newX = new_pos[s, 0]
    newY = new_pos[s, 1]
    newZ = new_pos[s, 2]
    
    p.setPosition((newX, newY, newZ))
    
    s += 1


 

screen_rbf_issue_2.png

screen_rbf_issue_1.png

Edited by DonRomano
Link to comment
Share on other sites

  • 1 year later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...