Direct Object Duplication in Blender

Previously I wrote about Duplicating Blender Objects in Python in which I used built in operators to achieve the task. It turns out there is a more direct way to duplicate objects:


new_obj = src_obj.copy()
new_obj.data = src_obj.data.copy()
new_obj.name = "New Object"

 

I’ve had to use this method as I’m duplicating groups of objects in my script by iterating through the children list on the parent object e.g.


for src_child in src_obj.children:
    new_child = src_child.copy()
    new_child.data = src_child.data.copy()
    new_child.parent = new_obj

 

Leave a Comment

Scripting the Extendable Cube

Following on from my previous post, I now want to use the python interface to get the new size of my cube. Poking around in the API, I have found I can access the position of the ExtendableBit bone using:

bpy.data.armatures['Armature'].bones['ExtendableBit'].head
Vector((0.9948633909225464, 0.0, 0.0))

 

(possibly head_local is a better choice)

This position is the original untransformed position of the bone. I should also be able to access the transform that was applied when I posed the bone.

At this point it’s good to look at the Outliner panel and you’ll notice that Cube is parented to an Armature Object which has a datablock also called Armature. There is a distinction between bpy.data.armatures[‘Armature’] and bpy.data.objects[‘Armature’]. The important part is that the Armature object (as opposed to the Armature data block) has a member called ‘pose’ and this pose is made up of PoseBones which are named the same as the bones in the Armature data block. The PoseBones are where the actual transformations of the bones are stored so:

bpy.data.objects["Armature"].pose.bones['ExtendableBit'].location
Vector((5.0, 0.0, 0.0))

 

Cool, with this information I know the cube has been extended by 5 units in the X direction. Seeing as the original bone location was 1 unit, I know the length of the X side of the cuboid is 6 units which is the value I’ll insert into the database. Hooray!

Leave a Comment

Blender Bones – Extendable Cube

One of the issues I’ve been tackling in my Blender project is how to resize my models. We have a bunch of standard models that we are going to use but we can extend the length of them when they are installed so I need to be able to do this easily in Blender without having to edit the models each time. I also need to be able to access the length of the part from a python script to put into a database.

In this post, I’ll show you what I’ve learned about bones by demonstrating how to make a cube with an extendible side.

Edit the model and select some vertexes, adding them to a Vertex group named ‘ExtendableBit’

Add – Armature – Single Bone (do this in wireframe display mode because it will appear inside the cube)

Edit the Armature (you can make it bigger if you like) and duplicate the bone along the X axis. Name this second bone ‘ExtendableBit’ (the name must match)

Now in object mode, click on the cube then shift-click the armature and press CTRL-P for Make Parent (you could also press spacebar and search for make parent). Choose the ‘Armature Deform’ option.

You now have two changes. If you select and move the armature, the model moves with it. You could make your model out of multiple objects, parent them all to the armature and they would all stay together if you always use the armature to reposition and even rotate them all together.

Secondly, if you click ‘Pose Mode’ while the armature is selected, you can move the ‘ExtendableBit’ bone on it’s own and the cube will be deformed just at the bit you selected.

To limit how you model can be extended, you can use the transform locks.

In my next post, I’ll look at how to access the position of the bones from a script

Leave a Comment

Blender Using a Modal Popup in an Operator

A few days ago I wanted to make my custom Blender operator popup a little modal window and allow me to enter some values before running the script. I had given up on this because it seemed too hard. The preferred GUI workflow in Blender is to have operations run from the panels being triggered by callbacks from the poperties. For example, changing the Rotate property causes the rotation to be applied to the object and the object is redrawn. According to the API docs, there are no callbacks on custom properties so this approach was out of the question. Also, the act of inserting into a database is a once-off operation so is different to most Blender functions.

For once off operations, Blender uses a button in a panel which will kick off an operator. But what if I want to just be able to kit a key combo and make my operator run? I’m going to be running the operation a lot during a certain workflow and maybe I don’t want to be switching back to a panel all the time, changing the input params and clicking an operator.

Apparently other users have had this need too which is probably why the Blender developers recently added a invoke_props_dialog method. It allows you to popup a little dialog box to adjust some values which you can access from your executing script.

Here’s how it works:

First you need to setup the inputs to your operator that you want to appear on the popup.


class MyNewObjectOperator(bpy.types.Operator):
    bl_idname = "my_new_object"
    bl_label = "Create My Object"
   
    my_new_prop = bpy.props.StringProperty(
            name="My Prop Display Name",
            description = "This description comes up in the tooltip",
            default="blah")

 

Next you need to override the invoke method and call invoke_props_dialog. This method will create a modal dialog using the properties it finds in the operator passed via the ‘self’ param.


    def invoke(self, context, event):
      context.window_manager.invoke_props_dialog(self, width=500)
      return {'RUNNING_MODAL'} 

 

