Blender Scripting With Python (Sample)

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 24

BLENDER SCRIPTING

WITH PYTHON
Automate Tasks, Write Helper Tools, and
Procedurally Generate Models in
Blender 2.7
Early Release Version 1.0

Isabel Lupiani
Publisher Isabel Lupiani
Cover Art Isabel Lupiani
Graph Paper Background Used in Cover Art László Németh [CC0]
Editing, Production (All Chapters) Isabel Lupiani
Acquisition, Global/Developmental Editing (Chapters 1 to 4) Tyler Ortman
Developmental/Copy Editing (Chapters 1 to 4) Jan Cash
Production (Chapters 1 to 2) Riley Hoffman
Marketing, Book Description, Author Bio Amanda Hariri, Isabel Lupiani
Marketing Serena Yang
Technical Review (Chapters 1 to 3) Patrick Crawford

Copyright 2019 by Isabel Lupiani. All rights reserved.

No part of this publication may be reproduced, stored in a retrieval system, or transmitted


in any form or by any means—electronic, mechanical, photocopying, scanning, or other-
wise—without prior written permission of the publisher.
To James
Author Bio

Isabel Lupiani is a programmer, researcher, and Blender enthusiast who enjoys handcrafting 3D
models as much as pushing Blender to the limit with procedural generation and add-ons. She has
worked at several game studios as an AI and gameplay programmer, contributing to the develop-
ment of both PC and Xbox games. Her love of Blender has led to several research projects in the
areas of computer vision, VR, and 3D geometry, including a revolutionary add-on that procedur-
ally generates human face meshes from photographs. Isabel currently lives in Orlando, FL with
her family.
Contents at a Glance
Preface ------------------------------------------------------------------------------------------------------------------------------------ 1
Chapter 1: Getting Started on Blender Scripting ---------------------------------------------------------------------------------- 2
Chapter 2: Getting Started with Operators and Add-ons ------------------------------------------------------------------------ 19
Chapter 3: Mesh Modeling Basics -------------------------------------------------------------------------------------------------- 52
Chapter 4: Advanced Mesh Modeling ---------------------------------------------------------------------------------------------- 85
Chapter 5: Procedurally Generating Stylized Fire Hydrants ------------------------------------------------------------------ 125
Chapter 6: Sculpting and Retopology -------------------------------------------------------------------------------------------- 140
Chapter 7: UV Mapping ------------------------------------------------------------------------------------------------------------ 173
Chapter 8: Texture Painting (Not Yet Available) ------------------------------------------------------------------------------ 215
Chapter 9: Showcasing and Publishing Your Add-ons and Scripts (Not Yet Available) -------------------------------- 215
Index (Not Yet Available) ---------------------------------------------------------------------------------------------------------- 215

