PlaneFit: Blender add-on to fit a plane through a set of vertices

After all the updates to my BlenderMarket add-ons, it is time to spend some time on other add-ons again.

Fitting a plane

Fitting a plane through a collection of selected vertices might be useful in all sort of scenarios. Currently you can snap a plane to a face with Blender's snap tools but if we want to fit a plane to a large set of vertices, we need to resort to basic linear algebra to do this in a fast and robust manner. And because linear algebra is not everybody's favorite subject I created a small add-on.

After installation the add-on is available from the Add menu if you have a mesh in edit mode. Clicking on it will create a square plane that is fitted through all selected vertices. A size option lets you scale this new plane interactively. The result might look something like this:
Note that currently we not check if the minimum of 3 vertices are selected, you get a an error if you try.


As usual the add-on is available from my GitHub repository. (right-click on the link and select Save As .. to store the .py file somewhere where you can find it again )

Source code

Both the linear algebra and the code to add a plane to an exiting mesh isn't completely trivial, so let me highlight the interesting bits:

Fitting a plane

The fitting code is quite short and straight forward:
import numpy as np

def planeFit(points):
    ctr = points.mean(axis=0)
    x = points - ctr
    M = np.cov(x.T)
    eigenvalues,eigenvectors = np.linalg.eig(M)
    normal = eigenvectors[:,eigenvalues.argmin()]
    return ctr,normal
Any book on linear algebra can give you a better explanation but with a fair bit of hand-waving it can be explained as follows: points is a list of 3d-vectors. ctr will be the midpoint of the plane which is the mean of each of the x, y and z-components.

In line 5 - 7 we calculate the eigen vectors of the point cloud. It is a 3d cloud so we will get 3 eigen vectors and 3 corresponding eigenvalues. Each combination of eigen value and eigen vector can be interpreted as a direction vector and a measure of how well it explains the spread of the points. This means that if the points lie roughly in a plane, the two biggest eigen vectors lie in the best fit plane while the smallest one will be the normal (all eigen vectors are perpendicular). And indeed this smallest one is the one we get in line 8.

Adding a plane an existing mesh

Now adding a plane consisting of four vertices in a square would be quite simple, yes? Ehh, no: the Mesh object has a from_pydata() function but it only works correctly when adding to an initially empty mesh. So lines 15 - 27 essentially replicate what that function does: create 4 vertices, and 4 loops, compose a polygon out of it and add it to the mesh as well. We could have worked with a BMesh representation but then we would not have an efficient way to retrieve all vertex coordinates, something we really need when working with thousands of vertices.

The code in lines 7 - 12 is a very efficient way to get the coordinates of selected vertices into a Numpy array: we create Numpy arrays to hold all the vertex coordinates and the selected status, then get all of them with the fast built-in function foreach_get(). verts[selected] then leaves us with an array of just the coordinates of selected vertices, which we pass to our planeFit() function we saw earlier.

We then create two vectors perpendicular to our normal and use them to construct four vertex coordinates.

         def execute(self, context):
  me =
  count = len(me.vertices)
  if count > 0:  # degenerate mesh, but better safe than sorry
   shape = (count, 3)
   verts = np.empty(count*3, dtype=np.float32)
   selected = np.empty(count, dtype=np.bool)
   me.vertices.foreach_get('co', verts)
   me.vertices.foreach_get('select', selected)
   verts.shape = shape
   ctr, normal = planeFit(verts[selected])
   dx, dy = orthopoints(normal)  # definition of orthopoints() not shown
   # can't use mesh.from_pydata here because that won't let us ADD to a mesh
   me.vertices[count  ].co = ctr+dx*self.size
   me.vertices[count+1].co = ctr+dy*self.size
   me.vertices[count+2].co = ctr-dx*self.size
   me.vertices[count+3].co = ctr-dy*self.size
   lcount = len(me.loops)
   pcount = len(me.polygons)
   me.polygons[pcount].loop_total = 4
   me.polygons[pcount].loop_start = lcount
   me.polygons[pcount].vertices = [count,count+1,count+2,count+3]

  return {'FINISHED'}

IDMapper: December 2017 release available on Blender Market

I have released an updated version of the IDMapper add-on to Blender Market.

New features

