Interested in writing my own RBF node. Any info helpful!

I’m interested in writing my own RBF node, more for gaining the knowledge of creating it than the use of it. I’ve tried digging around online and have only found this description(http://www.marcuskrautwurst.com/2017/12/rbf-node.html) which brought me a lot of insight but following it along the matrix math does not come out as described. Others seem to have the same issue judging from the comment section. If anyone would be willing to direct me to other resources for digging into this, I would be most grateful.

1 Like

Super helpful! Thanks!!!

This is a link to the entire course the linked video is taken from at Caltech. http://work.caltech.edu/telecourse.html#lectures

Take some inspiration from Ingos RBF.

I had the same thing - the math didn’t work out. From my understanding, RBF is just another interpolator who’s weights are solved based on the radial distance. So you need to build a coefficients matrix of the distance of the targets with respect to each other using one of the RBF functions. The values you drive can be anything. Ive built solvers before but I used non-negative least squared for it using the scipy library - which is VERY fast :slight_smile:

I always go to wiki first as it tends to be devoid of any varitation of the math:

Now there are several versions of the RBF interpolator - Guassian, Multi-Quadratic, Linear etc… Anything other than Linear will require a epsilon variable. Here’s a graph I made showing Gausian and the epsilon c value - which is a constant across the system. It basically describes the falloff the poses will start to blend with each other.

https://www.desmos.com/calculator/ulmpwhvjcj

Approximation

So you have a bunch targets A, B, C and, from which you build a coefficients matrix (left side) of their distance to all the rest using a given RBF interpolation.


RBF(0)      RBF(|A-B|)   RBF(|A-C|)        1 ...
RBF(|B-A|)  RBF(0)       RBF(|B-C|)        2 ...
RBF(|C-A|)  RBF(|C-B|)   RBF(0)            3 ...

The zero’s are because its the distance of a target to itself. On the right side you have your values - these can be anything. So you then solve this matrix with least squares (numpy and scipy solve this).

So once you have your solved matrix of weights- all you’re doing is sum’ing the RBF interpolated poses using the distance between your driver and target multiplied by the solved weight for that target/pose.

I was very confused about RBF for ages because I saw the function and spent a long time trying to understand how it works for many poses. When I realized its just the interpolation e.g. (b-a) * t + a you’re just using to interpolate poses using the weights from a solved matrix.

This paper is excellent - A Radial Basis Function Approximation for Large Datasets:

There is a regularization multiplication you can add - I don’t understand this that well other than adding some evenness to the approximation. This is generally noted as g.

2 Likes

Git project for RBF node for Maya 2016.

1 Like

Oh neat, I was just about to add my github link that Riggity posted. I used C++ and the Eigen library to solve. It’s been a minute but I’m happy to answer what questions I can

Thanks so much for joining the thread. I’ve been going through your git code trying to get a better handle on how to set up the math for RBF solving. The Krautwurst how-to described setting up matrices in prep for a Ax=b solve which sounds like it makes sense…setting up relationships based on on distances between the end targets.
I need to dig into things a little more this weekend… I guess I’m still not sure what questions to ask.
I first thought of setting up rotation values correlated to a pose weight matrix. Each pose being fully dialed in and all others dialed out… but was told Euler rotation values are not the way to go…gimbal problems, etc.

If you could help me get a sense of how you set up relations to start the solution that would be really helpful.

How are you using Eigen values?

ah just to clarify Eigen library is used like scipy, it’s an library for C++ that I use to solve Ax=b, there are no eigenvalues / eigenvectors (lowercase e) used in my code

i’ll try and dig back in thursday night, been meaning to revisit this code anyway. iirc i did extract and blend using individual euler rotations, but used an up vector/object to stabilize. hm don’t quote me though. meanwhile it’ll probably be easier to start with blendshapes, rgb, or translation values, ie channels you can blend to independently

Ah…gotcha.
I have been using both numpy and linalg.py as suggested in the Krautwurst steps feeding it Ax=b setups. They solved correctly but I’m hazy on how to set up the matrices to feed into that scheme meaningfully.

Chad Vernon has posted a really good rundown in both C++ and Python using linear regression. https://www.chadvernon.com/blog/rbf/

1 Like

Chad’s stuff is excellent!,

Note - may have flubbed some of this, any mistakes let me know.

RBF (Radial Basis Function) is by its namesake a basis function meaning it’s an interpolator of basis vectors. A basis is basically a dimensional space. You can write any basis function you like - crucially its how you produce your coefficients matrix that you’re solving with thats key (and inherently linked to how the final poses is interpolated too) . RBF is a radial function, meaning it relies on distance (simple euclidean) - these vectors do not need to be 3-dimension rather they can be n-dimensional!

Thats where the power comes from - you breaking the 1:1 rule that weight drives a pose. You can have n-number of poses for n-number of weights meaning you could have 10 weights driving 50 poses - In this case you have a 10 dim space with your poses being locations within it. RBF interpolates these poses as scattered interpolation.

In the simplest example lets say we have two weights w0 and w1 - lets have 4 poses:

pose a) w0=1.0 w1=0.0
pose b) w0=0.0 w1=1.0
pose c) w0=1.0 w1=1.0
pose d) w0=0.5 w1=0.5

This equates to four 2 dimensional vectors - these are you poses but not the final values that get interpolated. Now with RBF your coefficients matrix is the RBF interpolated weight for each pose relative to all the others ~ rough values here:

                RBF for a)      RBF for b)     RBF for c)    RBF for d)
pose a)         1.0             0.0            0.0           0.5
pose b)         0.0             1.0            0.0           0.5
pose c)         0.0             0.0            1.0           0.5
pose d)         0.5             0.5            0.5           1.0

Note - these are just arbitrary, you will have a falloff variable c for the interpolation which will describe how the the interpolated poses will blend. There are different methods for RBF interpolation - linear, gaussian, multivariate, thin-plate and so forth.

This is your coefficients matrix - its the left side part of the what your trying to solve - on the right side would be your values. So for numpy.linalg.leastsq your Ax=B - means A is your coeficents and B is your values your trying to solve for.

This will return a set of values that you interpolate the same way using RBF as your function, but your summing the interpolated solved value for each pose i.e. Take my input vector (sliders, position in space, etc) and sum the interpolated solved value of each pose by its extrapolated weight.

I’ve also seen this type of system described as a kernal based one. You first solve for the kernal(the weighted matrix, or the x in Ax=B) and then solve for your output B.