Detailed Contents
Preface ------------------------------------------------------------------------------------------------------------------------------------ 1
Intended Audience ------------------------------------------------------------------------------------------------------------------- 1
Resources------------------------------------------------------------------------------------------------------------------------------ 1
Chapter 1: Getting Started on Blender Scripting ---------------------------------------------------------------------------------- 2
Introduction to Blender’s Scripting Interfaces ---------------------------------------------------------------------------------- 2
Convenience Variables ---------------------------------------------------------------------------------------------------------- 4
Automatic Import and Autocomplete ----------------------------------------------------------------------------------------- 4
Example: Move Mesh Vertices in the Viewport with the Python Console --------------------------------------------- 6
Transferring Console Contents into a Script --------------------------------------------------------------------------------- 8
Editing and Running Script Files ---------------------------------------------------------------------------------------------- 9
Displaying Operator Calls in the Info Area ------------------------------------------------------------------------------ 12
Displaying Native Python Output in the Terminal ---------------------------------------------------------------------- 13
Using an IDE to Write Your Scripts ------------------------------------------------------------------------------------------ 14
Finding the Corresponding Script Function to a Command ----------------------------------------------------------------- 14
Finding Script Functions through Tooltips ---------------------------------------------------------------------------------- 14
Secondary Scripting Helper Menu -------------------------------------------------------------------------------------------- 16
Context-sensitive Search Box ------------------------------------------------------------------------------------------------- 18
Summary ----------------------------------------------------------------------------------------------------------------------------- 18
Chapter 2: Getting Started with Operators and Add-ons ------------------------------------------------------------------------ 19
Formulating a Plan to Automate a Task----------------------------------------------------------------------------------------- 19
Enabling and Disabling Add-ons ------------------------------------------------------------------------------------------------- 20
Locating Add-on Source Files Shipped with Blender ------------------------------------------------------------------------ 20
Template Files -------------------------------------------------------------------------------------------------------------------- 21
Overview Built-in Modules of the Blender API ---------------------------------------------------------------------------- 21
Basic Structure of Operators ------------------------------------------------------------------------------------------------------ 22
Adding an Operator or Add-on to a Menu -------------------------------------------------------------------------------------- 26
#1: Write a Method to Create the Menu Entry --------------------------------------------------------------------------- 27
#2: Find a Menu’s Corresponding Python Class in the Blender Python API --------------------------------------- 28
#3: Add the Entry to the Desired Menu ----------------------------------------------------------------------------------- 29
Adding a Pop-up Dialog to the Simple Operator ------------------------------------------------------------------------------ 31
Creating a Custom UI Panel in the Tool Shelf --------------------------------------------------------------------------------- 33
The bpy.types.Scene Data Block and Scene Variables ------------------------------------------------------------ 34
Defining Properties as Scene Variables -------------------------------------------------------------------------------------- 34
Creating Text Inputs with the StringProperty ---------------------------------------------------------------------------- 35
Creating Checkboxes with BoolProperty --------------------------------------------------------------------------------- 37
Creating Dropdown Lists with EnumProperty --------------------------------------------------------------------------- 37
Creating a Slider Widget with IntProperty or FloatProperty ---------------------------------------------------------- 38
Creating an Empty UI Panel at a Desired Screen Location --------------------------------------------------------------- 41
Assembling Properties inside the Empty Panel ----------------------------------------------------------------------------- 43
Setting Up and Cleaning Up Scene Variables Systematically ----------------------------------------------------------- 45
Testing the Sample Toolshelf Panel ------------------------------------------------------------------------------------------ 46
Peeking Under the Hood of Existing Blender UI Elements ----------------------------------------------------------------- 47
Finding the Python Class for a Menu Item from its Source File ------------------------------------------------------------ 48
Preparing Your Add-on for Publication ----------------------------------------------------------------------------------------- 49
Adding Metadata to bl_info ---------------------------------------------------------------------------------------------------- 49
Adding a License ---------------------------------------------------------------------------------------------------------------- 51
Chapter 3: Mesh Modeling Basics -------------------------------------------------------------------------------------------------- 52
Accessing a Mesh Object ---------------------------------------------------------------------------------------------------------- 52
Setting Object Interaction Modes and Selecting Objects -------------------------------------------------------------------- 53
Adding Built-in Primitive Shapes ------------------------------------------------------------------------------------------------ 55
Preventing Duplicate Built-in Objects ------------------------------------------------------------------------------------------ 56
Getting Object Locations and Moving Objects -------------------------------------------------------------------------------- 57
Adding Modifiers to Objects and Changing Modifier Settings ------------------------------------------------------------- 60
Creating New Mesh Objects ------------------------------------------------------------------------------------------------------ 63
Getting Started with BMesh------------------------------------------------------------------------------------------------------- 65
Accessing or Editing an Existing Mesh -------------------------------------------------------------------------------------- 65
Building a Mesh from Scratch ------------------------------------------------------------------------------------------------- 67
Using BMesh as a Mesh Sketch Pad ----------------------------------------------------------------------------------------- 69
Editing and Generating Meshes with BMesh ------------------------------------------------------------------------------- 71
Configuring Mesh Selection Modes --------------------------------------------------------------------------------------- 71
Adding, Removing, and Looking up Vertices, Edges, and Faces ---------------------------------------------------- 72
Moving Vertices, Edges, and Faces --------------------------------------------------------------------------------------- 75
Generating a Simple Barrel from Scratch --------------------------------------------------------------------------------------- 80
Generating the Circular Top, Bottom, and Cross-Sections of the Barrel ----------------------------------------------- 80
Generating a Barrel using Circular Cross Sections ------------------------------------------------------------------------ 81
Summary ----------------------------------------------------------------------------------------------------------------------------- 84
Chapter 4: Advanced Mesh Modeling ---------------------------------------------------------------------------------------------- 85
A Couple Things Before We Start… -------------------------------------------------------------------------------------------- 85
BMesh vs. bpy.ops.mesh Operators for Mesh Editing -------------------------------------------------------------------- 85
Using bmesh.ops Operators to Create Primitive Geometric Shapes ------------------------------------------------- 88
Editing Meshes with Edge Loops ------------------------------------------------------------------------------------------------ 89
Selecting Edge Loops and Rings ---------------------------------------------------------------------------------------------- 90
Bridging Edge Loops------------------------------------------------------------------------------------------------------------ 94
Generating a Stack of Edge Loops ----------------------------------------------------------------------------------------- 94
Bridging Edge Loops Utilizing Built-in Operators --------------------------------------------------------------------- 96
Extruding Edge Loops ---------------------------------------------------------------------------------------------------------- 98
Extrusion Using bpy Operator ---------------------------------------------------------------------------------------------- 99
Extrusion by Moving a Copy of the Loop and Connecting to it ---------------------------------------------------- 100
Loop Cut-and-Slides ---------------------------------------------------------------------------------------------------------- 102
Overriding Context --------------------------------------------------------------------------------------------------------- 103
Merging and Splitting Mesh Elements ---------------------------------------------------------------------------------------- 106
Merging Vertices -------------------------------------------------------------------------------------------------------------- 106
Ripping Vertices --------------------------------------------------------------------------------------------------------------- 109
Splitting and Joining Faces --------------------------------------------------------------------------------------------------- 111
Rotating and Scaling Mesh Objects (Object Mode) ------------------------------------------------------------------------ 113
Rotating and Scaling Mesh Data (Edit Mode) ------------------------------------------------------------------------------- 115
Rotating Individual Edges ---------------------------------------------------------------------------------------------------- 115
Rotating and Scaling a Selection on a Mesh ------------------------------------------------------------------------------ 116
Beveling Edges and Vertices --------------------------------------------------------------------------------------------------- 117
Insetting Faces --------------------------------------------------------------------------------------------------------------------- 119
Accessing and Editing Normals ------------------------------------------------------------------------------------------------ 121
Cleaning Up - Removing Doubles and Loose Vertices -------------------------------------------------------------------- 122
Chapter 5: Procedurally Generating Stylized Fire Hydrants ------------------------------------------------------------------ 125
Generating Stylized Fire Hydrants --------------------------------------------------------------------------------------------- 125
Designing the Generation Algorithm --------------------------------------------------------------------------------------- 125
Breaking the Generation into Stages ------------------------------------------------------------------------------------ 125
Deciding which Parameters Should be Adjustable -------------------------------------------------------------------- 127
Generating the Base ----------------------------------------------------------------------------------------------------------- 129
Adding the Pole and Top Band ---------------------------------------------------------------------------------------------- 131
Adding the Dome and the Basis for the Cap ------------------------------------------------------------------------------ 133
Shaping the Cap ---------------------------------------------------------------------------------------------------------------- 135
Adding Details and Finishing Up ------------------------------------------------------------------------------------------- 136
Configuring Viewport Display Options --------------------------------------------------------------------------------- 137
Generating a Variety of Fire Hydrants by Changing the Parameters ------------------------------------------------- 138
Chapter 6: Sculpting and Retopology -------------------------------------------------------------------------------------------- 140
Making Grease Pencil Based Sculpting Tools ------------------------------------------------------------------------------- 140
Adding Imports and bl_info for the Add-on ------------------------------------------------------------------------------ 141
Accessing & Configuring Grease Pencil in Python ---------------------------------------------------------------------- 141
Implementing the Carve Operator ------------------------------------------------------------------------------------------ 144
Using Grease Pencil Strokes to Knife Project ------------------------------------------------------------------------- 144
Carving the Hole using the Boolean Modifier’s Difference Operation -------------------------------------------- 147
Implementing the In/Outset Operator -------------------------------------------------------------------------------------- 149
Adding User Interface and Setup Code for the Add-on ----------------------------------------------------------------- 151
Automating the Setup of Reference Images for Sculpting ----------------------------------------------------------------- 153
Modeling References as Background Images ----------------------------------------------------------------------------- 153
Modeling References as Image Empties ----------------------------------------------------------------------------------- 155
Retopology ------------------------------------------------------------------------------------------------------------------------- 158
Making a “Draw Grid” Retopo Helper Tool ------------------------------------------------------------------------------ 159
Analyzing Mesh Topology Using BMesh Connectivity Data ---------------------------------------------------------- 165
Accessing a Vertex’s Connected Edges through BMesh ------------------------------------------------------------ 165
Finding Poles through Vertices’ Link Edges --------------------------------------------------------------------------- 166
Finding Sharp (or Dull) Face Corners ----------------------------------------------------------------------------------- 168
Summary --------------------------------------------------------------------------------------------------------------------------- 171
Chapter 7: UV Mapping ------------------------------------------------------------------------------------------------------------ 173
Before Unwrapping: Marking Seams------------------------------------------------------------------------------------------ 173
How do Seams Work? -------------------------------------------------------------------------------------------------------- 173
Impact of Seams on the Quality of UVs -------------------------------------------------------------------------------- 174
UV Mapping in Blender by Hand ---------------------------------------------------------------------------------------------- 175
Automating the UV Mapping Process----------------------------------------------------------------------------------------- 176
Downloading, Configuring, and Running the Sample Code for Chapter 7 ------------------------------------------ 176
Applying Modifiers in Python ----------------------------------------------------------------------------------------------- 177
Marking Seams from Script Function -------------------------------------------------------------------------------------- 179
Example: Marking Seams on a Cube ------------------------------------------------------------------------------------ 180
Generating and Seaming Box-Shaped Objects ------------------------------------------------------------------------ 183
Opening a UV/Image Editor using Script Functions--------------------------------------------------------------------- 184
Splitting Screen Area ------------------------------------------------------------------------------------------------------ 184
Maximizing a Screen Area ------------------------------------------------------------------------------------------------ 186
Configuring Commonly Used Settings for UV Mapping --------------------------------------------------------------- 188
Context-sensitive UI in the UV/Image Editor ------------------------------------------------------------------------- 189
Getting References to the UV/Image Editor --------------------------------------------------------------------------- 191
Stretch Color View --------------------------------------------------------------------------------------------------------- 193
Live Unwrap ----------------------------------------------------------------------------------------------------------------- 195
Keeping UV and Edit Mode Mesh Selection in Sync ---------------------------------------------------------------- 196
Fitting UV Image to View ------------------------------------------------------------------------------------------------ 197
Configuring UV Settings in General --------------------------------------------------------------------------------------- 199
Tooltip Category #1: Python: SpaceImageEditor.<setting> -------------------------------------------------------- 200
Tooltip Category #2: Python: SpaceUVEditor.<setting> ----------------------------------------------------------- 201
Tooltip Category #3: Python: ToolSettings.<setting> --------------------------------------------------------------- 202
Unwrapping the Model ------------------------------------------------------------------------------------------------------- 203
Example: Automatically Unwrap the UVs of a Cube Mesh --------------------------------------------------------- 203
Visualizing Unwrapped UVs on the Model ---------------------------------------------------------------------------------- 205
Creating a New Image Data Block------------------------------------------------------------------------------------------ 205
Configuring Viewport Settings for Displaying Texture on Model using Unwrapped UVs ----------------------- 207
Saving UVs and Images to File------------------------------------------------------------------------------------------------- 209
Saving Image Data Blocks to File ------------------------------------------------------------------------------------------ 209
Packing Image Files into *.blend File -------------------------------------------------------------------------------------- 210
Exporting UV Layouts to File ----------------------------------------------------------------------------------------------- 213
Chapter 8: Texture Painting (Not Yet Available) ------------------------------------------------------------------------------ 215
Chapter 9: Showcasing and Publishing Your Add-ons and Scripts (Not Yet Available) -------------------------------- 215
Index (Not Yet Available) ---------------------------------------------------------------------------------------------------------- 215
Excerpt from Chapter 2: Getting Started with Operators and Add-ons