It features some cosmetic changes but more importantly it hosts a ton of new features developed based on user feedback, including:
you can now directly bake a vertex color layer to an image without the cumbersome route of setting up materials, emission shaders and dummy images necessary in the regular way. Just 1-click and a couple of seconds later you'ĺl have you color id-map as an image in the UV-image editor
Vertex groups to vertex colors
there is now an option to assign unique vertex colors based on vertex group membership of vertices. This 1-click option lets you quickly convert vertex groups to vertex colors
Create materials based on vertex colors
this option creates a material for each unique vertex color and assigns the vertices with this color to the material.
Better color list management
If you use a predefined list of colors to use in id-maps across different models the color list lets you manage these colors. It is now possible to add items to this list for any vertex color nor yet present, simplifying the maintenance of those lists
And of course there are lots of smaller improvements too.

The new features are highlighted in this video:

This video is part of a small playlist with additional tutorials:


IDMapper is available in my Blender Market shop:

New version of WeightLifter introduces baking and animation

A new version of WeightLifter is available on BlenderMarket.

WeightLifter is an add-on that can calculate all sorts of information and store this into vertex groups or vertex color layers. It can for example determine the visibility of vertices for a certain camera or the distance to some light source and much more, information that can for example be used as a density map in particle systems.

New features

The newest version introduces some new modes like calculating a flow map or the mesh deformation but the most exiting new feature is the ability to bake any weight map for each frame in an animation. This way can quickly regenerate a vertex group for each frame while rendering, effectively animating a weight map, something which is not possible otherwise.

To illustrate how to do this, I have created a short video that shows the workflow for creating an animated density map that lets the proximity to a lamp drive the emission of particles.

Nodeset: tiny enhancement

A new version of nodeset is available that includes .jpg in the default list of extensions.


The current version (201712020811) is available for download (right click and save as ...) from my GitHub repository.

Previous nodeset articles

I wrote several articles on this tiny add-on that you might want to read. They are (newest first):

Blender Market Black Friday - Cyber Monday sale

Goods news for cost conscious Blenderheads: this thanksgiving weekend Blender Market will host the yearly Black Friday - Cyber Monday sale!

I will participate with my add-ons, including the popular IDMapper add-on. So if you want to save significantly on WeightLifter, SpaceTree, or IDMapper (video), head over to my shop on Blender Market this weekend. Of course many other creators will be participating as well so you might want to shop around a bit more :-)

[For Europeans: remember Blender Market runs on Chicago time, so don't start shopping too early next Friday :-) ]

Add-on: make vertex colors unique across selected objects

Say you have carefully assigned vertex colors to your mesh to be used as a color ID mask in a texturing program. And now you want two copies of this mesh and you want to assign different materials while using the same texture set for both objects to save on the number of textures. Assuming you have given each mesh a uv-mapping that covers a different set of uv-coordinates this shouldn't be an issue if you could make the vertex colors unique across this meshes.
This is where this add-on comes in handy: it will count the number of vertex colors used in all selected objects and reassign colors in such a way that all the colors are unique with the selected objects.
For example, starting with two meshes with identical color assignments

You will end up with something like this:

Note that none of the colors used in the left mesh appear in the right mesh and vice versa.


As usual the add-on is available for download from my GitHub repository (right click on the link and select Save as ...)
After you have installed and enabled the add-on, a new menu entry will be available in object mode: Object → Make vertex colors unique.
It might be a bit odd not to have this in vertex paint mode but it operates on more than one selected object and selecting objects is not possible in vertex paint mode so this is a bit less inconvenient.

Version 20170918 of IDMapper available on Blender Market

I have released an update version of the IDMapper add-on to Blender Market.

In the video I demo the new functionality and I have listed the release notes at the end of this article.

If you would like more information on all the functionality, have a look at this article. A complete workflow demonstration is available in this demo video.

Release notes

Version 20170918

  • Add ID Color List management
  • it is now possible to load, manage and save named lists of colors and to pick colors from this list when working in Face Paint mode. This is convenient if your studio uses smart materials for example and you have a list of predefined ID map colors you want to use for many different assets. Unlike Blender's built-in palettes, these colors have names, can be searched and sorted and loaded/saved as .csv files.
  • Add color picking outside select object in Face Paint mode
  • Number of undo levels in Face Paint mode is now configurable