Sunday, August 19, 2012

"Remapped Shape Keys Transfer" Revisited

Over a year ago, I released an experimental tool for transferring shape keys between meshes ([1] [2]). Unlike the builtin copy shapekeys tool, this one was built specifically for the case where the vertex counts were different but where significant parts of the mesh were still relatively untouched. This commonly occurred when you've gone and added some extra geometry (e.g. extra limbs/edge loops etc.) to a mesh after adding shapekeys.

Today, by popular request (and for a little diversion before jumping into my next block of scheduled project work), I've taken some time to check on this tool and get it working in 2.63/4 again.

Key Changes:
  • Fixed a small bug which was preventing it from working in 2.6.
  • Added support for copying vertex groups  ("Remapped Vertex Groups Transfer")

For the impatient, here the link:

Surprisingly, it actually worked without needing any significant changes to work with BMesh in 2.6! Considering that this was coded for 2.57, that's quite a miracle in Blender Python API terms. The only problem that was preventing it from working was "just" one of my debugging hacks, where apparently some changes in the Python 3 interpreter used have changed the lookups a bit (looking back at the offending piece of code, it's kindof surprising that it actually even worked in the first place!) meaning that it couldn't find "srcMesh" and "tarMesh" anymore when it went to tag their verts as being selected.


Having gotten this working and while preparing to write this post, I remembered that there had also been multiple requests for a "transfer vertex groups" feature too, based on this tech. It can now announce that this too is now available, as a separate operator ("Remapped Vertex Groups Transfer").

Getting this to work was actually a bit trickier than anticipated due to the API changes in this area due to BMesh. Having said that, by and large it was a piece of cake compared to some of the API's and projects I've been dealing with in the past few months (GTK, OpenCV, NumPy, matplotlib) which could be described as hell holes (for the worst offenders) and annoying (for the latter two). In particular, I'd like to draw your attention to several gotchas when trying to add new vertex groups to meshes:
  • If you intend to modify vertex group weights (this includes adding vertices to vertex groups), then you need to make a temporary BMesh copy of the mesh (bm =; bm.from_mesh(mesh)), where you'll perform the operations on one of the "Custom Data Layers" (deform) of that copy. Knowing this, the steps for actually performing that editing are 'satisfactorily' covered in the API docs (see 3rd example here).
  • Because you're working with a copy of the mesh, you'll need to recopy that BMesh copy everytime you use to add a vertex group, otherwise the new vertex groups won't be visible to the BMesh copy at all (you may also get a crash, though I'm not sure if that was related to this or not). Also, don't forget that you'll also need to flush (bm.to_mesh(mesh)) your changes from the BMesh back to the original mesh, or else those changes will be lost! Oh, and you'd be best advised to do a after you're done with an BMesh instance/copy to avoid any accidents with garbage collection not freeing everything and running out of RAM after many operations
  • Calling, and then rebuilding a BMesh instance is not enough to ensure that you'll have a deformverts customdata layer to actually work on. In fact, since vertex groups are implemented in a strange split-level style (name data is on object level, everything else is stored on the geometry), creating one doesn't equate to creating the other. After some digging, I finally found that you need to do, bm.verts.layers.deform.verify() instead of the .active suggested by the doc if you want to safely be able to modify group membership of vertices for a newly created vertex group.
Now, since this is my first time using this API, I may have overlooked something here (i.e. I may be being overly cautious/aggressive in terms of flushing and recreating BMesh copies here). However, it appears to work well enough so far.


Recently, I came across the "Mesh Saliency" paper by Lee et al. (2005), which might be a promising approach to use for detecting initial targets on meshes that have had a bit more geometric manipulation (e.g. a global smooth operation applied before having vertices pulled around). If/when I get some time, it'd be an interesting experiment to implement this and see how this compares, and to sue this as a backup method for the cases that are even worse than the original use case of these tools.


So to recap: today, I've updated the script to transfer shape keys (and now vertex groups) from one mesh to another, where the vertex counts may differ, as long as significant portions of the mesh are identical and


  1. Thank you very very much!I waited patiently for this, thanks to you here it is, I will try it as soon as I can(after few days when I come back home from vacation)

  2. Very nice script. Better as Blender`s core transfer keys ( it needs the same number of vertices).
    Please adapt your script to new Blender - 2.68, 2.69.
    It works in 2.67 only...

  3. hi Algorith,

    Is there a 2.69 / 2.7 compatible version of your brilliant 'remap shape keys script?' Would you consider making a short video screencapture demonstrating how it works?

  4. I tested it in 2.69 - it works! I made skapekeys transfer without mistakes.
    ( the first click on checkbox - rigging addons - it wrote error, but the second click was successful.)

    2.70 - the same! It works.
    ( the first click on checkbox - rigging addons - it wrote error, but the second click was successful.)
    Happy transfering!
    Thanks for Aligorith