Transfer vertex weights to vertex colors and vice versa

In a previous article I mentioned that my WeightLifter addon was updated and could now (besides many other things) transfer vertex weights to vertex colors and vice versa. Because this might be of use to many people I decided to split off this specific functionality into a separate addon and provide it for free.

After installing the addon in the usual manner you get two new menu options: one in the Weights menu in Weight Paint mode called VertexColorsToWeights and a corresponding one in the Paint menu in Vertex Paint mode.


Weight paint mode

In weight paint mode clicking on Weights -> VertexColorToWeight will transfer a color from the active vertex color layer to the active vertex group. If there is no vertex color layer present a will cretae a new one. You have an option to choose which color channel to use as weight or to combine all colors.

Vertex paint mode

In vertex paint mode clicking on Paint -> WeightToVertexColor will transfer the weights from the active vertex group to the active vertex color layer. if there is no veretx group present it will create a new one. You have again an option to transfer the weights to a single color channel or to all color channels.

Code Availability

The code can be downloaded from my GitHub repository.

WeightLifter add-on: user feedback release

Version 20150222 incorporates a lot of features based on user feedback, including an invert option, a new mode (that measures distances to selected vertices), auto update of particles systems that use a a vertex group and extra operators/menu options to transfer values between vertex groups and vertex color layers. The new version is available free of charge to people who have already purchased the add-on. Check the BlenderMarket page for more details.

Distance to selected verts

The new mode Distance to selected verts lets you for example create vertex groups that might be used to control the distribution of particle systems based on the distance to a wall:

Auto update of particle systems

If a vertex group is updated by WeightLifter it now takes care to trigger an update on any associated particle system that uses the vertex group. This way you can get immediat efeedback on the effects of your WeightLifter actions.

Transfer weights to vertex colors (and vice versa)

Sometimes it might be useful to transfer the weights of vertex group to a vertex color layer or the other way around. This might be useful in other contexts beside WeightLifter too, so this functionality is implemented as two separate operators that are available from the Weights menu in vertex weight mode and from the Paint menu in vertex color mode. There are installed automatically with WeightLifter/

WeightLifter in the press

Got a very positive review of my WeightLifter addon on BlenderNation. Needless to say I'm very pleased. The suggestions about a warning when there are modifiers that affect the mesh resolution and the wish to transfer weights to vertex colors and vice versa is noted too, I'll see if I can include that functionality in the future.

The addon itself is of coyrse available on BlenderMarket.

Blender addon to setup image based lighting (IBL) nodes in Cycles, bugfix

The addon I introduced in a previous article has a small bugfix release. Check the article for download instructions, the version on GitHub is the latest.

WeightLifter add-on: minor bugfix release

A new version of my commercial WeightLifter add-on is now available. Version 20150214 fixes a small bug where you would get an error in slope mode with the 3D cursor as a reference if the 3D cursor was at the center of the world.

Using vertex colors to color hair in Cycles

I got a question related to my WeightLifter Addon asking whether is was possible to use the addon to control hair particles. The addon itself does of course not control any particles but the vertex groups and vertex colors it creates can be used by any particle system to control the distribution and coloring of the the particles or hairs strands as shown in this example:

For this image WeightLifter was used to create a vertex group with more weight on horizontal surface:

Then this vertex group was used to control the distribution of the hairs by selecting the gruop in the particle system settings:

In the same manner WeightLifter was used to create vertex colors that change colors from left to right:

A Cycles material was then created to use these vertex colors (via the Attribute node) to color the hairs

Parameterized objects in Blender, a Python tutorrial

Writing new Blender operators in Python is quite simple and adding all sorts of parameters to customize that mesh is also not difficult but once a mesh is added to the scene and you have performed other actions it is no longer possible to tweak those settings and alter the mesh. You can of course delete the object and execute the operator anew but with more than one object the operator would remember its last settings which are not necessarily the ones you used to create the object you want to change. It would be much more convenient to have the options available for tweaking directly when you select an object.

The way to achieve this is to store the values for these options not as part of the operator but as part of the object and create an operator that checks for these object-bound properties and acts on their value.

Fortunately it's rather easy to do this in Blender and the code snippet below show how this can be done: it implements a very simple Spokes object, i.e. an object with a configurable number of arms, like in the picture below.