When the ‘Ok’ button is pressed, the ‘execute’ method will be called which you should also override. The property values entered in the modal dialog can be accessed via self.properties.my_new_prop


    def execute(self, context):
        my_new_prop_value = self.properties.my_new_prop
        self.report( "INFO", "I got value: " + str(my_new_prop_value))
        return {'FINISHED'}

 

Leave a Comment

Using a Custom Python Module With Blender

I’ve reached the stage in my blender project that I need to interface blender with a bunch of pre-existing libraries that we have which are written in C++. This is a better way to work with our system than directly interfacing to the database as our C++ libraries provide a common API with other systems that are using the same database. I am also eventually going to be doing more advanced things with the blender model such as interacting with our simulator system so it’s worth knowing how to do this now.

Fortunately, python provides a way to make bindings to a C/C++ library. Also, blender is happy to import any python module that is compiled against the same version of python that blender has built-in. In my case this is blender 3.1.2 and I’ve already tested this using the py-postgresql module (see previous posts: Blender Project and Connecting to a Database From Blender)

Python has this helpful documentation to get you started on writing a C/C++ module. I followed these instructions and had a python module working without any trouble once I managed to link in all the dependant libraries and set the include paths. I tested this by trying out the module from the python3 console on the linux command line.

As predicted, running from blender was seamless building on the work I’d done previously to get the sys.path right. I imported my module in my blender script and ran my module function with no problems.

Leave a Comment

Duplicating Blender Objects in Python

The aim of this next exercise is to have a bunch of prepared blender objects which I can use as building blocks for my overall model.

In order to differentate my base objects from other in the doc, I’ll use a naming convention of prepending the string ‘My_’ e.g. My_Car, My_Button, My_Cloth. I have a scene panel called My New Objects with some parameters for object creation: my_model, my_name, my_external_db_key. I’ve already worked out how to edit these in a panel and have a button called ‘Create New My Object’ that launches an operator with the scene as the context. The operator reads the scene custom properties.

The my_model property will have a value like ‘Car’, ‘Button’, or ‘Cloth’. I can now write some code to locate an object called “My_” + my_model and duplicate it.

The relevant process seems to be


      select_layers = [False] * 20
      select_layers[4] = True
      bpy.context.scene.layers = select_layers
      src_name = "My_" + obj_model
      found_model = False
      for src_obj in bpy.data.objects:
        if src_obj.name == src_name:
          bpy.ops.object.select_all(action='DESELECT')
          bpy.ops.object.select_name(name=src_name)
          bpy.ops.object.duplicate_move()
          new_obj = bpy.context.scene.objects.active
          new_obj.name = obj_name
          select_layers = [False] * 20
          select_layers[0] = True
          new_obj.layers = select_layers
          bpy.context.scene.layers = select_layers
          found_model = True
          break

 

Notice that I’m also mucking about with layers here. My reference object is in layer 4 so first I change the scene there to find it. Then once I’ve duplicated it and renamed it, I move it to layer 0 and switch the scene view back to layer 0 (I probably should save the original context.scene.layers and restored it at the end of the script)

Anyway, now I can work on adding some more properties to the object that I can set and also calling into an external library to setup extra bits in our database.

Comments (1)

Blender Operator With Input Parameters

Carrying on with my Blender project (which you can find by looking at the blender tag) I was up to the point of needing to supply user entered parameters to the operator so I could generate some rows in my database.

A good resource is the scripts/op directory in the blender distro which has many examples of operators in blender. What I found here was that while it’s possible to run a modal popup window from an operator, it’s not the done thing. Operators typically use default values and properties that have been set via a panel.

Looking at my workflow, I came up with the following steps:

  1. import base drawing on which to build the model
  2. construct the 3D model
  3. Set parameters of model in external database


For the initial creation of a model, I’ll need a panel in the scene which lets me set which of my custom objects will be created (the range of various models will change from project to project so it would be nice if I could load them from a file and configure them from a database). So I’ll type the name of the type of object I want to create and the name / label / MyID of the object and trigger the ‘createMyObject’ operator which will:
  1. load the blender object from a file
  2. call into my external python library to create some initial records for the object in the database
  3. query the database to load the properties that were created in the previous step and create properties for them on the object


I can then move the new object around and change it’s various properties. When I’m done, I’ll run another operation updateMyObject which will update the values in the database from the properties of the object. I suppose I’ll also need a refreshMyObject that will load the values from the DB into the properties of the object. I would do all this with callbacks but the blender docs tell me I can’t get callbacks on custom properties yet.

So going back to the drawing board, I need a scene panel to set the initial values for making a new MyObject. After mucking about for a bit, I found the chickenblender.com / Blender Python Tutorals site. I ended up using the City Destroyer example almost verbatim as a framework for my MyObjectCreator panel and operator.

