This means serious discounts on participating products and of course my add-ons are on sale too!
Check out BlenderMarket to see if that special product on your wish list now has an 'on sale' label.
A bit overdue perhaps, but I have just made a version of Ortho available that is tested against Blender 2.93 LTS.
Ortho offers a collection of tools that allows you to move, rotate, scale, snap and align selections of a mesh relative to a user-defined reference plane. Working relative to a reference plane can greatly simplify the positioning of mesh parts and can help clean up distorted meshes. Blender already offers several tools to transform and snap mesh parts but they work in the context of predefined coordinates, which makes it difficult to position or align mesh parts in meshes that are transformed with respect to their local coordinates or in situations where orthogonal coordinates are not sufficient, for example when positioning a window inside a slanted roof.
Ortho offers a simple and interactive way to define a plane that fits a selection of vertices in a mesh and offers a set of tools that operate with respect to this reference plane. You can for example align and snap a selection to the reference plane or move this selection along its normal or its surface. Scaling is also an option, offering ways to rectify slightly distorted meshes even in situations where such a distorted plane is not aligned with any axis and scaling along individual normals with Alt-S gives strange results.
It might not be immediately obvious how to make Blender to show units along with the properties you define in your add-ons, but fortunately it is not all that difficult.
There are two aspects to the display of units, representation and definition.
This determines how property values are displayed and is something that is is controlled by the end user.
It is configured in the Scene properties, specifically in the Units panel.
The main choice here is between Metric and Imperial, but you can also choose specific units for certain quantities, for example, you might prefer Celsius instead of Kelvin.
The Unit Scale property is convenient if you are working to scale. I work with model trains in the H0 scale and sometimes make visualizations in Blender. Then I set the unit scale to 87 (because H0 is 1:87 scale) and then building dimensions etc. will show up with their real world dimensions.
This determines what kind of quantity we are talking about.
This is something you configure in you property definitions. For a FloatProperty for example, you have subtype and unit parameters. If you leave unit at NONE, Blender will not show any units!
Let's say you want to define add a property called floorarea to your add-on, you might want to configure it like this:
floorarea = FloatProperty( name='Floor area', subtype='DISTANCE', unit='AREA')
So the subtype defines what quantity we're dealing with, and DISTANCE is used for anything that can be expressed as a length (or in the case of an area, length squared). Some other options for subtype are ANGLE and TIME.
The subtype determines the widget that is used too, which is especially important for properties that are lists of things, like a FloatVectorProperty, that shows a color picker when the subtype is COLOR and other widgets when the subtype is for example a DIRECTION.
Each type of property has its own set of possible subtypes and units.
The unit parameter defines the actual unit to use. For example, for a DISTANCE subtype you could use LENGTH, AREA or VOLUME. For an AREA the value of the property would be displayed as m² or ft², depending on the Unit System selected in the Scene properties.
The release of 30 September 2021 adds new functionality to creating snap-points as well as using snap-points. (For an introduction to Snap! see this article).
You can now position snap-points on selected vertices in Bezier curves and Lattice objects in the same way you can do this for Mesh objects. You could already define snap-points on any object but this makes it way easier to position snap-points accurately. In Bezier curves you can also use the positions of the handles, not just the control points themselves. Curves that are not Bezier curves are currently not supported (although you can position snap-point manually just like with any object).
New operators have been added that copy and object before starting interactive snapping. You can choose to create a full or a linked duplicate and these operators are available in the Snap! Pie menu as well. If you add these operator to your quick menu (or add the Snap! Pie menu) you speed up your workflow in the common scenario where you have appended an asset collection and want to snap multiple copies of those assets.
The new Copy snap points operator will copy the Snap! configuration of the active object to any other selected object. This is convenient for example if you want to create multiple variants of an asset with the same snap-points.
Colorful labels for snap-points can enhance the aesthetics of an asset collection with snap-points, but the colors might clash with the theme chosen by the end-user, making it perhaps difficult to read. Therefore the end-user can now override those colors in the preferences because I consider colors (as well as font-size etc.) an accessibility issue that should be under the control of the end-user.
Snap! is a time saving tool for people who often work with modular assets packs or creators of asset packs who want to make there product easier to use.
Snap! allows you to define snap-points with a predefined location and orientation on objects which can then be used to interactively snap objects together without the hassle of precise positioning.
Snap! is available in a personal and a redistributable version on my BlenderMarket shop.
This new video shows how you an approach to creating curve based assets with snap-points that allow for easy snapping while deforming an object at the same time.
Snap! allows you to define snap-points with a predefined location and orientation on objects which can then be used to interactively snap objects together without the hassle of precise positioning.
Snap! is available in a personal and a redistributable version on my BlenderMarket shop.
In a previous article I introduced a new add-on called Snap!
Snap! is a time saving tool for people who often work with modular assets packs or creators of asset packs who want to make there product easier to use.
Snap! allows you to define snap-points with a predefined location and orientation on objects which can then be used to interactively snap objects together without the hassle of precise positioning.
Snap! is available in a personal and a redistributable version on my BlenderMarket shop.
It is not every day I can announce a new add-on but today I published Snap! on BlenderMarket.
Snap! is a time saving tool for people who often work with modular assets packs or creators of asset packs who want to make there product easier to use.
Snap! allows you to define snap-points with a predefined location and orientation on objects which can then be used to interactively snap objects together without the hassle of precise positioning.
It is available in a personal and a redistributable version on my BlenderMarket shop.
Say you are developing Blender add-ons and you need some additional packages, perhaps to to some line profiling use the line_profiler package.
You could keep a separate Python installation outside your Blender environment (like I mentioned in this old article ) but then versions needed to be the same and you needed to tweak the import path to be able use those packages.
An easier approach is to install the necessary packages in your actual Blender Python installation, but if you use pip
from the command line it will install inside you regular python environment because pip
is a python script that installs in whatever Python installation it is part of.
Fortunately it is rather straight forward to bootstrap your Blender Python environment to get its own pip
and then use it to install whatever you want.
In the examples below, /blender refers to your Blender installation directory. This could be something like /home/michel/Downloads/blender-2.93.0-stable+blender-v293-release.84da05a8b806-linux.x86_64-release
First we install the pip module
/blender/2.93/python/bin/python3.9 -m ensurepipAfter installing it, we verify whether it works
/blender/2.93/python/bin/python3.9 -m pip --version pip 20.2.3 from /blender/2.93/python/lib/python3.9/site-packages/pip (python 3.9)Now we can immediately use it to install packages inside the Blender Python installation, for example the
line_profiler
package
/blender/2.93/python/bin/python3.9 -m pip install line_profiler Collecting line_profiler ... [a boatload of dependencies gets downloaded as well] ...You will most likely get a warning
WARNING: You are using pip version 20.2.3; however, version 21.1.2 is available.which is ok. You can upgrade the pip module if you like (with
/blender/2.93/python/bin/python3.9 -m pip install --upgrade pip
) but the version you got with ensurepip
works fine, as demonstrated, so there is no immediate need. You can verify that the package is installed
ls /blender/2.93/python/lib/python3.9/site-packages/line_profilerNow you can use this package in your add-ons without the need to change
sys.path
from line_profiler import LineProfiler profile = LineProfiler() @profile def fie(): ... expensive code happening here ...And then somewhere else in your code
profile.dump_stats("/tmp/test.prof")Inspecting the profile can then be done with
/blender/2.93/python/bin/python3.9 -m line_profiler /tmp/test.prof
You cannot profile Python code that you code inside text blocks in Blender. Or rather you can profile them alright but you can not inspect the stats in any meaningful way because the file name of the code that is logged makes no sense (if your .blend is called MyBlend
and you have a text block test.py
, the file will be called .../MyBlend.blend/test.py
which is a file that does not exist and even if you save your text block this is an issue because MyBlend.blend
is not a directory you can save to. I do not have a workaround for this (except for hacking the .prof file) but in practice this is probably not much of an issue.
Do not forget to remove the profiling changes (and the import) if you want to distribute your add-on, because your customer will probably not have the line_profiler package installed.
(refer to the original article for a bit more detail. Note that there is no longer the need to use my tweaked version, if you use pip as described earlier you have all you need)
The last couple of weeks I have been porting almost a hundred add-ons, scripts and snippets to Blender 2.9x and you would think that to be a lot of work. This proved to be not the case though, because the changes between 2.8x and 2.9x are actually fairly minimal and even scripts dating back all the way to 2.78 were fairly straightfoward to port.
This doesn't mean there were no changes but the fundamental concepts in the Blender python API, like data access and the way operators and panels work stayed the same. What changed were mainly additions (new operators, other new classes like all kinds of nodes), minor changes (optional arguments must now be passed using the keyword) and renaming (groups became collections, lamps became lights).
There were some exceptions though that had more impact, for example, the decision to require annotations for properties and force a naming convention onto classes that need to be registered (like Panel and Menu derived classes) force you to check every add-on because although not mandatory yet, it will be in the future.
Another change that required a bit of work was that the helper function to register all classes in a module has been removed. As we will see in the examples, an alternative is provided.
The biggest change has been in the OpenGL bindings, but although this has a lot of impact, only a minority of add-ons deal with OpenGL drawing.
Anyway, in the list of examples below, I have highlighted the changes, sorted roughly based on how many scripts it has affected (I think).
bl_info["blender"]
is no longer just a minimum but must list a version that is at least 2, 80, 0. Otherwise your add-on simply won't run, even if it were compatible.
bl_info = { "name": "Some Operator", "author": "Me, myself and I", "version": (1, 2, 3), "blender": (2, 78, 0), "location": "View3D > Object > Some Op", "description": "An operator doing someting", "category": "Special stuff"}new:
bl_info = { "name": "Some Operator", "author": "Me, myself and I", "version": (1, 2, 4), "blender": (2, 92, 0), "location": "View3D > Object > Some Op", "description": "An operator doing someting", "category": "Special stuff"}
The way classes that need to be registered are dealt with has changed. Instead of registering everything in a module we need to register individual classes.
from bpy.utils import register_module, unregister_module def register() register_module(__name__) def unregister() unregister_module(__name__)
There is now a factory fumction for this(docs)
from bpy.utils import register_classes_factory classes = [Myoperator, VIEW3D_PT_mypanel] register_classes, unregister_classes = register_classes_factory(classes) def register(): register_classes() def unregister(): unregister_classes()
I never understood the benefits of this change but it affects almost every add–on
Old:
class Myoperator(bpy.types.Operator): bl_idname = 'mesh.myoperator' bl_label = 'Do something' bl_options = {'REGISTER', 'UNDO'} someprop = IntProperty(name="Some prop")
New: Note that the only visible difference is that we now use a colon (:)
class Myoperator(bpy.types.Operator): bl_idname = 'mesh.myoperator' bl_label = 'Do something' bl_options = {'REGISTER', 'UNDO'} someprop : IntProperty(name="Some prop")
This wasn't the case earlier, but it is as simple as adding it to your list of classes
class MyAddonPrefs(bpy.types.AddonPreferences): bl_idname = __name__ # give settings the name of the python module somepref : IntProperty(name="Some pref") def draw(self, context): layout = self.layout layout.prop(self, "somepref") classes = [Myoperator, MyAddonPrefs] register_classes, unregister_classes = register_classes_factory(classes)
The visible bit of moving to a newer python version is mainly the use of the @ operator instead of *
mat = ob.matrix_world.inverted() for vert in ob_verts: world_coordinates = mat * vert.co
mat = ob.matrix_world.inverted() for vert in ob_verts: world_coordinates = mat @ vert.co
This is also applies to multiplying two vectors: * is now element-wise multiplication, @ gives the dot product (this is in line with Numpy)
Of course you get all the added benefits from Python 3.7 as well although most are not relevant for add-on development per se.
Not only have the icons been redesigned, many new ones are available and quite a few are removed. The list of change sis to big to list here but if you want an overview of the changes since 2.78 I have made a page
Lamp
has become Light
and Group
has become Collection
. Collections offer a lot more functionality too of course but at its simplest level a collection is just a group.
Functions that have optional parameters not must use a keyword. Some notable examples
setting text in an area header,
for example when displaying the status of a modal operator
(docs)
context.area.header_text_set(text="something") context.area.header_text_set(text=None)
And the label()
function in a layout (docs),
which is used often in panels and operator draw functions.
layout.label(text="something")
Talking about layout, a minor change is that the percentage
argument renamed to factor
(docs)
layout,split(factor=0.40)
See here
x,y,z = context.scene.cursor.location
But the Color()
constructor always expects 3 values (docs)
Which means you cannot assign a Color object to a .color attribute in a vertex color layer.
The ray_cast() function for example
so instead of
scene.ray_cast(origin, direction )
scene.ray_cast(context.window.view_layer.depsgraph, origin, direction )
The mathutils.bvhtree.BVHTree.FromObject function also needs it.
Still accessible through the context
but now as ,code>context.preferences instead of context.user_preferences
Note that this breaks stored preferences as well since they might contain references to this attribute in the set itself (preferences are stored as executable python)
scene.objects.active
is no longer available, use context.active_object
(docs)
To set an object as the active object you need to do something different as well
context.view_layer.objects.active = myobj
instead of
ob.select = True
ob.select_set(True)
More here
There is a select_get()
as well.
This is consistent with selection functions in BMeshes for verts, edges, etc. (docs)
For example the Object and Mesh menus were part of the Infobar but are now part of the 3d view area.
So, for example INFO_MT_mesh_add menu
is now called VIEW3D_MT_mesh_add
The info bar is no longer present by default, the part at the very top (with File, Edit, Render, ...) is now called the TOPBAR
Notably the way to perform uv subdivision as well see more here
mod.use_subsurf_uv = True
is no longer needed.
bgl
does no longer support direct mode at all (not even as an option).
Which means everything has to be done replaced by shaders. more here
I am pleased to announce that I just released an updated version of my Blender Add-on Cookbook
This new edition has been updated and tested on Blender 2.92 & 2.93 (beta at the time of writing).
It does not contain any drastically new things, but it has been revised to take into account all the small things that have changed in the Blender Python API since version 2.78, most screenshots have been updated to reflect the 2.9x interface, all links have been verified/updated, and the updated code has been placed in its own Github repository.
The Blender Add-on Cookbook - 2.93 Edition is available on Blender Market.
A long time ago I created a progress indicator that blended nicely with the info header. However, as someone pointed out, we nowadays have the view3d header at the top of the screen and the python API has also changed a bit. So, time for an update :-)
In the end, I didn't have to change all that much. The main difference is that we now replace the draw()
method of the VIEW3D_HT_tool_header
instead of the INFO_HT_header
and in the update()
function we now make sure we tag all VIEW3D
areas for redraw instead of the INFO
areas.
Some minor changes were needed too, but this affected mainly the test operators: wm.event_timer_add()
now has mandatory keyword for optional arguments and of course the way we register operators has changed.
The updated code is available from GitHub.
I am pleased to announce that I just released an updated version of Creating add-ons for Blender.
This new edition has been updated and tested on Blender 2.93 (beta at the time of writing) and will work on 2.92 too.
I does not contain any drastically new things compared to the previous edition, but it has been revised to take into account all the small things that have changed in the Blender Python API that would block a beginner.
Creating add-ons for Blender is available on Blendermarket.
The book is provided in .epub, .mobi and .pdf versions. The .epub will be readable on most devices, and the .mobi on newer Kindles but the .pdf is probably looks best.
WeightLifter has been been updated for 2.9x compatibility. It has been tested on Blender 2.92 and 2.93 beta and only minor modifications were needed to make it compatible. If you still encounter a bug , please let know so that I can have a look at it.
WeightLifter is available on BlenderMarket. This update is free for customers who bought previous versions of WeightLifter.
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.
The code in the add-on is very old (7 years, which in Internet terms is ancient) and it does show its age in the way it is structured and also, as I experience myself, it is not very fast, especially on large meshes.
I am tempted to modernize it and improve its speed if possible, but this might also be an opportunity to add features. So if you have an idea or suggestion, please drop me a note in the contact box at the top right of the page and I'll be happy to consider it.