Skip to content

Archive

Category: Blender Scripting

This A-Z list is a work in progress; just started :)

Add a new material

scene.objects.active = myObject
bpy.ops.object.material_slot_add() # add a material slot to active object
material = bpy.data.materials.new(“gold”)
# assuming the object previously had no material slots, otherwise search for empty slot
myObject.materials[0] = silver

Create an object

foo = bpy.data.objects.new(name=”foo”, object_data = data)
scene.objects.link( foo)

Create a mesh

mesh = bpy.data.meshes.new(“mesh”)

Populate using from_pydata(vertices,edges,faces). For example:

verts = [ ( 0,0,0), (1,0,0), (1,1,0), (0,1,0) ] # a square
edges = [] # usually not needed, but, e.g. [ (0,1), (1,2), (2,3), (3,0) ]
faces = [ (0,1,2,3) ] # connecting the square corners; can use 3, 4 points or more!
mesh.from_pydata(verts, edges, faces)

Duplicate an object

Method 1: bpy.ops.object.duplicate()

  • bpy.ops.object.duplicate() – duplicate currently selected objects (deep copy)
  • bpy.ops.object.duplicate( linked = True ) – duplicate currently selected objects (shallow copy – mesh and other properties should be shared).

@see make an object the only active, selected object

Method 2: create a new object and duplicate properties

The disadvantage of this is that duplicating all properties can be hard.

@see create an object

Get the current scene

bpy.context.scene

Get the scale (‘unit’) of the current scene

scene.unit_settings.scale_length

Make an object the active, selected object

Assume an object named X

for k in bpy.data.objects:
    k.select = False
X.select = True
scene.objects.active =  X

Set an object’s location

object.location = (x ,y ,z )

This article is useful you want to get productive quickly with blender scripting. There are much better ways to integrate scripts. I feel *almost* embarrassed to post this. Initially, however, script integration may feel intimidating. 

You’ve been toying around with the python console and/or adding quick scripts as text nodes in blender files, you wish to reuse your scripts, but add-on creation feels intricate? Read on.

However, if you’ve created a great script that you’d like to share with the community, you need to create an add-on instead (checking existing add-ons in the blender scripts folder is the way to go).

Move your script to py files

The idea here is to bypass time consuming integration steps, while retaining basic flexibility:

  • Don’t create an add-on.
  • Don’t create a button oriented UI
  • Keep scripts in *.py files (not in a *.blend file)

So, let’s say we have a script under /Users/Dick/foo.py, how can we call this from blender? The (quick and dirty) solution is to create a text node in the blender file, and add the following code:

# import sys and foo modules; append our script dir to the python path
import sys, imp
sys.path.append(“/Users/Dick”)

# import our py file as a module; reload to make sure recent changes
# to the script are considered
import foo
imp.reload(foo)

# call a function in the script file
foo.myFunction()

Then, we can invoke our script by hitting ‘run script’ in the text window.

We don’t want to type these lines over and over again. So we can add them as part of the default startup file. Just do File > Save User Settings.

Keep in mind that this will overwrite the startup file with whatever’s in your workspace (so, adding the quick and dirty ‘script runner’ right after opening blender is a good idea).

Bones

For games, exporting bone transforms is often more efficient than exporting animation curves.

Most animation data is modeled using Actions; however, data related to the current pose (for an Object using an Armature) is exposed via Object :

x = D.objects['armature']

bone = x.pose.bones['root']

bone.matrix # transform
bone.location # just the location.

(‘D’ is a shortcut for bpy.data).

Actions

In Blender 2.63, retrieve actions using:

anAction = D.actions[name]

Action.fcurves contains animation data per channel. The grouping of fcurves (in the blender UI) is cosmetic.

  • FCurve.data_path refers the data being animated using a given animation curve. This could be something like ‘pose.bones["neck"].scale’. Several curves may use the same name (e.g. scale has 3 components so there may be 3 curves with the same data-path)
  • FCurve.keyframe_points refers keyframes for a given curve. The main property of a Keyframe is co, which includes the time offset co.x (the frame) and property value co.y