Creating a Slider Widget with IntProperty or FloatProperty

Sometimes it might make sense to let users of your add-on specify a setting in whole number in-
crements, such as the number of subdivisions or number of edge loops to cut. IntProperty is
designed for this very purpose. When displayed inside a UI panel, an IntProperty instance
shows up as a slider widget that doubles as an input box that lets you enter a number, as shown
in Figure 2-8. The following code snippet shows how you can initialize an IntProperty:

sample_panel_tool_shelf.py

def init_scene_vars():
-- SNIP --
bpy.types.Scene.sample_int = bpy.props.IntProperty(
name = "Integer",
description = "Sample integer input.",
default = 30,
min = 20,
max = 40)

Figure 2-8: The widget corresponding to bpy.types.Scene.sample_int

You’ll see when the property is first loaded it shows the default value of 30. The min value
of 20 and max value of 40 are not displayed on the widget itself, but when the user drags the (im-
plicit) slider, the farthest it will go to the left is 20, and the farthest it will go to the right is 40. If
the user tries to enter a number out of bounds, it will automatically be clamped.
In addition to having min and max values, which are referred to as hard minimum and maxi-
mum values, the slider can have soft minimum and maximum values that are set with the varia-
bles soft_min and soft_max. You might be wondering what the difference is between the two.
The soft_min and soft_max values show up as the lower and upper constraints on the slider
widget so the user can’t slide it past either end, however, the user can still enter a value outside
this range to forcefully set a number lower or higher than the range. For example, if you set
soft_min = 20 and soft_max = 40, the user can’t slide the widget to the left past 20 or to the

