WeightLifter - Vertex Group Tool, bugfix release

Recently I published my first commercial addon on BlenderMarket and I am very pleased with the reactions I got so far. A big thank you to all those people who purchased the addon!

Of course, no serious piece of software is completely without bugs so I updated the addon a few hours ago. Version 20141018 contains a few small bugfixes and removes a limitation that could lead to crashes when assigning random weights to groups of connected vertices on large meshes (Thank you Wybren for reporting this).

DryStone: create irregular stone walls

It's been a while but I haven't been completely idle during the holiday season: In this post I am happy to present a small Blender addon that creates walls of irregular stacked stones.

Inspired by the walls of the castles at Conwy and Beaumaris this addon aims to produce irregular walls, resembling the ones shown below.

For quite some time Blender users have known the excellent masonry addon but I wanted irregular walls (and a proving ground for serious bmesh programming).

The addon offers a number of controls to tweak the appearance that should be quite self explanatory. It's available from GitHub and discussed in this BlenderNation thread. Download it and select File->User Preferences->Addons->Install from file to install it and it will then be available in the Add->Add mesh menu in the 3D view.

The mesh that is created consists of separate n-gons and the depth is provided by a solidify modifier topped by a bevel modifier. Currently you will have to do the uv-unwrapping yourself. The image at the start was created with a procedural stone texture.

Interested in a professional add-on to capture all kinds of mesh characteristics into vertex groups or vertex colors? Then have a look at my WeightLifter addon on BlenderMarket. (In the first image it was used to quickly assign a random vertex color to each block to vary the coloring and bump mapping for each separate block).

Floor board generator, using a floor plan




I have started on the support for a floor plan, i.e. restricting the generated planks to some outline. This feature is very much a work in progress but it is already useable:
It works by adding and applying a boolean modifier to the generated floorboards.

The current [updated] workflow is like this:
  • select your floor plan, make sure it is flat, has a number of faces selected and the face normals pointing up:

  • position the 3D cursor just outside the bottom left corner of the floor plan
  • choose Add -> Mesh -> Add floor board mesh
  • adjust the number of planks and their length (in the modifier tab!)

  • select 'use floorplan' and select your floor plan mesh

What is left to automate is probably to make sure the floor board is position at the lower left corner of the floor plan because that is easy to forget. You can change the position of the generated floor board but then you have to tweak some attribute (like the number of planks for example) to make it calculate a new floor board, which is ugly.

For those who find a video easier to understand, here's a short screencast of the workflow:


Code availability


You can download version 0.0.15 form GitHub to try out this new functionality. If you already installed a previous version don't forget to remove the old version before installing the new one. (You can remove an old version by deleting the file planks.py from your Blender addons directory (on Windows typically in C:\Users\<your user name>\AppData\Roaming\Blender Foundation\Blender\2.71\scripts\addons )

Known issues

The sides of the planks are currently not properly uv mapped, something that may show when large gaps are used.

Previous articles on the floor board addon

The development and use of this addon is documented in several earlier articles:

Part I initial version
Part II random uv-coordinates
Part III random vertex colors
Part IV additional options
Part V randomization
Part VI small enhancements

It is also extensively discussed in this BlenderArtists thread.

EnumProperty callback problems - a better workaround

A frequent use case of EnumProperties in Blender addons is to display a dropdown with a choice of scene objects. Of course which objects are available in a scene is only known when invoking the addon so a fixed list of choices is of no use here. For this scenario a callback option is provided. The callback can be any function that returns a list of choices. Unfortunately there are a number of severe bugs associated with using a callback: if your python code doesn't keep a reference to the items in the list it returns, Blender may crash. This bug is documented and a workaround suggested but this doesn't solve the problem completely. Have a look at the code below:
import bpy
from bpy.props import EnumProperty

available_objects = []

def availableObjects(self, context):
 available_objects.clear()
 for ob in bpy.data.objects:
  name = ob.name
  available_objects.append((name, name, name))
 return available_objects
 
