Книга: Mastering Blender
Назад: Part IV: Blender-Python
Дальше: Part V: Mastering the Blender Game Engine

Chapter 13

Python Scripting for Blender

In this chapter, you’ll begin writing Python scripts for Blender. This requires becoming familiar with Blender’s Python coding environment and the Blender-Python API. This chapter teaches you how to place objects in Blender’s 3D space and manipulate their associated values in your script. You’ll also learn how the Blender-Python interface construction tools work, which will enable you to create interactive scripts and tools. The goal is to show you not only how to accomplish the specific tasks in this chapter’s tutorials but also how to mine the sometimes-daunting API specifications for the information you need to accomplish your own goals.

In this chapter, you will learn to

Editing and Running Scripts in Blender

With the recode of Blender’s interface and API prior to Blender 2.5, the Python API became more tightly integrated with Blender’s internal data structuring system. This meant that more of Blender’s core C/C++ functionality could be accessed and controlled by means of Blender scripts. Indeed, although you may not see it at first blush, a lot of what you are doing already uses Python as glue to connect the interface to the underlying functionality. Don’t believe me? Try going into your Blender application directory and deleting the scripts directory (be sure to back it up first). When you run Blender after doing that, you’ll see it start up as normal, and then you’ll see the default screen look something like . It looks familiar, but it’s certainly not the Blender you’ve come to know and love! As you can see, much of Blender’s interface is already written in the form of Python scripts. That’s why Python lets you create your own custom controls that integrate perfectly into the Blender interface. It’s also why once you know what you’re doing with Python, you’ll be able to root around the scripts directory yourself and customize just about anything.

Now that you’ve looked at the basics of the Python programming language, you’re ready to begin working with the Blender-Python API and create scripts that access your Blender 3D and workspace data.

What Blender would be without Python

c13f001.tif

The Blender-Python API is made up of three sets of modules. These are application modules, stand-alone modules, and game engine modules. Application modules are the core of the Blender-Python API. They enable you to access data related to the 3D scene content, the Blender interface, animation and driver data, and Blender-specific operations and properties. The stand-alone modules contain more general-purpose classes such as math utilities and other useful tools and interfaces that are not part of Blender’s core functionality. Finally, the game engine modules contain the API for real-time scripting within the Blender Game Engine (BGE), which you will read more about in Chapter 16, “Python Power in the Blender Game Engine.” In the past, the Blender-Python API and the Game Engine API have been completely distinct, and that remains true. When in the BGE play mode, scripts do not have access to all the data that the standard Blender-Python API has access to. This is because the game engine modules are designed for the purpose of writing game logic, whereas the application modules are designed for writing custom tools for working with 3D content.

This chapter deals primarily with the application modules. The application modules share the common prefix bpy. These modules include the following:

bpy.context Provides access to data specific to the current state of Blender. For example, the currently selected object can be accessed through this module. Information about posed bones is accessed through bpy.context.
bpy.data Provides access to datablocks in the current blend file, independent of the context. For example, information about bones independent of posing (such as the information you would access in Edit mode) is accessible through bpy.data.
bpy.ops Provides access to operators. These enable Python scripts to carry out the same kinds of operations that you would carry out as a user of Blender. There are operators available for every possible context and window type.
bpy.types Provides access to miscellaneous useful classes that are not represented as datablocks in Blender. These include window and interface elements.
bpy.utils Provides access to Blender utilities that don’t deal with Blender internal data. Many of these utilities deal with managing external data paths.
bpy.path Provides access to utilities for parsing and processing the paths themselves.
bpy.app Provides access to application data that remains unchanged during runtime. Debug settings, C compiler flags, the location of the Blender executable on your computer, and similar information are accessible through bpy.app.
bpy.props Provides access to the properties system. This makes it possible to extend Blender’s internal data using properties. The properties system has built-in tools for creating graphical user interface access to property values.

The application modules and the most commonly used stand-alone modules are imported automatically in the Blender Python interactive command-line console. Other stand-alone modules can be imported in the interactive console using the import command. The BGE modules are not available for import in the interactive console environment, further underscoring the distinction between how those modules are used. In Blender Python scripts, modules must be imported using the import command, as you’ll see throughout this chapter.

The complete API specifications (all 1,397 pages as of this writing) are available in PDF format for download as well as online at .

Calling Functions from the Command Line

Blender’s interactive console is a great tool for quickly checking on API information. To work with this, open a Python Console in your Blender work area. Be sure to keep your 3D viewport open also.

Exploring with the Autocomplete Function

The autocomplete function (Ctrl+spacebar) is a handy way to look up methods available to a given module or object. For example, to explore the operators available in bpy.ops, type bpy.ops. into the command line like this

>>> bpy.ops.

followed by Ctrl+spacebar to activate autocompletion. You’ll see a list of possible continuations, representing classes of operators.

Let’s say you wanted to add a mesh primitive to the scene. Adding mesh primitives to a scene is one of the low-level operators available to bpy.ops, so you can do this with one line of code. (If you want to add more complex mesh objects, you’ll need to code the operator by hand, as you will see later in this chapter.)