1|P age
right past 40, however, he/she can still enter 55. On the other hand, min and max pose rigid lim-
its—a user can’t slide the widget past either end nor enter a number outside the range. For exam-
ple, if you set min = 20 and max = 40, and a user enters 55, the entered value would be auto-
matically clamped to 40, which is the nearest limit. The min/max and soft_min/soft_max values
also don’t need to be specified in pairs—you can specify only one end of the range and leave the
other open.
It’s worth mentioning that you can create a percentage slider widget just by adding the sub-
type 'PERCENTAGE' to an IntProperty instance:

sample_panel_tool_shelf.py

def init_scene_vars():
-- SNIP --
bpy.types.Scene.sample_int_pcrt = bpy.props.IntProperty(
name = "Percentage",
description = "Sample integer percentage input.",
default = 50,
min = 10,
max = 100,
subtype = 'PERCENTAGE')

Code-wise this widget is set up like bpy.types.Scene.sample_int from the previous ex-
ample, except that there is an additional subtype specified as 'PERCENTAGE' , which adds a
percentage sign (%) to the right of the input field in the widget. The background of the widget is
a darker grey starting from the left end, and grows toward the right as the percentage value in-
creases.
Instead of whole number increments, sometimes it makes more sense to allow users to enter
decimal values for a setting, such as for the strength of a sculpting brush, or the scaling factor for
a mesh selection. A FloatProperty instance creates a slider widget that supports decimal num-
bers:
sample_panel_tool_shelf.py