class TestCase(bpy.types.Operator):
 
 bl_idname = "object.testcase"
 bl_label = "TestCase"
 bl_options = {'REGISTER', 'UNDO'}

 objects = EnumProperty(name="Objects", items = availableObjects)
if we hover the mouse over the second or third option we see that the description shows garbage, i.e. the description part of another item!

The really annoying part is that even if we make a full copy of the object's name (with ob.name[:]) the problem isn't solved. So probably the internal callback code trashes memory even outside its own allocated memory.

def availableObjects(self, context):
 available_objects.clear()
 for ob in bpy.data.objects:
  name = ob.name[:] # a copy, not just a reference
  available_objects.append((name, name, name))
 return available_objects

A way around this is to let the callback just return a list that is filled with values outside the callback code, for example in the code thst is executed when the user clicks on the menu item that selects the addon:

available_objects = []

def availableObjectsInit(self, context):
 available_objects.clear()
 for ob in bpy.data.objects:
  name = ob.name[:] # a copy, not just a reference
  available_objects.append((name, name, name))
 return available_objects
 
class TestCase(bpy.types.Operator):

        ... stuff omitted ... 

 objects = EnumProperty(name="Objects",
                    items = lambda self,context: available_objects)

  
def menu_func(self, context):
 availableObjectsInit(self, context)
 self.layout.operator(TestCase.bl_idname, 
                             text="TestCase",icon='PLUGIN')

def register():
 bpy.utils.register_module(__name__)
 bpy.types.VIEW3D_MT_object.append(menu_func)
This is usable even if the addon changes the number of objects. The only downside is that the code isn't reentrant because in its present form does not guard thread access to the global variable but as far as I know the Blender UI runs as part of a single Python interpreter so there's only one thread, which renders this point moot. The other issue is that it looks ugly, but as long as it works that's a minor issue :-)

Note: you might wonder why we need the lambda here but that's because if we would point to just the list here, the list would be empty at the point where the EnumProperty was defined and apparently it makes a copy of that list so it would stay empty.

WeightLifter - My first BlenderMarket addon

I am quite proud to announce my first addon that's available on BlenderMarket!

The addon combines a lot functionality in a single comprehensive addon. There's a tutorial online as well, demoing the most eyecatching features and I hope it will be useful to not just ArchViz people!

Update: there is now an update available that fixes a crash that could happen when assiging random weights to groups of connected vertices in large meshes.

A hexagon shader in OSL, second edition

A while ago I made a simple OSL shader for hexagonal tilings. Prompted by some questions on BlenderArtists I decided to create a more versatile version that retained the color options but added the distance to the closest edge. That feature may help in creating crips edge patterns because the previously availble distance to the closest center creates rounded shapes that might be suitable for bee hives but not for hard edged stuff like floor tiles etc.

The noodle used to create the image is shown below (click to enlarge):

The color code has stayed the same except for the calculation of the distance to the edge. This might be a bit inefficient, but at least it's easy to read.

The additions are shown below, the full code is available on GitHub.

    // distance to nearest edge
    
    float x = mod(Coordinates[0]/3,1.0);
    float y = mod(Coordinates[1]/3,A2);
   
    #define N 18
    vector hc[N] = {
        vector(  0, -A2/3     ,0),
        vector(  0,     0     ,0),
        vector(  0,  A2/3     ,0),
        vector(  0,2*A2/3     ,0),
        vector(  0,  A2       ,0),
        vector(  0,4*A2/3     ,0),

        vector(0.5, -A2/3+A2/6,0),
        vector(0.5,     0+A2/6,0),
        vector(0.5,  A2/3+A2/6,0),
        vector(0.5,2*A2/3+A2/6,0),
        vector(0.5,  A2  +A2/6,0),
        vector(0.5,4*A2/3+A2/6,0),

        vector(1.0, -A2/3     ,0),
        vector(1.0,     0     ,0),
        vector(1.0,  A2/3     ,0),
        vector(1.0,2*A2/3     ,0),
        vector(1.0,  A2       ,0),
        vector(1.0,4*A2/3     ,0)
    };
    
    float d[N], t;
    
    for(int i=0; i < N; i++){
        float dx = x - hc[i][0];
        float dy = y - hc[i][1];
        d[i] = hypot(dx, dy); 
    }
    
    for(int j= N-1; j >= 0; j--){
        for(int i= 0; i < j; i++){
            if(d[i] > d[i+1]){ 
                SWAP(t, d[i], d[i+1]);
            }
        }
    }
    
    Center  = d[0];
    Edge    = d[1] - d[0];
    InEdge  = Edge < Width;