1. To find out what options are available to you, type bpy.ops.mesh.primitive_ into the command line, and press Ctrl+spacebar to see the autocomplete options. You’ll see a list like this:
>>> bpy.ops.mesh.primitive_              circle_add(              cone_add(              cube_add(              cylinder_add(              grid_add(              ico_sphere_add(              monkey_add(              plane_add(              torus_add(              uv_sphere_add(

These method names are self-explanatory.

2. Let’s add a Suzanne to the scene. Simply finish the line of code with monkey_add() like this:
>>> bpy.ops.mesh.primitive_monkey_add()
3. Voila! A monkey will appear in your scene, and the return value {'FINISHED'} will appear in the interactive console.

An Object-ionable Question
When you do Python programming for the Blender environment, the word object may be a source of confusion. In Python-speak, objects are instantiations of classes. (In fact, in Python, everything is an object of some class.) This is standard terminology in object-oriented programming (OOP). On the other hand, in Blender, objects are things that have positions, rotations, and centers in the 3D space. In short, anything you can select with your right mouse button in Blender’s Object mode is an object.
To give an example, a Mesh datablock, which contains data about the location of vertices with respect to each other, is different from a Mesh object, which contains information about its overall location, scale, and orientation of in the 3D space. If you do not already know the difference between datablocks in Blender and the objects to which they are associated, I recommend reviewing this before continuing with this chapter. Chapter 1, “Blender Basics: Interface and Objects,” of my book Introducing Character Animation with Blender, 2nd Edition (Sybex, 2011), goes into the difference for the case of meshes in some detail.
In most cases, the meaning of the word object should be clear from the context. In cases where it may not be clear, I will refer to Blender-style objects as 3D objects.

Working with Text Editors

The interactive console is great for running one-line commands like the ones you just saw and for looking things up using autocomplete. In fact, if you really want to, you can even write complete scripts in the console by pressing Enter once for new lines and twice to return to the interactive mode. When you work in the console, the Python interpreter keeps track of variable values and even class definitions. However, for even simple scripts, it is much better to work with a text editor. In this chapter, I’ll assume you’re using the Blender text editor, but other good editors exist. Notepad++ is a nice editor for working with Python scripts in Windows, and for Unix-based machines there is always Emacs. You need to be careful that the tab settings match between the editors you use, or you’ll run afoul of Python’s indentation sensitivity.

The Blender Text Editor

Like any other window type, the Blender text editor can be accessed from the Window Type menu in the left corner of any window header. The text editor window is shown in .

A script displayed in the text editor

c13f002.tif

The basic functionality in the File and Edit menus is standard and will be familiar to anyone who has used a word processor or text editor.

The Format menu item has various options that are specific to Python scripting. For example, the Indent and Unindent options will add a tabbed indentation to (or remove one from) selected blocks of text. You can also perform these operations from the keyboard with Tab and Shift+Tab, respectively. Because the structure of a Python program is determined by the pattern of indentation, these are handy shortcuts. The Comment menu item adds a hash (#) symbol to the beginning of each line in a selected block of text, which comments out that line of code. Commented-out code is ignored by the interpreter, so this is a good way to add comments to help explain the code to other programmers who might have cause to read it (or to yourself, if you come back to your script after a long time away!). You can also use the Comment and Uncomment options to remove and replace blocks of code from your script for testing purposes, without having to delete and rewrite them. Commenting out code to help narrow down the source of a problem is a commonly used method of debugging. The Convert Whitespace option in the Format menu enables you to convert whitespace from spaces to tabs and vice versa, which can be useful for fixing problems that can result from using multiple editors with different tab settings.

The three buttons shown in , from left to right, toggle line numbering, word wrap, and color-coded syntax highlighting.

Toggle buttons for line numbering, word wrap, and syntax highlighting

c13f003.tif

Script Format and Templates

Blender Python scripts follow certain conventions. You don’t necessarily have to follow them if you are writing scripts for yourself, but if you plan to release your scripts for use by others, or if you want to make sure that your scripts can be fully integrated into the Blender environment and included in menus, be sure that you have them properly formatted. Several ready-made templates can be accessed via the Templates menu in the text editor header, as shown in .

Loading a script template

c13f004.tif

Licensing Information
Typically, scripts that are intended to be made available for others’ use should include licensing information. If you aim to have your script included in an official release of Blender, the script must be licensed with a GPL-compatible license. You can copy and paste the GPL text directly from other scripts into your own. If you choose to use another license, make sure that it accurately reflects how you want people to treat the script. Don’t assume that people will read your mind and understand what they can and can’t do with your script in the absence of licensing information.

The remainder of the template’s content is an outline for the actual code. The rest of this chapter covers in depth the issues of defining classes and writing your script.

Adding a Simple Mesh Object to the Scene

Before you start working with templates, it’s a good idea to see how scripts run from the text editor. You can do this by writing a very simple script and executing it. In this section, you’ll see how to write the simplest possible script that creates a mesh object with a single vertex and places it in the scene.

While you were poking around the bpy.ops module in the previous section, you might have noticed that a built-in mesh operator already exists to create a single vertex mesh, just like the ones to add primitives to the scene. In actual practice, you’d probably just call this operator in your script to make a single-vertex mesh, a process analogous to how you added the monkey to the scene in the previous section. But that would be a little too simple. Instead, you’ll create a script that will do exactly what that operator does, but you’ll code the whole thing explicitly in Python. This is much closer to what you would need to do if you wanted to create a script to add a custom shape to the scene.

1. After header information, the import bpy command is the first line of code for any standard Blender Python script. Thus, the first thing you need to do is to import the bpy modules, which is done using the import command like this:
import bpy 
2. Next, you need to set a variable to represent the vertices in the mesh you want to create. Vertices in a mesh are represented as a list of triples or vectors. In Python, a list data structure is enclosed in square brackets. Multiple list entries are separated by commas. In this example, the mesh will have only a single vertex, so there will be only one triple in the list of vertices. The vertex will be placed at the object origin, so its coordinates will be 0, 0, and 0. To do this, create the next line of code, which looks like this:
verts = [(0, 0, 0)]
3. When you create the mesh, the method you use will also want lists representing the edges and the faces of the mesh. With a single vertex, there are no edges or faces, so you can assign these to be empty lists like this:
edges = []  faces = []
4. Next, you’ll create a new Python object representing the mesh datablock. I told you the word object was ambiguous! Here, you’re not yet creating the Blender 3D object; you’re only creating a new instance of a Python class representing mesh data. This is done by calling the new() method (with the name of the mesh as an argument) for bpy.data.meshes like this:
mesh = bpy.data.meshes.new(name='Single Vertex Mesh')
Objects of this class have a method called from_pydata() that enables you to pass Python-formatted data to the object. This is how you get the vertex, edge, and face information to your mesh datablock object:
mesh.from_pydata(verts, edges, faces)
5. Now, create a Python object to represent the Blender 3D mesh object. Again, use a new() method. In this case, the arguments represent the name of the new 3D object and its associated datablock. This is done like this:
obj = bpy.data.objects.new("Single Vertex", mesh)
6. The 3D object is ready to be placed into the scene (called linking), but you haven’t yet done that. Before you do that, set the object’s location to be the same as the 3D cursor’s location, like this:
obj.location = bpy.context.scene.cursor_location
7. Next, link the object into the scene, like this:
bpy.context.scene.objects.link(obj)
8. Finally, make the new 3D object the active object in the scene, like this:
bpy.context.scene.objects.active = obj
9. When you’ve done this, click the Run Script button in the text editor header. A new 3D object will appear in the 3D viewport at the location of the 3D cursor. You’ll see only the object’s center, because there’s only a single vertex. However, if you tab into Edit mode, you’ll be able to extrude new vertices.
10. If you have any problems, check the error output in the System Console (review Chapter 12, “The Blender-Python Interpreter,” to see how to view the System Console for your operating system). Check for any typos or inconsistent spacing and indentation along the left edge of the script.

State-of-the-Art Virtual Reality at MetaVR
Modeling and animating with Blender isn’t all just fun and games. At MetaVR, one of the industry leaders in virtual reality software, integration with Blender has been a central part of the development of their Virtual Reality Scene Generator (VRSG) software, which has been used extensively for real-time, immersive military training by the armed forces of several countries. Blender developer Campbell Barton was contracted to author MetaVR’s Blender plug-in, which enables users to create new content for use in the VRSG environment, including fully rigged, animated characters.
This work resulted in the ability to create scenes involving tens of thousands of buildings and trees and in the creation of a character library of more than 100 human characters that could be exported simultaneously to the VRSG format, with automatic level-of-detail generation and infrared texture map creation. Numerous current features of Blender were the direct result of MetaVR’s investment in this project, including BVH export functionality, the array modifier, UV projection, custom transform axes, knife snapping, improved quad-to-triangle conversions, and numeric input for transforms. Under-the-hood developments from this project include ID properties, which form the basis for the data interchange system of Blender 2.50 and future versions.
The MetaVR Blender plug-in is a quintessential example of how Python scripting can extend the possibilities of Blender by enabling users to export content to, and import content from, other formats. Blender already includes a wealth of built-in Python-based import and export scripts for most standard 3D formats. With the custom-made MetaVR plug-in, Blender was able to offer functionality that would otherwise have been limited to special VR content-creation software ranging in the tens of thousands of dollars per seat.
You can learn more about MetaVR’s use of Blender in the VRSG environment at their website:

Creating an Interactive Add-on

You’ve now seen the basis of how the Python API works to enable your script to access Blender’s operators and data. But nobody wants to have to jump through the hoops of loading up a script in the text editor and executing it every time they want to trigger some custom functionality. Fortunately, the Blender 2.5 API enables you to write your script as an add-on so that its functionality can be seamlessly integrated with the rest of the Blender interface. The add-on system is one of the biggest new developments to come from the recode. It’s a great way to add Python functionality, particularly if you want to share it with other users.

Making add-ons is especially simple to do if you start with one of the ready-made templates available from the text editor, which is what you will do now.

The Addon Add Object Template

In this section, you’ll create an add-on to add a single-vertex mesh to the 3D scene. You have already seen the nuts and bolts of how that would be done in Python. When you use a template, the hard work is done for you and the resulting script is much more elegant and useful. You’ll only need to change a few lines.

To use the template, open up a new text editor window and select Templates > Addon Add Object. The script will appear in the text editor window. You can edit this, change it, save it, or rename it as you like. The Templates menu can always be used to create a fresh, unchanged copy of the original template script.

Before you get to actually editing the script, let’s run it as an add-on and then read though the template in some detail, to see exactly what the code is doing.

To run the script, of course, you could simply click the Run Script button. That would work, but it’s not the way add-ons are natively executed, so let’s do this in a more representative way:

1. Save the script in the appropriate add-ons folder on your operating system; then click F8 to make Blender update its scripts.

Where to Save Your Add-on
The correct place to save your add-on depends on your operating system. One way to do it is to save your script anywhere and then to import it to the correct directory by clicking the Install Add-on button in the header of the Add-ons area. Alternatively, you can save the script directly in your user Add-ons directory. To find out where this is, you can run the System Info script from the Help menu as you learned to do in Chapter 1, “Working in Blender.” The Addons_Contrib folder contains experimental scripts that can be seen by turning on Testing. On the 64-bit Windows 7 machine I’m working with now, the directory is
(Home directory)\AppData\Roaming\Blender Foundation\Blender\2.60\scripts\addons

2. When you’ve saved the script, press F8 to reload all scripts. Be sure to watch the System Console to make sure there are no complaints. If not, your add-on should have loaded smoothly. Check the Add-ons panel in the User Preferences window to verify that the Add Mesh: New Object add-on is there.
3. Click the check box to the right of the add-on listing to activate the add-on, as shown in .

The Add Mesh: New Object add-on

c13f005.tif
4. Once the add-on is activated, you can go to the 3D viewport and add a new object using the add-on functionality in the same way you would any other mesh object. Simply press Shift+A and select Mesh > Add Object, as shown in .

Using the add-on

c13f006.tif
5. When you do this, a plane will appear in the 3D viewport, and a panel will appear in your tool shelf (you can toggle visibility of the tool shelf with the T key), as shown in . In the panel, you can interactively adjust the Location, Rotation and Scale of the object.

Now that you’ve run the add-on and you’ve seen how it integrates into the interface, let’s take a closer look at the code itself.

Adding a new object

c13f007.tif

The bl_info Block

For add-ons, the first (uncommented) code should be the bl_info code block. This is a special part of the code. When your script is saved in the appropriate directory for scripts, Blender will automatically read the bl_info values for the script upon startup and again when you refresh the scripts using the F8 key. These values will tell Blender how to classify the add-on so that it shows up correctly in the Add-ons panel of the user preferences.

The code block in the template looks like this:

bl_info = {   "name": "New Object",   "author": "YourNameHere",   "version": (1, 0),   "blender": (2, 6, 2),   ""   "location": "View3D > Add > Mesh > New Object",   "description": "Adds a new Mesh Object",   "warning": "",   "wiki_url": "",   "tracker_url": "",   "category": "Add Mesh"}

Most of these values are self-explanatory. If you’re using the template, the versioning information (version, blender, and API values) should be up to date. You can change the name of the script, your own author name, the description of the script, and the category it should be classified under in the Add-ons panel. The Location value tells where in the interface the script will be found. In this case, the functionality can be accessed from the 3D viewport’s Add menu, at Add > Mesh > New Object, which is just as you saw when you used the add-on.

Module Imports

The next few lines of the code import the necessary modules. Modules store the definitions for classes and functions that are used elsewhere in the script. If you want to use a class defined in a module, the module must be imported. As you can see, the first line

(import bpy)

imports the bpy module, so you can call objects that begin with the bpy prefix.

The next three lines,

from bpy.props import FloatVectorProperty  from add_utils import AddObjectHelper, add_object_data  from mathutils import Vector

are a little different. Rather than using the import command, they use the from X import Y syntax. This is a different way of doing the same thing that the import command does, but it results in a different naming convention within your script. Objects imported using the from X import Y syntax can be accessed directly by name without using any module prefix. This is a subtle but important difference. In this case, the from X import Y syntax is used for the sake of brevity, so that object names like FloatVectorProperty can be used without a lengthy string of prefixes. The bpy module is always imported using the import command.

Class and Function Definitions

The next part of the code, from line 21 to line 59 in the unedited template file, contains the definitions that constitute the main portion of the code. The first definition is the definition of the add_object() function, which is the block of code beginning on line 21 with

def add_object(self, context):

The next definition is the definition of the OBJECT_OT_add_object class, which begins on line 41 with the line

class OBJECT_OT_add_object(bpy.types.Operator, AddObjectHelper):

The Class Definition

Writing these definitions in this order is intuitive, because the class calls the function. However, it’s a bit easier to understand what’s going on if we look at these definitions in reverse order. So first, let’s look at the class definition, beginning on line 41. Later, we’ll return to line 21 to look at the function definition.

The first line begins the definition of the OBJECT_OT_add_object class:

41 class OBJECT_OT_add_object(bpy.types.Operator, AddObjectHelper):

The keyword class indicates that this is a class definition. The arguments are the classes from which this class inherits its properties and methods. Python allows multiple inheritance, so OBJECT_OT_add_object inherits the functionality of both bpy.types.Operator and AddObjectHelper. The former is the general class for operators in Blender, so we know that this new class will be an operator. The latter is something that was imported from the add_utils module. The AddObjectHelper class contains a variety of useful shortcuts and built-in features to make it easier to build operators that (guess what?) add objects to the scene. Among these features is an automatically generated interface for interactively setting the rotation and location of the object you create, as you’ll see shortly.

The next few lines set variables that are necessary for registering operations, which you’ll learn about shortly. The bl_idname will be the identifier for the Python call of the operator, and the bl_description will appear on the tool tip in the interface, as shown in . The bl_label value sets the text label on the interactive panel, and bl_options sets the values for available operator options. In this case, the option to register the operator and the option to make the operation reversible are set.

42  """Add a Mesh Object"""  43  bl_idname = "mesh.add_object"  44  bl_label = "Add Mesh Object"  45  bl_description = "Create a new Mesh Object"  46  bl_options = {'REGISTER', 'UNDO'}

The Add Object tooltip

c13f008.tif

The next few lines, between line 48 and line 53, set the scale property. Unlike location and rotation, which are handled automatically on the object level (thanks to the AddObjectHelper), the effect of the scale value on the mesh data (i.e., the location of vertices) needs to be written out explicitly in your script. For this reason, this value will be represented as a property of the OBJECT_OT_add_object class.

Setting a class property is simply a matter of assigning a value to a variable within the class definition. In this case, the scale variable is assigned an object of class FloatVectorProperty, which is a class that was imported in the first few lines of the script from the bpy.props module. The arguments for the constructor of the object are mostly self-explanatory. The name, default value, and description are all what you’d expect them to be. The subtype value is used to organize properties and help the AddObjectHelper to know how to handle this property.

48  scale = FloatVectorProperty(  49    name='scale',  50    default=(1.0, 1.0, 1.0),  51    subtype='TRANSLATION',  52    description='scaling',  53    )

Finally, the execute method contains the actual code that gets called when the operator is executed in Blender. It’s common to have this be simply a single function call and have that function contain the code you want to run. In this case, the function is add_object(), which was defined previously in the script and which you’ll look at shortly. The return value is FINISHED, indicating that this is a function that is called, runs, and then exits when complete.

55  def execute(self, context):  57   add_object(self, context)  59   return {'FINISHED'}

The Function Definition

Now that you’ve seen the context in which it’s called, it will be more meaningful to look at the add_object() function’s definition. Turn your attention back to line 21:

21 def add_object(self, context):

The first things to note are the arguments to the function call, self and context. The self variable will carry the self value from the OBJECT_OT_add_object class. In Python, self is a special term representing an object itself. So in this case, self is the instance (object) of the OBJECT_OT_add_object class. The context value has been passed from one method call to the next, beginning with the registration of the class. The context object carries the information about Blender’s current state that the operator needs to know how to execute.

Moving into the function definition, you can see that some local variables, scale_x and scale_y, are given values that draw on the x and y components of the scale vector of the OBJECT_OT_add_object object (passed to the function as the variable self). Next, a list of three-dimensional vectors is assigned to the verts variable. These represent the locations in space of the four vertices that will make up the default plane mesh object created by this operator. Note that the positions of the x and y values are multiplied by scale_x and scale_y, respectively. The position of a mesh’s vertices in space depends on the scale of the mesh 3D object.

22  scale_x = self.scale.x  23  scale_y = self.scale.y  25  verts = [Vector((-1 * scale_x, 1 * scale_y, 0)),  26    Vector((1 * scale_x, 1 * scale_y, 0)),  27    Vector((1 * scale_x, -1 * scale_y, 0)),  28    Vector((-1 * scale_x, -1 * scale_y, 0)),  29    ]

The next two lines define the list of edges and the list of faces:

31  edges = []  32  faces = [[0, 1, 2, 3]]

In this case the edges are implied by the face, so it is not necessary to define any edges. The face is a list of lists of vertices. In this case, there is only one list of vertices, corresponding to the one face of the plane.

In the next two lines, a mesh datablock object is created and the data is generated from the lists of vertices, edges, and faces, just as you did in the example of the single vertex mesh previously.

33  mesh = bpy.data.meshes.new(name='New Object Mesh')  35  mesh.from_pydata(verts, edges, faces)

Lines 36 and 37 are commented out, so they don’t do anything by default. If you are working with more complex meshes and you need debugging information with respect to the validity of the mesh structure, you can uncomment line 37.

36  # useful for development when the mesh may be invalid.  37  # mesh.validate(verbose=True)

In line 38, some magic happens:

38  add_object_data(context, mesh, operator=self)

The add_object_data() function is a function imported from the add_utils module that automatically produces the interactive interface to enable you to tweak the Location, Rotation, and Scale values using the sliders in the tool shelf when you add the object. You don’t have to do anything at all for this. Of course, you may want to control how things appear in the interface. This is possible to do by overriding the automatic interface generation. You’ll see how this is done later in this chapter.

Registration

The next few function definitions are somewhat boilerplate definitions that need to be present for add-ons. The add_object_button() function takes care of placing the function in the menu. The text argument is the text that will be on the menu entry and the icon value lets you choose the icon to go with the functionality.

def add_object_button(self, context):   self.layout.operator(    OBJECT_OT_add_object.bl_idname,    text="Add Object",    icon="PLUGIN")

(Re)using Icons
You can use any icon from Blender’s icon set in your interface. Unfortunately, the icon set is fixed and it is not trivial to add to it. This is why you will sometimes see new or altered functionality coupled with somewhat unintuitive icons. An example of this was the temporary use of a speaker button to represent “muting” the behavior of animation curves in the nonlinear animation editor. It’s not that anybody thought a speaker was an optimal symbol for this functionality; it was just that the selection of icons was limited to ones that already exist.

The register() function calls the register_class() function for your newly created object and then adds the add_object_button function to the list of panels and menu items that need to be displayed in the interface:

def register():   bpy.utils.register_class(OBJECT_OT_add_object)   bpy.types.INFO_MT_mesh_add.append(add_object_button)

The unregister function does what you’d expect it to. It unregisters the class and removes the widget from the interface:

def unregister():   bpy.utils.unregister_class(OBJECT_OT_add_object)   bpy.types.INFO_MT_mesh_add.remove(add_object_button)

The last few lines of code are a little bit of Python-alia to call the register() function when the script is run:

if __name__ == '__main__':   register()

That’s all there is to the add-on. To change the functionality to create the single-vertex mesh you worked with previously, the edits are very simple. The only really necessary change is to rewrite the add_object() function to construct the mesh as follows:

def add_object(self, context):   verts = [Vector(0, 0, 0))]   edges = []   faces = []   mesh = bpy.data.meshes.new(name='Single Vertex Mesh')   mesh.from_pydata(verts, edges, faces)   add_object_data(context, mesh, operator=self)

You should also delete the scale property from the class definition, because it is not used, and change the various labels and names in the interface to reflect the new functionality, but these changes are trivial.

Working with Custom Properties

In this section, you will build an interactive sample script from the ground up. The functionality is simple. The script will enable the user to create bouncing, colored cones in 3D space by using a script interface to set various parameters for the cones such as their dimensions, color, and the speed and height of their bouncing. It’s not a very practical script, but it will give you a good sense of how a Python script works with 3D assets in Blender.

Composing the Add-on

The add-on you’ll create in this section is based on the same add-on template as the one described in the previous section. However, there are significant additions and changes, particularly in the part of the code that creates the object.

The overall code is structured identically to the template. First, there is the bl_info assignment and the necessary imports. The bl_info assignment is as follows:

bl_info = {   "name": "Add Bouncing Cone",   "author": "Tony Mullen",   "version": (1, 0),   "blender": (2, 6, 2),   ""     "location": "View3D > Add > Bouncing Cone",   "description": "Add a bouncing, colored cone.",   "warning": "",   "wiki_url": "http://wiki.blender.org",   "tracker_url": "https://projects.blender.org",   "category": "Add Object"}

All of this should be familiar from the previous description of the bl_info data structure. Only the values for name, location, description, and category have changed.

The next five lines are necessary imports. Most of these you’ve seen before. Using the * statement imports everything from a module. We’ll discuss the imported property classes in more detail shortly.

import bpy  from bpy.props import FloatVectorProperty, FloatProperty  from add_utils import AddObjectHelper, add_object_data  from mathutils import Vector  from math import *

After the imports, we declare a global variable to determine the number of vertices that will compose the circular base of the cone. As one of the exercises at the end of this chapter, you’ll change this from a global variable to an integer property and make this value interactive. For now we’ll keep it simple and let it be an ordinary variable:

cverts = 10

The rest of the script is structurally identical to the example from the template. The function and class definitions are written in the following order:

def addBouncingCone(self, context):  class Bouncing_Cone(bpy.types.Operator, AddObjectHelper):  def menu_func(self, context):  def register():  def unregister():

Note that the five lines of code presented here, if run exactly as written, without any content in the function definitions, will produce errors. Python does not allow empty control structures, so a line ending with a colon must be followed by some properly indented code. If you want to write a placeholder function (or any control structure) without any content, use the Python command pass to fulfill this requirement. As you fill in different parts of the script, the add-on usually won’t work until it’s complete. In fact, Blender won’t even let you turn it on from the Add-ons menu if certain functionality hasn’t been coded. Stick with it until the whole add-on is written, and use comments in your script to describe new tools as you learn them.

Let’s look at the content of these definitions from the bottom up.

register() and unregister()

Let’s begin with the register() and unregister() functions:

def register():   bpy.utils.register_module(__name__)   bpy.types.INFO_MT_add.append(menu_func)  def unregister():   bpy.utils.unregister_module(__name__)   bpy.types.INFO_MT_add.remove(menu_func)

These are almost identical to what you saw in the previous example, just somewhat more generalized. The biggest difference is that we are calling bpy.utils.register_module() (and the corresponding unregister function) instead of bpy.utils.register_class(). This is simply a more general way to write the same thing. If we have multiple classes in the module, all of the classes will be registered. For that reason, rather than a specific class name as the argument, the special variable __name__ is used, which returns the name of the current module (i.e., this script) itself.

menu_func()

The next lines in the function send the function menu_func() to be added to the interface (or removed from it, in the case of unregister).

def menu_func(self, context):   self.layout.operator(Bouncing_Cone.bl_idname,         icon='MESH_CONE')

This connects the operator, referred to by its bl_idname property value to the menu item in the interface. It places MESH_CONE as the icon on the menu. The icon is borrowed from the menu item for adding a primitive mesh cone. Note that with the multiline function (), you can have as much or as little whitespace on the second lines as you want. However, it’s preferable to format it with previous lines for readability.

The Main Class

Moving on to the definition of the Bouncing_Cone class, you can see that creating the class begins just as in the previous examples. Bouncing_Cone will inherit class properties from bpy.types.Operator and AddObjectHelper:

class Bouncing_Cone(bpy.types.Operator, AddObjectHelper):   """Add a bouncing colored cone"""

The standard variables for operators are declared and given values:

 bl_idname = "object.bouncing_cone_add"   bl_label = "Bouncing Cone"   bl_description = "Add a bouncing cone"   bl_options = {'REGISTER', 'UNDO'}

The scale value from the default Add Object template is included. There’s no real need to delete it, although you may not choose to use it. The scale code looks like this:

 scale = FloatVectorProperty(name='scale',      default=(1.0, 1.0, 1.0),      subtype='TRANSLATION',      description='scaling') 

Height, Radius, Bounce, and Color Properties

Next, you’re going to add a few properties specific to the bouncing cone object. We want to be able to set the height of the cone, the radius of the cone base, the speed and height that the cone bounces, and the color of the cone’s material in terms of red, blue, and green values. All of these values are objects of the class FloatProperty.

The height property variable is set like this:

 height = FloatProperty( attr='height',      name='Height', default = 1,      min = 0, soft_min = 0, max = 2,      description='Height of the cone')

The minimum, maximum, and default values are set in this constructor, as well as the optional soft_min and soft_max, which determine the minimum and maximum values available through the graphical user interface. The radius of the base is defined here:

 radius = FloatProperty( attr='radius',      name='Radius', default = 0.5,      min = 0.001, soft_min = 0.001, max = 2,      description='Radius of the cone')

The speed of the bounces is determined with the speed variable, which is set to range from 0.5 to 2. This will later be used as a denominator to set the distance between keyframes. The definition of the speed variable goes like this:

 speed = FloatProperty( attr='speed',      name='Bounce speed', default = 1,      min = 0.5, soft_min = 00.5, max = 2,      description='Speed of the bouncing cone')

The bounce_height variable, similarly to speed, is used to determine the positioning of keyframes. Its definition is as follows:

 bounce_height = FloatProperty( attr='bounce_height',      name='Bounce height', default = 1,      min = 0, soft_min = 0, max = 2,      description='Height of the bouncing cone')

The last three float properties are the RGB color values that will be assigned to the 3D object’s material color. They range from 0 to 1, yielding a full range of possible color settings. We’ll make a light-green material. The definitions are as follows:

 r = FloatProperty( attr='red',      name='Red', default = 0.5,      min = 0, soft_min = 0, max = 1,      description='Red')   g = FloatProperty( attr='green',      name='Green', default = 1,      min = 0, soft_min = 0, max = 1,      description='Green')   b = FloatProperty( attr='blue',      name='Blue', default = 0.5,      min = 0, soft_min = 0, max = 1,      description='Blue')

Drawing the Interface

The next part of the class definition is the draw() method, which tells Blender how to draw the interactive interface for the operator. This is something new. In previous examples, the draw() method was not defined. So how did Blender know to draw the interactive interface? The answer is that a draw() method is built into the AddObjectHelper class. If you do not define a method by the same name to override the default method, Blender automatically draws an interactive interface for setting object location, rotation, and scale values. In this example, we want to include other interactive properties besides just location, rotation, and scale, so it is necessary to override the draw() method. This definition begins as follows:

 def draw(self, context):

The first argument, self, passes the Bouncing_Cone object’s own data to the method. The second argument, context, passes the context information about Blender’s internal state to the method.

Operator objects have a property called layout. We assign the layout property to a local variable called layout like this:

  layout = self.layout

The next few lines of code arrange the properties in the UI. You can arrange properties in columns or rows. The specific widget type used to access the properties depends on the property type. Float properties like the ones used here are displayed as numerical slider bars. Enum properties are displayed as drop-down menus, and boolean properties are displayed as check boxes. This is automatic, and it maintains consistency in the interface.

To begin a column, call layout.column() and assign the result to a variable like this:

  col = layout.column()

You can now call the prop() method on the column to put a property widget into the column, as in the following two lines, which access the height and radius properties:

  col.prop(self, 'height')    col.prop(self, 'radius')

The column class has other methods that can add other kinds of widgets besides properties. To place a text label on a column, use the label() method, like this:

  col.label(text='Material color: ')

You can arrange widgets horizontally by using a row object. Row objects are created just like column objects but using the row() method, like this:

  row = layout.row()

Here is how RGB color values can be arranged horizontally on the row:

  row.prop(self, 'r')    row.prop(self, 'g')    row.prop(self, 'b')

After this, we return to column layout by calling layout.column() again and attaching the remaining labels and properties to the column as follows:

  col = layout.column()    col.label(text='Bounce properties:')    col.prop(self, 'speed')    col.prop(self, 'bounce_height')    col.prop(self, 'location')    col.prop(self, 'rotation')    col.prop(self, 'scale')

That completes the draw() method, which will give you your complete interactive interface for the operator.

The execute() method

The next method that needs to be defined for this class is the execute() method, which contains the code the operator will run when activated. As in the previous example, we’ll write the operator’s execution code in a separate function, called addBouncingCone(), and call that function from the execute method like this:

 def execute(self, context):    addBouncingCone(self, context)    return {'FINISHED'}

This completes the Bouncing_Cone class definition.

Adding the Cone

Now, we’ll define the addBouncingCone() function. This definition starts off in a familiar way:

def addBouncingCone(self, context):

We’ll retain the code from the original template to pass the scale properties of the object to local variables (this is not necessary; the values can be accessed through self.scale at any time, but it helps to keep things a bit tidier):

 scale_x = self.scale.x   scale_y = self.scale.y   scale_z = self.scale.z

Next, we’ll create the set of vertices with two initial vertices. We’ll place one of these vertices at the origin of the space (this will be where the cursor is). This vertex will represent the center point of the base of the cone. We’ll place the other vertex directly above the first at a height of self.height multiplied by scale_z. These values will be interactively adjustable, and the height of the cone will change depending on their values.

 verts = [Vector((0,0,0)),Vector((0,0,self.height*scale_z))]

We’ll set edges and faces to empty lists. Later, we’ll add faces to the faces list. It wouldn’t make sense to do that at this point, because there are only two vertices, and they don’t form any part of a single face.

 edges = []   faces = []

The next block of text runs through a loop ranging from zero to the number of vertices you chose previously for the base of the cone (recall that this value was set to 10). The loop is initialized like this:

 for j in range(0,cverts,1):

This is a standard Python for loop. The arguments of range represent the minimum, the (exclusive) maximum, and the interval. The function returns a list, which j iterates over.

For each of these 10 iterations, the coordinates of the corresponding vertex need to be calculated. We use a little simple trigonometry to position the verts. The x and y values are calculated from the sine and cosine of the angle of the position of the vertex multiplied by the radius value and the scale value for the axis. If this doesn’t make sense, you might want to bone up on your trig functions (always a good idea if you want to do graphics programming). The z coordinate is set to zero to make the base of the cone flat. These variable assignments look like this:

  x = (sin(j*pi*2/(cverts-1))*self.radius)*scale_x    y = (cos(j*pi*2/(cverts-1))*self.radius)*scale_y    z = 0

Each vertex is appended to the list of vertices like this:

  verts.append(Vector((x,y,z)))

The append() function is standard Python. It adds elements to a list.

For each vertex around the base after the first one, two triangular faces are created: one upward towards the apex of the cone and one inward to form the solid base of the cone. This is done using the following conditional block of code:

  if j > 0:     faces.extend([[0,j+1,j+2],[1,j+1,j+2]])

The extend() function is another standard Python list function. It is similar to append(), but rather than adding elements to a list on their own, it adds a list of elements to the list. In this case, two faces are added at a time.

When this loop exits, the mesh’s geometry has all been established. Next, we’ll create the mesh datablock object, pass the geometry data to that datablock, and add the mesh to the scene just as you saw in the template example:

 mesh = bpy.data.meshes.new(name='Bouncing Cone')   mesh.from_pydata(verts, edges, faces)   add_object_data(context, mesh, operator=self)

You might have noticed in the template example that the edges of the default added object are not highlighted when the object is first created, as is usual for selected objects. You can make sure that they are selected by calling the update() function on the mesh as follows:

 mesh.update(calc_edges=True)

A final point: The cone whose mesh we’re creating from scratch starts out with mixed normals, the base facing outward and the cone facing inward. Additionally, one vertex isn’t connected, so we’ll remove doubles while in edit mode. First, we enter into edit mode to affect our mesh data:

 obj = bpy.context.selected_objects   bpy.ops.object.mode_set(mode='EDIT', toggle=False)

Then, we can recalculate normals and remove doubles before returning to object mode:

 bpy.ops.mesh.normals_make_consistent(inside=False)   bpy.ops.mesh.remove_doubles(mergedist=0.0001)   bpy.ops.object.mode_set(mode='OBJECT', toggle=False)  

Setting a Colored Material

At this point, the basic functionality of placing the mesh object in the scene has been completed, but there’s more to be done. The script should create colored bouncing cones, so we need to give the cones color and animate their movement. There are a number of options for making them colored, but the most useful is probably to give them a colored material.

1. First, let’s get the active object (which is necessarily going to be the cone that was just created) and assign it to the local variable obj.
 obj = bpy.context.object
2. Next, we create a new material datablock object using the standard bpy syntax for creating new data objects:
 mat = bpy.data.materials.new(name="Cone Material")
3. The red, green, and blue values for the material’s diffuse color value can be set as follows:
 mat.diffuse_color.r = self.r   mat.diffuse_color.g = self.g   mat.diffuse_color.b = self.b
4. Finally, we set the material to be the object’s active material like this:
 obj.active_material = mat

Keyframing the Animation

Animation keyframes are set analogously to the way keyframes would be set in ordinary Blender use, by calling the appropriate operators in Python:

1. First, place the object at the location determined by the script:
 obj.location[2] = self.location[2]
2. Then set the start frame to 1 like this:
 startframe = 1
3. Call the keyframe_insert() method to add a keyframe:
 obj.keyframe_insert(data_path="location",        frame=startframe,        index=2)
4. Change the location of the object by adding the bounce height value like this:
 obj.location[2] = self.location[2] + self.bounce_height
5. Now, set another keyframe, this time with an increased frame value. Note that self.speed is used as a denominator to control the closeness of the keyframes.
 obj.keyframe_insert(data_path="location",        frame=startframe+(10/self.speed),        index=2)
6. Place the object back at the original position and add a third keyframe, advancing another few frames (depending on the speed value).
 obj.location[2] = self.location[2]   obj.keyframe_insert(data_path="location",        frame=startframe+(20/self.speed),        index=2)
7. Finally, add a cyclic modifier to the animation F-curve to make it repeat, like this:
 obj.animation_data.action.fcurves[0].modifiers.new('CYCLES')
8. You now should be able to install and activate this script as an ordinary add-on. It will create a bouncing colored cone with values that can be interactively adjusted, as shown in . In order to see the bouncing movement, you will need to press Alt+A to play animation in the 3D viewport.

The Add Bouncing Cone operator in action

c13f009.tif

Clearly, this example only scratches the surface of the functionality of the Blender-Python API. However, it should give you a sufficient sense of how operators and data are accessed through the API to begin digging around for what you want yourself. There are many resources already built into Blender for finding what you need. Operator names are listed in the mouse-over tooltips and are logged in the Info window as they are called during ordinary Blender use. Script templates provide examples of a wide variety of functionality implemented in Python. Furthermore, since most of the interface is actually written in Python, you can go straight to the interface code in your scripts directory and study (or alter) it first hand. In addition to all of this, there is the online API documentation to fill in any blanks.

The Complete Add Bouncing Cone Code

The Add Bouncing Cone script is listed here in its entirety, without breaks:

bl_info = {   "name": "Add Bouncing Cone",   "author": "Tony Mullen",   "version": (1, 0),   "blender": (2, 6, 2),   ""     "location": "View3D > Add > Bouncing Cone",   "description": "Add a bouncing, colored cone.",   "warning": "",   "wiki_url": "http://wiki.blender.org",   "tracker_url": "https://projects.blender.org",   "category": "Add Object"}  import bpy  from bpy.props import FloatVectorProperty, FloatProperty  from add_utils import AddObjectHelper, add_object_data  from mathutils import Vector  from math import *  cverts = 10  def addBouncingCone(self, context):   scale_x = self.scale.x   scale_y = self.scale.y   scale_z = self.scale.z     verts = [Vector((0,0,0)),Vector((0,0,self.height*scale_z))]   edges = []   faces = []   for j in range(0,cverts,1):    x = (sin(j*pi*2/(cverts-1))*self.radius)*scale_x    y = (cos(j*pi*2/(cverts-1))*self.radius)*scale_y    z = 0    verts.append(Vector((x,y,z)))    if j > 0:     faces.extend([[0,j+1,j+2],[1,j+1,j+2]])     mesh = bpy.data.meshes.new(name='Bouncing Cone')   mesh.from_pydata(verts, edges, faces)   add_object_data(context, mesh, operator=self)   mesh.update(calc_edges=True)   obj = bpy.context.selected_objects   bpy.ops.object.mode_set(mode='EDIT', toggle=False)   bpy.ops.mesh.normals_make_consistent(inside=False)   bpy.ops.mesh.remove_doubles(mergedist=0.0001)   bpy.ops.object.mode_set(mode='OBJECT', toggle=False)   obj = bpy.context.object   mat = bpy.data.materials.new(name="Cone Material")   mat.diffuse_color.r = self.r   mat.diffuse_color.g = self.g   mat.diffuse_color.b = self.b   obj.active_material = mat   obj.location[2] = self.location[2]   startframe = 1   obj.keyframe_insert(data_path="location",        frame=startframe,        index=2)   obj.location[2] = self.location[2] + self.bounce_height   obj.keyframe_insert(data_path="location",        frame=startframe+(10/self.speed),        index=2)   obj.location[2] = self.location[2]   obj.keyframe_insert(data_path="location",        frame=startframe+(20/self.speed),        index=2)   obj.animation_data.action.fcurves[0].modifiers.new('CYCLES')      class Bouncing_Cone(bpy.types.Operator, AddObjectHelper):   """Add a bouncing colored cone"""   bl_idname = "object.bouncing_cone_add"   bl_label = "Bouncing Cone"   bl_description = "Add a bouncing cone"   bl_options = {'REGISTER', 'UNDO'}       scale = FloatVectorProperty(name='scale',      default=(1.0, 1.0, 1.0),      subtype='TRANSLATION',      description='scaling')   height = FloatProperty( attr='height',      name='Height', default = 1,      min = 0, soft_min = 0, max = 2,         description='Height of the cone')   radius = FloatProperty( attr='radius',      name='Radius', default = 0.5,      min = 0.001, soft_min = 0.001, max = 2,      description='Radius of the cone')   speed = FloatProperty( attr='speed',      name='Bounce speed', default = 1,      min = 0.5, soft_min = 00.5, max = 2,      description='Speed of the bouncing cone')   bounce_height = FloatProperty( attr='bounce_height',      name='Bounce height', default = 1,      min = 0, soft_min = 0, max = 2,      description='Height of the bouncing cone')   r = FloatProperty( attr='red',      name='Red', default = 0.5,      min = 0, soft_min = 0, max = 1,      description='Red')   g = FloatProperty( attr='green',      name='Green', default = 1,      min = 0, soft_min = 0, max = 1,      description='Green')   b = FloatProperty( attr='blue',      name='Blue', default = 0.5,      min = 0, soft_min = 0, max = 1,      description='Blue')   def draw(self, context):    layout = self.layout    col = layout.column()    col.prop(self, 'height')    col.prop(self, 'radius')    col.label(text='Material color:')    row = layout.row()    row.prop(self, 'r')    row.prop(self, 'g')    row.prop(self, 'b')    col = layout.column()    col.label(text='Bounce properties:')    col.prop(self, 'speed')    col.prop(self, 'bounce_height')    col.prop(self, 'location')    col.prop(self, 'rotation')       def execute(self, context):    addBouncingCone(self, context)    return {'FINISHED'}  def menu_func(self, context):   self.layout.operator(Bouncing_Cone.bl_idname,         icon='MESH_CONE')  def register():   bpy.utils.register_module(__name__)   bpy.types.INFO_MT_add.append(menu_func)  def unregister():   bpy.utils.unregister_module(__name__)   bpy.types.INFO_MT_add.remove(menu_func)  if __name__ == "__main__":   register()

The Bottom Line

Edit and run interactive scripts in Blender. Blender has its own internal text editor that you can use to write scripts or commentary. The text editor features line numbering and color-coded syntax highlighting.
Master It Get accustomed to working with the Blender text editor. Open operator_simple.py from the Templates menu in the text editor header. Run the script with the System Console visible. The names of all the 3D objects in the scene will be output to the console. Edit one line of the script so that the script outputs the names of only selected objects to the console.
Become familiar with the Blender-Python API. If you code in Blender Python, the API will become your faithful companion. A large part of learning to script for Blender is becoming comfortable navigating the API.
Master It An important step in using the API is to read the API itself and figure out what its various modules and classes do. Look over the API now. Which class would you use if you wanted to work with a Text object in the 3D space? What method would you use to set the text string for this object?
Design your own GUI with an interactive script. Blender’s Python API includes tools for designing graphical user interfaces for your scripts that enable you to set parameters and execute commands interactively.
Master It Add a new property to the bouncing cone add-on that enables you to interactively adjust the number of vertices in the base of the cone. At present, there are 10 vertices. Make sure there is a reasonable minimum number of vertices, and remember that the value should be an integer.
Назад: Part IV: Blender-Python
Дальше: Part V: Mastering the Blender Game Engine

lookforrent
Буду знать! Оцените туристический портал lookfor.rent
JbnvJinge
12 month loans cash now cash loans in winchester tn cash advance in dubai
androidinfoSa
Знать достаточно свежие публикации у сфере планшетов и наблюдать презентации планшетов Андроид пользователи смогут на разработанном сайте запись телефонных звонков , который окажет помощь для Вас находиться в теме последних выпусков мировых марок в операционке Android и продажи задекларированной устройств. Популярный ресурс выдает потребителям совершенно популярные предметы обсуждения: мнение экспертов про телефоны, оценка пользователей, обновление, апки для персональному смартфону, ОС Андроид, ответы на популярные вопросы также различные основные содержание, какими интересуются регулярно. Стоит коротко увидеть новый телефон и выделить уникальные характеристики? Вовсе не AndroidInfo.Ru преград - у основной строчке возможно кликнуть модель либо ключевое слово затем одержать с вашего задания подходящую параграф совместно с фотоотчетом плюс описанием преобладающего функций. В случае если юзер есть несомненного ценителя выпусков смарт устройств по операционке Андроид Android , здесь регистрация поможет юзерам ни разу не выпустить каждую единую добавленную новость у области умных систем. Будет изобилие всего увлекательного также развивающего для всем ценителей инноваций новой эры.
Anciwhish
buying paper custom written papers
DbgvAmurn
dissertation research research methodology dissertation