data_path does not fully identify which property of the object is being animated (e.g. for location, X, Y or Z?). for vector properties, it appears that FCurve.array_index identifies the component ( x <=> 0, y <=> 1, z <=> 2)

References (Blender API docs)

Blender allows associating markers to a given action. This is useful to add logic to animations, for example:
  • Label an ‘effect frame’ for a hit animation
  • Label a ‘takeoff frame’ for a jump
Markers can be added from the action editor in the dope sheet:
  • M to create a marker
  • CTRL+M to rename a marker
After creating markers select ‘Make markers local’ from the Marker menu in the dope sheet; otherwise markers are associated with the timeline instead of the current action.

Python

# get a reference to the 1st marker in action 0
m = bpy.data.actions[0].pose_markers[0]

m.name # marker name
m.frame # frame for this marker 

References

A quick, biased article looking at useful BGE (Blender Game Engine) parameters.
Note that this is out of date, targeting Blender 2.4x.

Works pretty much the same in 2.6x. 

Rigid bodies

Blender objects have several properties used to determine their dynamic behavior: rbFlags, rbMass, rbRadius, rbShapeBoundType.

rbFlags ( => API docs ) provides a bunch of properties, the most useful properties may be:

  • ACTOR (Actor)
    • DYNAMIC (Dynamic)
      • RIGIDBODY (Rigid Body)
      • COLLISION_RESPONSE (No sleeping)
    • GHOST (Ghost)
    • BOUNDS
For example, test for ACTOR flag:
if obj.rbFlags % Object.RBFlags.ACTOR > 0 :
  #do something…
According to docs flags down the hiearchy (as arranged above) require flags up the hiearchy (e.g. for ‘RIGIDBODY’ to have an effect in BGE, DYNAMIC and ACTOR should be enabled).
BOUNDS specifies the physical shape; this is enumerated by Object.RBShapes:
  • BOX = 0 (Box)
  • SPHERE = 1 (Sphere)
  • CYLINDER = 2 (Cylinder)
  • CONE = 3 (Cone)
  • POLYHEDERON = 4 (*) (Triangle mesh)
  • 5 (Convex Hull) (**)
(*) incorrect spelling as per enum value
(**) available in UI, but not enumerated

Decimators and LoD

The Decimator modifier can be useful to cut down face count; for example suppose you have an object ‘X’ with 5k triangles and you’d like to cut this down to 1k when generating a triangle mesh for the physics engine:

obj = Object.Get(“X”)
for mod in obj.modifiers:
  if mod.type is Modifier.Types.DECIMATE:
    if mod.name==’physics’
      mod[Modifier.Settings.REALTIME] = False # use ‘False’ to disable the decimator, ‘True’ to enable it.

When collapsing the modifier stack we temporarily enable ‘REALTIME’. We don’t see the cut down version while editing the scene, but can still export a simplified mesh.

Properties

Blender allows defining arbitrary properties per object; this can be handy in many situations.

list = obj.getAllProperties()
p = list[0] # then use p.name, p.data, p.type …

where type is one of:

  • BOOL (bool)
  • INT (int)
  • FLOAT (float)
  • STRING (string)
  • TIME (timer)

We use blender to create game assets; we also use blender as level editor. Blend files are exported to our proprietary format using py scripts.

Exporting files manually is okay… to a point. Soon we find out not only that exporting files manually is a chore, it contributes to creating a beautiful mess.

How to automate the conversion? With XCode, it can be done using build rules. I’m covering the following points:

  • Build integration – add files to your build, automatically translate them using utilities and include the products in your app bundle.
  • Defining useful build rules.
  • Invoking blender from the command line.
  • Modifying blender scripts so that they won’t crash in a windowless environment.
  • Signaling export errors (notably, errors generated by a script running inside blender) using XCode.

