RBF Features¶
Introduction to RBF in py-dem-bones¶
py-dem-bones integrates SciPy’s Radial Basis Function (RBF) capabilities with Dem-Bones skeletal weight calculations to support advanced animation workflows. This integration enables:
Using Dem-Bones to calculate basic bone weights and transformations
Leveraging SciPy’s RBFInterpolator to create parameter-driven auxiliary joints
Implementing functionality similar to Chad Vernon RBF nodes, but using standard Python scientific computing libraries
Key Advantages¶
Uses production-grade SciPy implementation instead of custom RBF code
Supports multiple RBF kernel function options (thin plate spline, multiquadric, gaussian, etc.)
Seamlessly integrates with the Python scientific computing ecosystem
Maintained and updated by the scientific computing community
RBF Kernel Functions¶
The following kernel functions are available through SciPy’s RBFInterpolator:
thin_plate_spline: φ(r) = r²log(r), suitable for smooth interpolation with minimal curvature
multiquadric: φ(r) = sqrt(1 + (εr)²), good for general-purpose interpolation
inverse_multiquadric: φ(r) = 1/sqrt(1 + (εr)²), creates smoother interpolations
gaussian: φ(r) = exp(-(εr)²), creates very smooth interpolations with local influence
linear: φ(r) = r, simple linear interpolation between points
cubic: φ(r) = r³, provides smooth interpolation with more local control
quintic: φ(r) = r⁵, higher-order polynomial with smoother derivatives
Where r is the distance between points and ε is a shape parameter that controls the influence radius.
Example Usage¶
Here’s a basic example of using RBF interpolation with py-dem-bones:
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3"""
4RBF Integration with DemBones Demo
5
6This example demonstrates how to combine DemBones with SciPy's RBF functionality, similar to Chad Vernon's implementation.
7We will use DemBones to calculate bone weights and transformations, then use RBF interpolators to drive auxiliary joints.
8
9To run this example, you need to install the following dependencies:
10 pip install py-dem-bones numpy matplotlib scipy
11"""
12
13import numpy as np
14import matplotlib.pyplot as plt
15from mpl_toolkits.mplot3d import Axes3D
16from scipy.interpolate import RBFInterpolator
17import py_dem_bones as pdb
18
19
20def create_simple_mesh():
21 """
22 Create a simple test mesh (cube)
23 """
24 # Create cube vertices
25 vertices = np.array([
26 [0, 0, 0], # 0
27 [1, 0, 0], # 1
28 [1, 1, 0], # 2
29 [0, 1, 0], # 3
30 [0, 0, 1], # 4
31 [1, 0, 1], # 5
32 [1, 1, 1], # 6
33 [0, 1, 1], # 7
34 ], dtype=np.float64)
35
36 return vertices
37
38
39def create_deformed_mesh(vertices, deformation_amount=0.3):
40 """
41 Create a deformed mesh
42 """
43 # Deform the upper part of the cube
44 deformed = vertices.copy()
45 # Deform the upper part (vertices 4-7)
46 deformed[4:, 0] += deformation_amount # Offset along X axis
47 deformed[4:, 2] += deformation_amount # Offset along Z axis
48
49 return deformed
50
51
52def compute_dem_bones(rest_pose, deformed_pose, num_bones=2):
53 """
54 Use DemBones to calculate skinning weights and bone transformations
55 """
56 # Create DemBones instance
57 dem_bones = pdb.DemBones()
58
59 # Set parameters
60 dem_bones.nIters = 30
61 dem_bones.nInitIters = 10
62 dem_bones.nTransIters = 5
63 dem_bones.nWeightsIters = 3
64 dem_bones.nnz = 4 # Number of non-zero weights per vertex
65 dem_bones.weightsSmooth = 1e-4
66
67 # Set data
68 dem_bones.nV = len(rest_pose) # Number of vertices
69 dem_bones.nB = num_bones # Number of bones
70 dem_bones.nF = 1 # Number of frames
71 dem_bones.nS = 1 # Number of subjects
72 dem_bones.fStart = np.array([0], dtype=np.int32) # Starting frame index for each subject
73 dem_bones.subjectID = np.zeros(1, dtype=np.int32) # Subject ID for each frame
74 dem_bones.u = rest_pose # Rest pose
75 dem_bones.v = deformed_pose # Deformed pose
76
77 # Compute skinning decomposition
78 dem_bones.compute()
79
80 # Get results
81 weights = dem_bones.get_weights()
82 transformations = dem_bones.get_transformations()
83
84 return weights, transformations
85
86
87def create_rbf_interpolator(key_poses, key_values, rbf_function='thin_plate_spline'):
88 """
89 Create RBF interpolator, similar to Chad Vernon's RBF nodes
90
91 Parameters:
92 key_poses: Input values for key poses (n_samples, n_features)
93 key_values: Output values for each key pose (n_samples, m)
94 rbf_function: RBF function type, options include:
95 - 'thin_plate_spline': Thin plate spline (default)
96 - 'multiquadric': Multiquadric
97 - 'inverse_multiquadric': Inverse multiquadric
98 - 'gaussian': Gaussian function
99 - 'linear': Linear function
100 - 'cubic': Cubic function
101 - 'quintic': Quintic function
102
103 Returns:
104 RBF interpolator
105 """
106 # Use SciPy's RBFInterpolator, which is a more modern alternative to the Rbf class
107 return RBFInterpolator(
108 key_poses,
109 key_values,
110 kernel=rbf_function,
111 smoothing=0.0 # No smoothing, exact interpolation
112 )
113
114
115def visualize_results(rest_pose, deformed_pose, dem_bones_weights, helper_joint_positions):
116 """
117 Visualize results
118
119 Parameters:
120 rest_pose: Vertex positions in rest pose
121 deformed_pose: Vertex positions in deformed pose
122 dem_bones_weights: Bone weights calculated by DemBones
123 helper_joint_positions: Auxiliary joint positions calculated by RBF interpolator
124 """
125 fig = plt.figure(figsize=(18, 6))
126
127 # First subplot: Original mesh
128 ax1 = fig.add_subplot(131, projection='3d')
129 ax1.scatter(rest_pose[:, 0], rest_pose[:, 1], rest_pose[:, 2], c='blue', s=100)
130 ax1.set_title('Original Mesh')
131 ax1.set_xlabel('X')
132 ax1.set_ylabel('Y')
133 ax1.set_zlabel('Z')
134
135 # Second subplot: Deformed mesh
136 ax2 = fig.add_subplot(132, projection='3d')
137 ax2.scatter(deformed_pose[:, 0], deformed_pose[:, 1], deformed_pose[:, 2], c='red', s=100)
138 ax2.set_title('Deformed Mesh')
139 ax2.set_xlabel('X')
140 ax2.set_ylabel('Y')
141 ax2.set_zlabel('Z')
142
143 # Third subplot: Weights and auxiliary joints
144 ax3 = fig.add_subplot(133, projection='3d')
145 # Use weight values as colors
146 colors = dem_bones_weights[:, 0] # Use weights of the first bone as colors
147 scatter = ax3.scatter(
148 deformed_pose[:, 0],
149 deformed_pose[:, 1],
150 deformed_pose[:, 2],
151 c=colors,
152 cmap='viridis',
153 s=100
154 )
155 # Add auxiliary joint positions
156 ax3.scatter(
157 helper_joint_positions[:, 0],
158 helper_joint_positions[:, 1],
159 helper_joint_positions[:, 2],
160 c='red',
161 marker='x',
162 s=200
163 )
164 ax3.set_title('Bone Weights and Auxiliary Joints')
165 ax3.set_xlabel('X')
166 ax3.set_ylabel('Y')
167 ax3.set_zlabel('Z')
168 plt.colorbar(scatter, ax=ax3, label='Bone Weights')
169
170 plt.tight_layout()
171 plt.show()
172
173
174def main():
175 # Create test data
176 rest_pose = create_simple_mesh()
177 deformed_pose = create_deformed_mesh(rest_pose)
178
179 print("1. Computing DemBones weights and transformations...")
180 weights, transformations = compute_dem_bones(rest_pose, deformed_pose)
181
182 print("Bone weights:")
183 print(weights)
184 print("\nBone transformations:")
185 print(transformations)
186
187 # Create RBF interpolation data
188 print("\n2. Creating RBF interpolator...")
189
190 # Define input key poses
191 # In a real scenario, these might be controller positions or other control values
192 key_poses = np.array([
193 [0.0, 0.0], # Default pose
194 [1.0, 0.0], # X-direction extreme
195 [0.0, 1.0], # Y-direction extreme
196 ])
197
198 # Define output values - auxiliary joint positions
199 # These are the positions of auxiliary joints corresponding to each key pose
200 key_values = np.array([
201 # Auxiliary joint positions for default pose
202 [[0.5, 0.5, 0.0], [0.5, 0.5, 1.0]],
203 # Auxiliary joint positions for X-direction extreme
204 [[0.7, 0.5, 0.0], [0.7, 0.5, 1.2]],
205 # Auxiliary joint positions for Y-direction extreme
206 [[0.5, 0.7, 0.0], [0.5, 0.7, 1.2]],
207 ])
208
209 # Create RBF interpolator
210 rbf = create_rbf_interpolator(key_poses, key_values.reshape(3, -1), rbf_function='thin_plate_spline')
211
212 # Test RBF interpolation
213 test_pose = np.array([[0.5, 0.5]]) # Test pose
214 interpolated = rbf(test_pose).reshape(-1, 3) # Get interpolation result
215
216 print("Input test pose:", test_pose)
217 print("Interpolated auxiliary joint positions:")
218 print(interpolated)
219
220 # Visualize results
221 visualize_results(rest_pose, deformed_pose, weights, interpolated)
222
223 print("\n3. Testing RBF interpolation for different poses:")
224 # Test RBF interpolation for different poses
225 test_poses = [
226 [0.0, 0.0], # Default pose
227 [1.0, 0.0], # X-direction extreme
228 [0.0, 1.0], # Y-direction extreme
229 [0.5, 0.5], # Middle pose
230 [0.25, 0.75], # Other pose
231 ]
232
233 for i, pose in enumerate(test_poses):
234 test_pose = np.array([pose])
235 result = rbf(test_pose).reshape(-1, 3)
236 print(f"\nTest pose {i+1}: {pose}")
237 print(f"Interpolated auxiliary joint positions:")
238 print(result)
239
240
241if __name__ == "__main__":
242 main()
Maya Integration¶
To use the RBF functionality in Maya:
Implement the MayaDCCInterface to handle Maya-specific data structures
Replace matplotlib visualizations with Maya nodes/views
Consider Maya’s Python environment compatibility
import maya.cmds as cmds
from py_dem_bones.interfaces.dcc import DCCInterface
from scipy.interpolate import RBFInterpolator
import numpy as np
class MayaDCCInterface(DCCInterface):
def from_dcc_data(self, **kwargs):
# Implementation for Maya data extraction
pass
def to_dcc_data(self, **kwargs):
# Implementation for Maya data application
pass
# Create RBF setup between two poses
def create_rbf_setup(source_joint, target_joint, poses):
# Extract pose data
source_poses = []
target_poses = []
for pose in poses:
# Set the pose
cmds.setAttr(f"{pose['control']}.{pose['attribute']}", pose['value'])
# Get joint positions
source_pos = cmds.xform(source_joint, q=True, ws=True, t=True)
target_pos = cmds.xform(target_joint, q=True, ws=True, t=True)
source_poses.append([pose['value']])
target_poses.append(target_pos)
# Create RBF interpolator
rbf = RBFInterpolator(
np.array(source_poses),
np.array(target_poses),
kernel='thin_plate_spline'
)
return rbf
Jupyter Notebook Integration¶
A Jupyter Notebook version of the RBF demo is available for interactive exploration. The notebook includes:
Interactive visualizations
Step-by-step explanations with markdown
Compatibility with Google Colab
Installation instructions for dependencies
Compatibility¶
The RBF functionality requires:
Python 3.8+
SciPy 1.7.0+
NumPy 1.20.0+
For Maya integration, compatibility has been tested with:
Maya 2020+
Python 3.8+ (as provided by Maya)
API Reference¶
For detailed API documentation, see the Python API section.