Radial Basis Function Interpolation

Geometry Deformation

The deformation network and it’s output (ground truth colored red)

This coefficient matrix can now be used to interpolate an attribute value for any position in space. So let’s copy it and the other detail attributes over to our target geometry stream with an AttributeCopy SOP. We’ll implement the deformation in OpenCL and VEX (as a fallback option if no GPU is available) by proceeding as follows. For every target point we’ll have to find the sum of the source points’ distances multiplied by their respective coefficient value (using the same basis function mode as the Python SOP). Then offset @P with this sum by choice.

Here’s the VEX code executed for every point of the target geometry:

    int deform = chi("do_deform");
    int mode = chi("mode");
    vector coef[] = detail(geoself(), "coef");
    vector lpos[] = detail(geoself(), "lpos");
    
    float basis(float d; int m;) {
        if (m==1) {
            return(d*d*d);
        } else if (m==2) {
            return(d*d*log(d));
        } else {
            return(d);
        }
    }
    
    int lattice_pts = detail(geoself(), "lpts");
    vector sum = set(0);
    for(int lpt=0; lpt<lattice_pts; lpt++) {
        float b = basis(distance(lpos[lpt], v@P), mode);
        sum += b*coef[lpt];
    }
    v@def = sum;
    if(deform==1) {
        @P += sum;
    }

The OpenCL version works pretty much the same except for some type handling (vload_3) and the slightly painful parameter setup on the node. Note that for attributes of different sizes you’ll have to use the respective variant of that function (vload_n).

    float basis(float d, int m) {
        if(m==1) {
            return(d*d*d);
        } else if(m==2) {
            return(d*d*log(d));
        } else {
            return(d);
        }
    }
    
    kernel void rbf_deform( 
                     int P_length, 
                     global float * P ,
                     int def_length, 
                     global float * def ,
                     int lpos_length, 
                     global int * lpos_index, 
                      global float * lpos ,
                     int coef_length, 
                     global int * coef_index, 
                      global float * coef ,
                     int lpts_length, 
                     global int * lpts,
                     int     do_deform,
                     int     mode 
    ){   int idx = get_global_id(0);
        if (idx >= P_length) {
            return;
        }
        
        float3 _P = vload3(idx, P);
        float3 sum = 0.0;
        float b;
        
        for(int lpt = 0; lpt<lpts[0]; lpt++) {
            b = length(vload3(lpt, lpos) - _P);
            sum += vload3(lpt, coef) * basis(b, mode);
        }
    
        if(do_deform==1) {
            _P += sum;
            vstore3(_P, idx, P);
        }
        vstore3(sum, idx, def);
    }
    

Leave a Reply

Your email address will not be published. Required fields are marked *