def init_scene_vars():
-- SNIP --
bpy.types.Scene.sample_float = bpy.props.FloatProperty(
name = "Float",
description = "Sample float input.",
default = 0.0,

2|P age
soft_min = -5.0,
soft_max = 5.0)

You’ll notice the arguments and widget of a FloatProperty are nearly identical to an
IntProperty. The only difference is that the numerical arguments and user input can have deci-
mal points.
Next we’ll create an empty UI panel in the tool shelf that will later be used to house these
properties.

Creating an Empty UI Panel at a Desired Screen Location

In the following code snippet, an empty UI panel is created through a class that derives from the
built-in type bpy.types.Panel.

sample_panel_tool_shelf.py

class SamplePanelToolShelf(bpy.types.Panel):
bl_label = "Sample Panel"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = 'Tools'
"""Sample UI panel located in the Tool Shelf/Tools tab."""

There are several metadata fields that must be defined for the panel to render and function
properly. bl_label specifies the name shown at the top of the panel. The next three fields,
bl_space_type, bl_region_type, and bl_category define a nested hierarchy of screen spaces
(from outer to inner most, and from largest to smallest), that together define the location of the
panel. For example, the 3D viewport is a bl_space_type that encloses the tool shelf which is a
bl_region_type (T key), which in turn encloses the Tools tab (a bl_category). See Figure 2-9
for a visualization of how these screen areas fit together.

Figure 2-9: Defining a panel’s location using metadata

3|P age
Excerpt from Chapter 3: Mesh Modeling Basics

Generating a Barrel using Circular Cross Sections

Next we’ll add the method generate_barrel shown in Listing 3-10 to generate a barrel mesh
by making edge loops defining the barrel’s cross sections using add_circle, then bridging the
loops to form the barrel’s silhouette. Add this code after the add_circle method in the script.

creating_and_editing_mesh_objs.py

def generate_barrel(context, name, radius_end, radius_mid, height, num_segments, \


center = Vector((0, 0, 0))):

bm, barrel_obj = get_placeholder_mesh_obj_and_bm(bpy.context, 'barrel_obj', center) 

bottom_cap_verts = add_circle(bm, radius_end, num_segments, -height/2) 


add_circle(bm, radius_mid, num_segments, 0)
top_cap_verts = add_circle(bm, radius_end, num_segments, height/2)

bm.faces.new(top_cap_verts) 
bm.faces.new(bottom_cap_verts)

bmesh.ops.bridge_loops(bm, edges = bm.edges) 


bmesh.ops.recalc_face_normals(bm, faces = bm.faces) 

bpy.ops.mesh.select_all(action = 'SELECT')

bpy.ops.mesh.subdivide(smoothness = 1.1) 

bmesh.update_edit_mesh(barrel_obj.data)
context.scene.update()