The number of arms is stored as an object property and the code provides both an operator to add a Spokes object and a panel that is installed in the modifier context to change the number of spokes. There is nothing special about placing the panel with the modifiers, you could position it elsewhere, but because these properties are persistent and changing them is non destructive it feels to me a bit like a modifier.

bpy.types.Object.reg = StringProperty()

bpy.types.Object.numberofspokes = IntProperty(name="Number of spokes",
         description="Number of spokes",
         default=6,
         min=2,
         soft_max=50,
         update=updateMesh)

class Spokes(bpy.types.Panel):
 bl_idname = "Spokes"
 bl_label = "Spokes"
 bl_space_type = "PROPERTIES"
 bl_region_type = "WINDOW"
 bl_context = "modifier"
 bl_options = {'DEFAULT_CLOSED'}

 def draw(self, context):
  layout = self.layout
  if bpy.context.mode == 'EDIT_MESH':
   layout.label('Spokes doesn\'t work in the EDIT-Mode.')
  else:
   o = context.object
   if 'reg' in o:
    if o['reg'] == 'Spokes':
     box = layout.box()
     box.prop(o, 'numberofspokes')
    else:
     layout.operator('mesh.spokes_convert')
   else:
    layout.operator('mesh.spokes_convert')

class SpokesAdd(bpy.types.Operator):
 bl_idname = "mesh.spokes_add"
 bl_label = "Spokes"
 bl_options = {'REGISTER', 'UNDO'}

 @classmethod
 def poll(self, context):
  return context.mode == 'OBJECT'

 def execute(self, context):
  bpy.ops.mesh.primitive_cube_add()
  context.active_object.name = "Spokes"
  bpy.ops.mesh.spokes_convert('INVOKE_DEFAULT')
  return {'FINISHED'}

class SpokesConvert(bpy.types.Operator):
 bl_idname = 'mesh.spokes_convert'
 bl_label = 'Convert to Spokes object'
 bl_options = {"UNDO"}

 def invoke(self, context, event):
  o = context.object
  o.reg = 'Spokes'
  o.numberofspokes = 6 # assigning something forces call to updateMesh()
  return {"FINISHED"}
The first lines in the code snippet show the property definitions while line 10 and 33 are where code for the modifier panel and the operators start respectively. Note that the new properties are added to the bpy.types.object. Because Python is such a dynamic language we can add properties to existing class objects.

The nitty gritty

There are a few things to note. When defining a new object property this custom property is available on all Blender objects. It is therefore not sufficient to check whether the numberofspokes property exists to see if we want to show a panel (in the draw() function at line 24). We could check if it contained a valid integer (because other objects that were not created with the Spokes operator would have the property but it wouldn't have been initialized) but it is much easier to create a second object property (a string property called reg in this example) that holds a value that identifies it as a Spokes object. This property could be reused and hold different values for other kinds of parameterized objects. The panel is part of the modifier context and looks like this:

The class that implements the panel doesn't have any code to actually change a Spokes object, all it does is display the numberofspokes property. This property however is defined with a reference to the updateMesh() function (line 8, the actual definition of tbe function is not shown) via its update argument, so every time the numberofspokes option is adjusted this function gets called to update the mesh.

The draw() function also shows a message when we are in edit mode and offers to convert an object to a Spokes object if it isn't already. The reason to have two operators is that we would like to have the option to create a Spokes object from scratch (from the add->mesh menu) and to convert existing objects. For the first option we provide the SpokesAdd operator, which merely creates a cube object and calls the SpokesConvert operator.

All that the SpokesConvert operator does is to assign values the object properties which will trigger a call to the updateMesh() function that will change the mesh data.

Note that custom properties that we defined are also available in the context panel (the one you get when pressing ctrl-n in the 3d view) but unlike the panel we defined we have no control over how to display these properties. They are however 'live', changing the numberofspokes property here will just as surely alter your object as when you alter it in the modifier panel.

Summary

To create parameterized objects you need to:
  • add properties to the bpy.types.Object class
  • make sure one of these properties can be used to identify an object as being a parameterized object
  • create an operator to add a new object like always but make sure it sets these object properties as well
  • create a way (a panel for example) to let the user alter the new object properties
  • create a function to actually alter the mesh when a property is changed

Code availability

The full code for a working add-on is available on GitHub