The approach we have taken is very simple: the hc enumerates all nearby hexagon centers. We then calculate all the distances to these points and sort them shortest to longest (yes with a bubble sort: with 18 elements it might just be faster to do it with a more efficient sorting algorithm at the cost of much more complex code so I don't bother).

The Edge is not realy the distance to the closest edge but the difference between the closest center and the next closest. Near the edge these values are more and more the same so Edge will approach zero. For convience we provide a comparison with some threshold also.

If you would like to know more about programming OSL you might be interested in my book "Open Shading Language for Blender". More on the availability of this book and a sample can be found on this page.

Inheritance and mixin classes vs. Blender operators

recently I was working on an addon that would offer functionality both in weight paint mode and in vertex paint mode. There were slight differences in functionality of course so I needed two operators but I wanted to keep most of the shared code in a single mixin class.

Sharing member functions was easy enough using a mixin class but for some reason for properties this didn't work. Any property I put in the mixin class was not accessible from the derived classes. What was happening here?

class mixin(bpy.types.Operator):
  foo = FloatProperty()
  def oink(self): pass

class operator1(mixin):
  def execute(self, context):
    self.oink()  # ok
    bar = self.foo  # error :-(

However, if I didn't derive the mixin class from bpy.types.Operator all was well ...
class mixin:
  foo = FloatProperty()
  def oink(self): pass

class operator1(bpy.types.Operator, mixin):
  def execute(self, context):
    self.oink()  # ok
    bar = self.foo  # ok too :-)

So what is happening here? Sure in the first scenario both the mixin and the derived class inherit from bpy.types.Operator but that shouldn't be a problem is it? after all, Python's inheritance model supports the diamond pattern.

The answer to this riddle is hidden in Blender's source code, quote:

/* the rules for using these base classes are not clear,
 * 'object' is of course not worth looking into and
 * existing subclasses of RNA would cause a lot more dictionary
 * looping then is needed (SomeOperator would scan Operator.__dict__)
 * which is harmless but not at all useful.
 *
 * So only scan base classes which are not subclasses if blender types.
 * This best fits having 'mix-in' classes for operators and render engines.
 */
So upon creating an instance of a class that is derived from bpy.types.Operator only the class itself and any base classes that are not derived from Blender types are searched for properties. This will reduce needless traversal of base classes that do not define properties themselves and avoid duplicate searches in cases where there is a diamond pattern but it sure is confusing.

It does make sense though: instantiation of operators should be as cheap as possible because instantion happens each time a screen area with the operator controls is redrawn! And this can add up: merely moving your mouse can result in tens of instantiations.

So the moral of this story? Sure it's awkward, especially while it's not well documented, but it is an understandable design choice. There is one serious drawback though; if you have the mixin and your operators in the same file you cannot use register_module() because that function tries to register all classes even the mixin class and that will fail.

conclusion

When using inheritance with bpy.types.Operator derived classes and you want to define properties in a mixin class make sure that:

  • the mixin class does not derive from bpy.types.Operator,
  • the final classes do derive from bpy.types.Operator (and from the mixin of course),
  • you don't use register_module() but use register_class()
  • for each operator separately (but do not register the mixin)