Listing 3-10: Generating a simple barrel shape from scratch using BMesh

The method creates a blank mesh object barrel_obj and a BMesh instance bm for editing it
using get_placeholder_mesh_obj_and_bm from Listing 3-6 . Then three edge loops defining
the bottom, middle, and top cross sections of the barrel are added via bm using add_circle from
Listing 3-9 . The end cap faces are filled in  then the three cross sections are bridged to-
gether using the built-in operator bmesh.ops.bridge_loops . The normals are recalculated
next  to ensure they’re consistent (all facing outward). Then, we subdivide the barrel using
bpy.ops.mesh.subdivide with a smoothness of 1.1  (by first selecting all since the operator
performs its action on the current selection).
Once you have the method written, you can call it in your script like this:

4|P age
creating_and_editing_mesh_objs.py

generate_barrel(bpy.context, 'test_barrel', radius_end = 3, radius_mid = 5, \


height = 10, num_segments = 16, center = Vector((0, 0, 5)))

Listing 3-11: Example of calling method generate_barrel from Listing 3-9

This creates a 10-unit-tall barrel centered at (0, 0, 5) with 16 segments, end caps with ra-
dius 3, and a mid-section of radius 5 as shown in Figure 3-10.

Figure 3-10: Result of running Listing 3-11. 1. Edge loops defining the cross sections are added using
add_circle (Listing 3-9). 2. The top and bottom faces are filled in. 3. Edge loops are bridged and nor-
mals corrected. 4. Mesh is subdivided with a smoothness of 1.1.

5|P age
Excerpt from Chapter 5: Procedurally Generating Stylized Fire Hydrants

Figure 5-9: Shaping the cap. The numbering in the figure corresponds to the Wingdings in Listing 5-4

Adding Details and Finishing Up

As we continue into the final part of the method gen_stylized_fire_hydrant shown in the fol-
lowing snippet, our goals are to add finishing touches to the model with inset details and config-
ure the viewport display options.

mesh_editing_ops.py

bmesh.ops.inset_region(bm, faces = face_loop_pole_top, thickness = 0.3, depth = 0.1) 


bmesh.ops.inset_individual(bm, faces = face_loop_pole_bottom, thickness = 0.2, depth = -0.1)


bmesh.ops.inset_region(bm, faces = face_loops_dome, thickness = 0.1, depth = -0.15) 

bmesh.ops.recalc_face_normals(bm, faces = bm.faces) 


bmesh.update_edit_mesh(fh_obj.data)
bpy.ops.object.mode_set(mode = 'OBJECT')

bpy.ops.object.select_all(action = 'SELECT') 
bpy.ops.object.shade_smooth()
bpy.ops.object.select_all(action = 'DESELECT')

config_viewport_shading(context) 
bpy.context.scene.update()

Listing 5-5: Method gen_stylized_fire_hydrant, part 5 of 5, adding detail to top band, pole & dome

6|P age
We’ll start by adding details to the dome, top band, and pole. First we add an outset (with a
depth > 0) to the top band to give it a rounded look  (recall that we recorded the list of faces
face_loop_pole_top in Listing 5-2), then we add an inset to every other segment of the pole’s
bottom-most face loop  (see face_loop_pole_bottom in Listing 5-2)). Finally, we add insets
to every other segment of the dome  (see face_loops_dome in Listing 5-3). Notice that
bmesh.ops.inset_region is used for  so the faces that belong to the same segment of the
dome across the different horizontal face loops are automatically grouped together for the insets.
We wrap up the generation by re-computing normals  to ensure they’re all facing outward,
then set all objects to shade smooth  (in Object mode, select all (A) then Tool shelf (T)Tool
tabShading: Smooth) and use the method config_viewport_shading (Listing 5-6, below) 
which we’ll look at shortly in the next section to configure viewport display options.

Configuring Viewport Display Options

To make the details on the generated models easier to see, I put together the method con-
fig_viewport_shading to configure the viewport display settings as shown in the following
snippet.

mesh_editing_ops.py

def config_viewport_shading(context):
for a in context.window.screen.areas:
if a.type == 'VIEW_3D':
for s in a.spaces:
if s.type == 'VIEW_3D': 
s.viewport_shade = 'SOLID' 
s.show_textured_solid = True 
s.fx_settings.use_ssao = True 
s.show_floor = False 
s.show_axis_x = False 
s.show_axis_y = False

Listing 5-6: Configuring viewport shading and turn off grid