Leave a Comment

Blender Custom Operator

I’m working on a project to link a blender model with a database. In the first step, I was able to make blender load and display some values from the database based on the name of the selected blender object. The next step is to be able to make blender generate some database records from the blender model. As far as I can tell, the best way to do this is using a custom operator. The operator is executed by selecting an object and pressing the spacebar which brings up a list of operators which I can run.

From the API examples, I put together a little bit of code:

class my_generate_resource(bpy.types.Operator):
    bl_idname = "object.my_generate_resource"
    bl_label = "Generate Resource"
 
    def execute(self, context):
        obj = context.object
        self.report({'WARNING'}, "Generating resource " + obj.name)
        # here I need to do something
        return {'FINISHED'}

 

But how do I make this operator ask me for values that I want to use when generating the database records? I have access to the object name but I also want to type in a value to set in the database.

Maybe I could setup these values in my custom properties panel but then I run into another problem: it seems you can’t create custom properties from a panel, although you can bind a text entry field to an existing custom property. So I’m assuming I can do it from an operator:


class my_test(bpy.types.Operator):
    bl_idname = "object.my_test"
    bl_label = "My test"
 
    def execute(self, context):
        obj = context.object
        obj["my_prop"] = 42
        return {'FINISHED'}

 

I can test if this works by adding a check to my custom panel:

if "my_prop" in obj:
    row = layout.row()
    row.label(text="my_prop: "+str(obj["my_prop"]))

 

The answer is yes: I can create custom properties on my objects from a Operator but not from a Panel (at least not in the draw method). There must be a way I can get a pop-up form from my Operator to type in params.

Leave a Comment

Connecting to a Database from Blender

Continuing on from yesterdays exercise in getting Blender to see a python module on my system, I’m now able to connect to a database from within Blender using the py-postgresql module.

# using DB API 2.0
import postgresql.driver.dbapi20
db =  postgresql.driver.dbapi20.connect(user='blah',
                                password='blahblah',
                                database='blah',
                                host='yada.blah')
cursor = db.cursor()
cursor.execute('select * from foo where bar = \'' + obj.name + '\'')
cursor.fetchall()
 

I also tried using the py-postgresql specific interface which worked just as well and has a few more options:
import postgresql.driver as pg_driver
db =  pg_driver.connect(user='blah',
                                password='blahblah',
                                database='blah',
                                host='yada.blah',
                                port=5432)
ps = db.prepare('select * from foo where bar = \'' + obj.name + '\'')
ps()
 

I could then use the values extracted from the database in my custom panel which updates depending on which object is selected.

Leave a Comment

Blender Project

I’m sharing a few notes here on some work I’m doing with Blender. The task is to model some physical objects that we control in Blender and then autogenerate a lot of information that we can use to make a simulator for testing our controller, the data used by the controller and the scada monitoring system.

Yesterday I downloaded the beta version of Blender as it has a revised GUI and python API which I think will make my life much easier. Using the example in the API Intro I was able to quickly make a custom panel that displays the name of the currently selected object.

The next cab off the rank is to connect to our configuration database and pull out any records that we have configured for our blender model. Specifically we want to assign a class to this model which describes how it is controlled and that in turn will enable us to pull up a list of configuration variables.

To do this I started by installing the python-pygresql package for ubuntu and reading a tutorial on Linux Journal. The first derailment was almost immediate:

import pgdb
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
ImportError: No module named pgdb
 

After a few googles I was led to understand that blender has a bundled version of python with limited built in modules. To use the full power of python I had to install the version that python was bundled with natively on my system and then compile in any modules I wanted for that version. Looking at the console for blender, it gave the version as 3.1.2.

I managed to find a python3 package in ubuntu’s synaptic package manager and installed that but this made no difference so I ended up leaving a message on the blender forums which is where I’m leaving things for today.

UPDATE: The solution to the hurdle of not being able to load the pgdb module from blender is documented on the linked forum post but here is the summary:


1) The pgdb module is python 2.6 only
2) I had to compile an alternative module py-postgresql from source as there are no .deb packages that work with python3
3) py-postgresql installed ok but the install script left the read permissions as root-only. Python reported that the module didn’t exist which I guess is a generic way of saying it couldn’t read the module library files.

I also misunderstood the way blender interacts with the system python version. It seems to always run the bundled version of python but you can add the search paths using PYTHONPATH so that it will load external modules you have installed yourself. As long as the python versions are close, the modules will load ok.

Once I had py-postgresql installed correctly, I was able to set PYTHONPATH to include /usr/local/lib/python3.1/dist-packages/ and import py-postgresql and connect to my database from there.

Comments (1)