While we have a mixed workflow (Blender 2.49 / Blender 2.61), we’re dominantly using 2.49b, so I started with the older version. I’ll be covering 2.61… later.

I used the following articles as a starting point:

This article is not concise; I’ll summarize my findings in a coming article.

The experiment

The first step is to configure build rules to process *.blend files I guess, so in a first approximation I used this:

  • Source files with names matching *.blend
  • Custom Script: /Applications/blender/blender.app/Contents/MacOS/blender ${INPUT_FILE_PATH} (bad)
  • Output Files:
    ${TARGET_BUILD_DIR}/../../${INPUT_FILE_BASE}.scg (bad)
I just thought it would be interesting to try this way although it’s obviously not complete. And indeed, it was.
First surprise, Blender opens in a window. Good for testing (notably because it’s displaying errors already; for a nice smooth build I’ll want to disable this).
Both Blender & XCode are displaying messages in the XCode errors & warnings panel, which is nice.
The initial problem is path related. The file won’t open because spaces in the path are incorrectly interpreted. So the correct form to open the blend is like this:
  • /Applications/blender/blender.app/Contents/MacOS/blender “${INPUT_FILE_PATH}” (good)
Running the script is the next obvious step. For now blender just opens and idles happily until I quit. So I modify my command, like this:
  • /Applications/blender/blender.app/Contents/MacOS/blender -b “${INPUT_FILE_PATH}” -P qwagga.py (bad)

-b to tell blender to ‘render in background’. -P qwagga.py is the wishful step to run my script hoping that scripts are being run from the blender scripts folder. qwagga.py is my export script. There will be a problem with that but let’s try anyway.

Indeed, -b prevents the blender window from opening. Blender is reporting (via XCode) that qwagga.py wasn’t found. Interestingly it would appear that -P could also refer a script included inside the blend file (text node). For now, however, I’ll just provide the full path.

  • /Applications/blender/blender.app/Contents/MacOS/blender -b “${INPUT_FILE_PATH}” -P /Applications/blender/blender.app/Contents/MacOS/.blender/scripts/qwagga.py (good)

Yea this works. As you’d expect since the exporter is trying to pop a file selection panel the script crashes with a fairly explicit message:

File “/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/qwagga.py”, line 213, in <module>   Blender.Window.FileSelector(exportAssets,’Export to File’,PATH)
RuntimeError: the file/image selector is not available in background mode

This error can be patched easily:

    try:
            Blender.Window.FileSelector(exportAssets,’Export to File’,PATH)
    except RuntimeError:
            OUTPUT=Blender.sys.makename(ext=’.scg’)
    exportAssets(OUTPUT)

Telling XCode where the ouptut is located turned out to be a nag. The docs aren’t overly explicit about what environment variables can be used. As it turn out, however, whenever running a custom shell script (like, what we are doing now) the messages window displays a whole batch of setenv commands. That is all we need to know. I adjusted my entry in output files accordingly:

  • ${INPUT_FILE_DIR}/${INPUT_FILE_BASE}.scg

Immediately after I got this work, it seemed there was ‘a bit of weirdness’ in XCode (an error I couldn’t make sense of). For whatever reason this cleared after cleaning the build and re-saving my blend file.

It appears that each file is getting processed/converted whenever building (even if the input file hasn’t changed). I’m a bit worried about how this will turn when I have 200 blend files linked in this way – since blender loads almost instantly I’ll just wait and see.

Single input => multiple output

Now, the above looks quite useful but there are issues:

  • My py scripts don’t output just one file.
  • In fact I have two py scripts used in blender. One outputs a single file, the other outputs a whole lot of files. The names of the files match object names in blender
I would hope that both Blender and XCode can handle this situation gracefully.
For proof of concept, I just hacked a different output file path and created a file hierarchy looking like this :
  • blends
    • car_park.blend
    • build
      • car_park.blz
        • foo.rtf
        • bar.rtf
