Archive for March, 2011

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