The method iterates through the screen areas until it finds the viewport , then through
which sets Viewport Shading to Solid , and under Properties shelf (N)Shading checks the
Texture Solid  and Ambient Occlusion  boxes to increase the contrast of light and shadow to
make the bumps and cavities on the models easier to see. Next, the grid floor  and gird X/Y
axes lines  in the viewport are turned off to prevent cluttering the view, which are equivalent to

7|P age
unchecking the Grid Floor box and toggling the X and Y buttons under Properties shelf
(N)Display.

Generating a Variety of Fire Hydrants by Changing the Parameters

The following is a method I put together which creates eight different fire hydrants using
gen_stylized_fire_hydrant with various parameters.

mesh_editing_ops.py

def test_gen_fire_hydrant():

gen_stylized_fire_hydrant(bpy.context, location = (15, -12, 0)) 


gen_stylized_fire_hydrant(bpy.context, location = (5, -12, 0), subsurf = True) 
gen_stylized_fire_hydrant(bpy.context, location = (-5, -12, 0), \

pole_diameter = 2, num_pole_levels = 2, num_dome_levels = 3) 


gen_stylized_fire_hydrant(bpy.context, location = (-13, -12, 0), \

pole_diameter = 1, num_pole_levels = 6, num_dome_levels = 5) 


gen_stylized_fire_hydrant(bpy.context, location = (15, 0, 0), stylize = True) 
gen_stylized_fire_hydrant(bpy.context, location = (5, 0, 0), stylize = True, \

subsurf = True) 
gen_stylized_fire_hydrant(bpy.context, location = (-5, 0, 0), \

pole_diameter = 2, num_pole_levels = 2, num_dome_levels = 3, stylize = True) 


gen_stylized_fire_hydrant(bpy.context, location = (-13, 0, 0), \
pole_diameter = 1, num_pole_levels = 6, num_dome_levels = 5, \

stylize = True, pole_bent_factor = 2, dome_bent_factor = 1.5) 

Listing 5-7: Generating a variety of fire hydrants with gen_stylized_fire_hydrant

Model  is model  with two levels of subsurf division added. Models  through  are the
stylized counterparts of models  through , respectively. You can also see that the zig-zag in
the pole and dome of  is more pronounced than , , and  since  uses pole_bent_fac-
tor and dome_bend_factor that are larger. You can see the results of running Listing 5-7 in
Figure 5-10.

8|P age
Figure 5-10: Various fire hydrants generated by running Listing 5-7

9|P age
Excerpt from Chapter 6: Sculpting and Retopology

Implementing the In/Outset Operator

My second inspiration from Sculpt Tools UI is the “mesh extract” feature which automatically
creates a new mesh based on the masked region on a model, as if you’ve pulled the mask out into
a separate mesh and added thickness to it. This is handy when you need to create an accessory or
appendage that conforms to a model’s contour. Since “mesh extract” already provides the func-
tionality for creating a detached extrusion, I decided to make an operator that creates an attached
outset (or indent) from the user-drawn grease pencil outline on the mesh. I call this operator
In/Outset and its operator class BUTTON_OT_inset is shown in the following snippet.

sculpt_retopo_toolkit.py

class BUTTON_OT_inset(Operator):
bl_idname = 'button.inset'
bl_label = 'Inset'
'''Inset'''

def execute(self, context):

knife_project_success, mode_to_restore = gp_knife_project(context) 


if knife_project_success:
bpy.ops.mesh.extrude_region_move(TRANSFORM_OT_translate = \

{'value': Vector((0, 0, 0))}) 


bpy.ops.transform.shrink_fatten(value = context.scene.inoutset_amount) 
bpy.ops.object.mode_set(mode = mode_to_restore) 
self.report({'INFO'}, 'Sculpt & Retopo Toolkit: In/Outset.')
return {'FINISHED'}

def invoke(self, context, event):


return self.execute(context)

Listing 6-6: The In/Outset operator for our Sculpting and Retopo Toolkit add-on

We start by using the GP Strokes to Knife Project on the active object (Listing 6-3) . If the
cut is successful, with the portion of the mesh enclosed by the cut still selected, we create the (in)
outset by extruding the selection in place  then scale the extrusion along normals  by the off-
set specified by the user through a FloatProperty (which we’ll look at shortly). Lastly, we fin-
ish by switching the active object back to the mode it was in before  (recall we saved a copy of
the mode (string) in Listing 6-3).
To make the amount of (in)outset adjustable by the user, we create a FloatProperty as
shown in the following snippet, which creates a slider widget for entering decimal numbers (that

10 | P a g e
you can also type in). Add the code to the end of the init_scene_vars method from Listing 6-4
or find it there.
sculpt_retopo_toolkit.py