I added a ‘build’ folder under blends because we don’t want to have output files sprawling around. Then the question is to know whether car_park.blz will be exported along with all its content (for sake, foo.rtf, bar.rtf). The answer is YES.
Not perfect
Using this method I don’t know how to modify the location of the output in the resulting package. Before I would link a ‘blue folder’, so all my media 3D assets would go under [package]/3D/. Controlling the structure of this package is useful in various ways. 
We just demonstrated that we can link a whole folder given a single input file; this means we could input a config file describing which blend files we want to translate and how; then we’d run blender once , translate all the files and producing the correct output.
In the end I think this will turn out to be a better solution, notably because it will avoid translating the same files other and other even if they weren’t modified. Scene files process fast; not the case with files containing large meshes and animations.

For whatever reason, the next steps turned out to be troublesome.
My second py script was symlinked. I didn’t think it would matter (strictly speaking, still don’t think it does) but I found it hard to get the script to refresh (meaning, I would edit the py script and run the build again, find the same error as previously. And again. And again.

An error in the scene export script caused the wrong path to be used.

Passing several scripts on blender command line (-P foo.py -P bar.py) doesn’t work so I ended calling blender twice which is a lesser evil. Maybe.

Complications

  1. I have a mixed workflow using both Blender 2.4x and Blender 2.5x. In theory this means that I would have to go through the motions again, finding out how I can run 2.5x from the command line (likely as not, it won’t work in the same way).
  2. Scene files contain level edits and assets. Asset files do not contain level edits. Both blender 2.4x and 2.5x files are just annotated as *.blend. How do I know which version of blender to run and which scripts to call?

The answer to (1) will be simple for now. Don’t do that. I mainly use 2.4x; the only 2.5x file that really matters so far is the one containing the PC mesh and animations. So I’ll just pass and use the manual workflow for that.

The answer two question (2) will be equally simple. Use a convention. For starters:

  • level file: level.s.blend
  • asset file: asset.a.blend

( and likewise when I get 2.5x scripts working, different conventions may be used )

This is a bit lame. Maybe a better convention might be something like:

  • *2.4x/scenes*.blend
  • *2.5x/assets*.blend

Works – although the build rule does say something like “files with name matching”, the matching rule actually uses the path.

A nag here is that I don’t want to have 2 or 4 ‘build’ folders for my assets. Just one folder (that I can trash as a quick and dirty way to make sure no out of data lingers in the system) would be best. This should be straightforward, matching the output like so:

  • ${INPUT_FILE_DIR}/../../build/${INPUT_FILE_BASE}.blz

Conflating the output from various files (e.g. 2.4x/assets/foo.blend and 2.4x/scenes/foo.blend ) is possible. Collisions are unlikely, however, so I’ll keep it this way.

Polish?

Silencing the output?

When running blender directly from the desktop, getting console output to show up can be tricky. XCode surely doesn’t have this problem. All debug output appears in the messages window. Too much of it, in fact. Worse, something forces the item matching the translation script to expand.

No luck. I was assuming (maybe wrongly) that blender output is displayed because it is sent to stderr. Either way standing messages to stderr or stdout will yield the same result. Until further notice if I want to avoid script messages blotching the output, I need to disable debug output manually.

Displaying errors during the export process

An issue serious enough that putting it under ‘polish’ may be foolish : how to ensure that XCode will alert us when export errors occur? And by the way, what is an export error?

I tried my luck again, this time by looking at the unit test framework output. I thought XCode may be detecting a simple pattern to identify errors, and it is. The pattern is something like this:

  • error: description of error

The space after the colon in error : is required. In python (~2.7), use:

print (“error: something went wrong”)

And XCode will detect the error and display a flamboyant exclamation mark. Neat.

This won’t stop the build from completing but a red exclamation mark is difficult to ignore so it will be enough.

What is an error, then?

A py script failing while running inside blender does NOT cause an error to appear in XCode. This is because blender returns with exit code ‘OK’ regardless. Now that we know how to signal errors to XCode, we can insert validation related errors. But we also want to report an error when our script fails unexpectedly:

    try:
        exportAssets(PATH)
    except:
        print “error: in blender script: “, sys.exc_info()[0], “(see messages window)”
        raise

raise causes the error to propagate, allowing detailed information to appear in the log.

caveat: If the script contains a syntax error, it won’t run. In this case blender will report the error and exit, however we cannot alert XCode since the script didn’t even start running.

(how to cope with) limitations

Limitations with the approach I described derive from the atomicity of the conversion. It has to be done like this:

input file => output file or directory

For level edits, it is fine.

I see a problem when several files want to output to the same deployment directory. For example, it often makes sense to define actors as shared assets (same creatures used in different levels). Although it is a bit messy, it is often convenient to keep several actors in the same blend file. But then what we’ll end up doing is this:

  • myCreatures1 => targetFolderA
  • myCreatures2 => targetFolderA

This is bad in at least two ways:

  • We should cleanup targetFolderA before exporting (to avoid outdated files lingering in the build)
  • When exporting myCreatures2, we’ll end up copying over again data output by myCreatures1.
If we export to separate folders (myCreatures1Out/, myCreatures2Out/) the deployment structure becomes inconvenient. We may end up manually adding every output folder to the path used by a loader, and if we do so retrieving assets will take more time.
For shared assets, we have to choose. Either we start from a file listing all shared asset files and this becomes the input – processed by a special script – or we agree that each file will contain one actor / item. While the first solution is somewhat constraining it does help keeping things neat and requires less work.
So, do what?
Although not ideal, a solution is to modify the way the loader retrieves data blocks. I want to do this conservatively.
Before, a data block would be retrieved by creating a file name against the resource paths (e.g: rabbit => retrieve the mesh called rabbit.dbk)
After, a data block can also be retrieved by matching a file name against a path in a designated shared resource folder (this would have to be the bundle’s root I’m afraid) : rabbit => rabbit.blz/rabbit.dbk

Additionally, the name of the blend file for a shared resource should match the name of the data it contains.

Not quite. For now just a few links that you may find helpful.

Know the tricks

There are several essential tricks for Blender 2.6.1 (much of this works in 2.5x/2.49 or can inspire you). Presented as a list of tips, honestly it’s more of a survival kit if you’re serious about scripting Blender – read it or learn the hard, frustrating way.

And if you’re still an OS-X newbie (I am), learn how to run programs from the terminal.

What if I wanted to use a Python IDE with Blender?

The main problem I see here is that bpy and Blender may not be recognized by Python IDEs (I tried PyCharm). I think there might be a workaround but it looks heavy handed.

  • There is/was/used to be Stani’s Python editor. I think there is an old version on sourceforge. Maybe you can access his blog in which case you might get a later version (untested).
  • It may be possible to setup Eclipse in a useful way (see ‘Programming add-ons for 2.5′ below) (untested).
  • Wing IDE provides a solution that is somehow compatible with Blender (untested).

I want to set breakpoints

There is a community add-on for that (2.5x, untested)

Programming add-ons for 2.5…

Getting started with writing add ons is a little harder than with 2.49b. I wrote a little about this (search?). More notably, there is a free e-book in PDF format by Witold Jaworksi (haven’t read it yet, looks useful)

I just did a test using blender 2.49′s radiosity feature. I wanted to bake self illumination to vertex color.

However, this opens more questions than it solves.

Radiosity in 2.49 doesn’t support double sided faces. This seems to cause artifacts when baking clothes and hair (clothes don’t have thickness, and I doubt I would go this far – the model is heavy enough as it is).

Additionally, the rendering is not very clean with the original, mid poly model (~5k faces). I can increase the definition to render lighting (using radio buttons), but then I need to transfer the result back to the original model.

So the plan (assuming I persist) would be to modify the model, add thickness to clothes, bake illumination, then write a script that can transfer color data back to the original model.

I think it’s a bit over the top but radio bakes play an important part in our pipeline already, and I feel vertex paint, however old fashioned, offers distinctive possibilities. For example I already have a script that can extract dark areas from the radio bake, which gives access to ‘shadow geometry’ – so we can take this into account when programming gameplay.

I’m also working on a method to simplify geometry while losing as little color information as possible – ultimately this should help me improve rendering quality without losing much performance.

This is applicable to Blender 2.49. It’s hardly worth a post but I keep forgetting about it.

  • In your blender folder, select the blender application icon, right click and do ‘show package contents’
  • browse to content/MacOS/.blender
  • The nag is that this .blender file is hidden by default, you can use this tip or download a free utility to hide/show hidden files and folders.

A good idea is to make an alias after you found your scripts folder…

This post won’t give you all the information you need if you’re simply new to Blender Scripting. Many of us, however, continued scripting Blender 2.49 because 2.5 scripting wasn’t stable at the beginning. I’m quite sure this post can help you to migrate your scripts from 2.49 although it’s very hands on and I haven’t really tried to organize these useful bits.

  • Export script template (source code). This shows how to arrange metadata, invoke the file selector and write simple output to a file (to make sure something’s actually happening). Includes summary instructions to install the script.

I updated my exporter, Ox3ich, although not with all the features of the current 2.49 version. After trying it out a little I will make it available. In the meantime I list just a few of the many differences between the 2.49 / 2.59 APIs.

Writing I/O scripts for Blender 2.5 isn’t exactly what I’d like to do at the moment. I just have to. Scripting integration looks interesting, with a little more flexibility than in 2.4. Useful links…

As usual, looking at existing scripts will help. The documentation isn’t awesome.

Script Registration

  • The registration process has changed. The easy part is updating your metadata (just look at any of the scripts bundled with 2.5).
  • Scripts now require register/unregister methods. This allows tighter integration as far as I can see, notably it makes it easy/possible for a script to call another script.

Your script/add-on won’t automatically show in the designated menu, but it should appear under [file > user preferences > add-ons] where you can enable it. Then save user prefs (save as default option in the bottom left) to keep the script enabled next time. This page gives a little information about registering add-ons.

2.49 => 2.59 scripting : Miscellaneous changes

  • access current scene - bpy.context.scene
  • get object data (e.g mesh) – object.data
  • Blender.sys.join => os.path.join
  • Writing strings to output stream, see stack overflow answer (python 3.0)
  • mesh.verts => mesh.vertices
  • faces.verts => face.vertices - additionally, face.vertices is now an array of ints representing vertex indexing.
  • face.mat => face.material_index
  • mesh.getFromObject => object.to_mesh(bpy.context.scene,True,”PREVIEW”)
  • vertex.no => vertex.normal (but still uses vertex.co for ‘coord/coordinate’)
  • to change the current frame, use scene.frame_set(). Do not directly assign the frame number. Note that frame numbers start at 0, not 1.

There are changes from Python 2.x to Python 3.x in the way global variables are handled; this combines with a change in the way scripts are invoked, adding up to annoyances when trying a quick and dirty way to output debug info to a file…

Vertex colors

Vertex color data is now separate from face data, stored in Mesh.vertex_colors; additionally this now supports multiple layers, and colors are now in rgb float format (think it used to be rgba, byte format)

  • Iterate layers with something like for layer in mesh.vertex_colors
  • layer.active to find if a layer is active.
  • get layer data: layer.data
  • get vertex color for a face: layer.data[i], will contain corner colors for face at index i.
  • example 1: mesh.vertex_colors[0].data[1].color4[0]
    Red component for corner 4 in face 1, vcol layer 0 of mesh
  • example 2: mesh.vertex_colors[0].data[0].color1.r
  • Red component for corner 1, face 0, vcol layer 0 of mesh

Random links