bpy.types.Scene.inoutset_amount = FloatProperty(
name = 'In/Outset Amount',
description = 'Amount to inset(+) or outset(-).',
default = 0.1)

Listing 6-7: FloatProperty for specifying the amount to (in)outset for the In/Outset Operator (Listing 6-6)

We inform users through description (which populates the contents of the tooltip when
you hover over the widget) that a positive value creates an inset whereas a negative one creates
an outset, and set the default value to 0.1. Examples of using the In/Outset operator with differ-
ent values for In/Outset Amount and the Cut Through checkbox are shown in Figure 6-5.

Figure 6-5: Examples of using the In/Outset operator with In/Outset Amount of -0.1 (top) and 0.1 (middle)
with Cut Through unchecked, and -0.15 (bottom) with Cut Through checked

11 | P a g e
Excerpt from Chapter 7: UV Mapping

Creating a New Image Data Block

When you press the +NEW button at the bottom of the UV/Image Editor, it creates a new image
data block. Data blocks are the basic units of data in Blender and primary building blocks of
*.blend files. They come in many different varieties such as meshes, objects, materials, etc. The
image data blocks are stored at the *.blend file level in bpy.data.images, and you can look up
an image by name like this,

bpy.data.images[<name>]

You can write a function to create an image data block like create_image_data_block
shown in the snippet below, which is from the file Ch7/create_and_save_images.py (see section
“Downloading, Configuring, and Running the Sample Code for Chapter 7” on page 176 on how
to obtain and setup the file).

create_and_save_images.py

def create_image_data_block(context, name, type='UV_GRID', color=(0, 0, 0, 1)):

if bpy.data.images.find(name) < 0:


bpy.data.images.new(name=name, width=1024, height=1024, alpha=True, \

float_buffer=False, stereo3d=False)

bpy.data.images[name].generated_color = color

bpy.data.images[name].generated_type = type

split_screen_area(context, 'VERTICAL', 0.5, 'IMAGE_EDITOR', True)

image_editor, uv_editor = get_image_and_uv_editors(context)

image_editor.image = bpy.data.images[name]

image_editor_context_override = get_context_override(context, 'IMAGE_EDITOR', 'WINDOW')

bpy.ops.image.view_all(image_editor_context_override, fit_view=True)

The method checks if an image with the given name already exists, and if not (find returns -
1) , uses the built-in function bpy.data.images.new to create a new image data block with
the given name, while leaving the rest of the parameters at default values —the same values
pre-filling the box that pops up when you click ImageNew Image at the bottom of the UV/Im-
age Editor, as shown in Figure 7-22. Two of the parameters, Color  and Generated Type ,
cannot be configured by the call to bpy.data.images.new and need to be set after the fact
through the image data block itself. Color is configured through a 4-tuple of RGB-Alpha values
, for example, red with opacity at 50% is (1, 0, 0, 0.5), while type can be either 'BLANK',

12 | P a g e
'UV_GRID', or 'COLOR_GRID'. The current screen area is split vertically half way to create a new
UV/Image Editor, if one doesn’t already exist . The method uses get_image_and_uv_editors
from Listing 7.3 to get a reference to the SpaceImageEditor object image_editor tied to the
first open UV/Image Editor area found , and sets the newly created image data block as the ac-
tive image for that area . The method finishes by adjusting zoom on the active image so it fits
the current size of the UV/Image Editor  (ViewView Fit or SHIFT-HOME). Note that the ap-
propriate context override  has to be passed to bpy.ops.image.view_all so Blender knows to
perform the zoom in the right area, in this case the UV/Image Editor.

Figure 7-22: Mapping of script parameters to new image block creation

For instance, going back to our cube unwrap example from the section “Example: Automati-
cally Unwrap the UVs of a Cube Mesh”, after generating, seaming, and unwrapping the cube,
you’d simply call create_image_data_block to create a texture, like this,

generate_and_seam_cube(bpy.context, 'test_cube', 2, (0, 0, 0))


unwrap_model(bpy.context, 'test_cube', 2)
create_image_data_block(bpy.context, 'test_uv_grid_texture')

Listing 7.5: Creating a texture image data block after generating, seaming, and unwrapping a cube.

The result of running Listing 7.5 is shown in Figure 7-23.

13 | P a g e
Figure 7-23: Results of running code Listing 6.5

14 | P a g e

You might also like