Python & Blender

Designing for 3D Printing

An Edmonton.py presentation by
Chris Want / cjwant@gmail.com / @cwant

Road map

  • Talk about Blender in general
  • Modeling meshes
  • Python scripting
  • Exporting for 3D printing
  • Common issues
  • ShapeWays 3D printing service bureau

But first, a short bio ...

  • MSc in Math (U of A, long time ago)
  • Previously a scientific visualization analyst at the U of A, lead the U of A's central 3D printer for almost 10 years (ZCorp, plaster based).
  • Former Blender developer (semi-retired)
  • Currently work for WestGrid, an HPC consortium

Blender

From the Blender website:

“Blender is a free and open source 3D animation suite. It supports the entirety of the 3D pipeline—modeling, rigging, animation, simulation, rendering, compositing and motion tracking, even video editing and game creation”
  • Blender is released under a GPL license
  • Python scripting through a rich API
  • Recommended:
    • Keyboard with a numpad
    • Three button mouse with a scrollwheeel
    • Best graphics card you can afford

Python

Three ways to access python

  • Built in text editor
  • The python console
  • Installed scripts that show up in the menus

We'll run our scripts through the text editor

Execute with Alt-P while your mouse is in the editor

Operators

Most of the modeling is done through the menus or through hot keys. These execute bits of code called "operators". The Python API maps well to these operators.

Check out the tooltips

bpy module and some of it's parts

  • bpy.types: The main data classes for the objects in Blender
  • bpy.data: Access to data within the program
  • bpy.ops: Operators, e.g., things you might find in menus
  • bpy.context: State of the program, for example the current view or scene

Objects and their data

An object is defined by the type of data it points to, e.g., mesh, camera, lamp, curve, text ...


>>> ob = bpy.data.objects["Profile"]
>>> ob.data
bpy.data.meshes["Plane"]
					

>>> ob2 = bpy.data.objects["Camera"]
>>> ob2.data
bpy.data.cameras["Camera"]
					

Modeling Meshes

Typically meshes are modeled in "Edit Mode".

Meshes are made of vertices, edges, and faces

Mesh data structures

Think of vertices as a zero-based list of coordinates

Think of faces/edges as pointers into the list of vertices

Vertices


# A list of 3D coordinates
verts = [
  [1, 1, 0],
  [1, -1, 0],
  [-1, -1, 0],
  [-1, 1, 0]
]
							

Edges


# List the verts to connect
edges = [
  [0, 1],
  [1, 2]
]
							

Faces


# List the verts to span
faces = [
  [0, 2, 3]
]
							

bpy.types.Mesh.from_pydata


# The magic is done by:
#   bpy.types.Mesh.from_pydata
me = bpy.data.meshes.new("me")
me.from_pydata(verts,
               edges,
               faces)
ob = bpy.data.objects.new("ob",
                          me)
scn = bpy.context.scene
scn.objects.link(ob)
# Not needed
scn.objects.active = ob
ob.select = True
							

Profile to solid

edpy1.1.blend

Specification

To create the shape, we must specify:

  • Profile shape (with numverts vertices, connected by edges)
  • Radius
  • Resolution
  • Amplitude
  • Cycles (peaks/valleys)

Implementation, part 1

Copy numverts vertices mulitple times, based on resolution

Implementation, part 2

Old edges become new faces.

Exploit the fact that we are connecting vertices who's indices are numverts apart.

Part 1: modules and globals


import bpy
from math import sin, cos, pi

num_cycles = 4
resolution = 64
radius = 5
amplitude = 1
					

Part 2: setup


def main():
  oldob = bpy.data.objects["Profile"]
  if oldob == None:
    return

  oldme = oldob.data

  numvert = len(oldme.vertices)
  numedge = len(oldme.edges)
  numface = len(oldme.polygons)

  verts = []
  faces = []
					

Part 3: main loop


###### ... main() cont'd
  for i in range(resolution):
    for j in range(numvert):
      # Duplicate and transform vertices
      vold = oldme.vertices[j].co
      vnew = transform_vert(vold, i)
      verts.append(vnew)

    # Extrude old edges into new faces
    for j in range(numedge):
      if oldme.edges[j].is_loose:
        e = oldme.edges[j].vertices
        f = edge_to_face(e, i, numvert)
        faces.append(f)
					

Part 4: creating the new mesh


###### ... main() cont'd
  me = bpy.data.meshes.new("thingy")
  me.from_pydata(verts, [], faces)
  ob = bpy.data.objects["thingy"]
  ob.data = me
					

Part 5: transforming the vertices


def transform_vert(v, i):
  prop = float(i) / float(resolution)
  a = 2*pi*prop
  b = a * num_cycles
  cosa = cos(a)
  sina = sin(a)
  sinb = sin(b)
  x =  (v[0] + radius) * cosa + v[1] * sina
  y = -(v[0] + radius) * sina + v[1] * cosa
  z = v[2] + sinb * amplitude

  return [x, y, z]    
					

Part 6: old edges become new faces


def edge_to_face(e, i, numvert):
  i1 = i
  i2 = (i + 1) % (resolution)

  f = [e[0] + i1*numvert,
       e[1] + i1*numvert,
       e[1] + i2*numvert,
       e[0] + i2*numvert]

  return f
					

Part 7: call main

(duh)


main()
					

Printability

Manifold Surfaces

The interior must be clearly defined

Printability

Fragility

Printability

Faceting

The subdivision surface modifier is your friend!

Export

From the File/Export menu ...

Recommendations:

  • STL (Stereolithography) for monochrome
  • X3D for color
  • Think about the size of your object before exporting

Service Bureau

I use ShapeWays, because:

  • Material selection
  • Price
  • Turnaround
  • Buy or Sell (Shops)

Example 1: Charms

  • Lost wax casting
  • Polished silver
  • $111 USD (incl. shipping)
  • $16 brokerage
  • 23 days

Example 2: Rings

  • Stainless steel, gold plated steel, raw brass, raw bronze
  • $76.60 USD
  • Free shipping!
  • 15 days

Another form of tangible output ...

Laser Crystal Awards

  • Etched clear plastic
  • 2 inch cube: $20
  • Light base: $20
  • Shipping: $20
  • Order multiples to reduce average cost

More information ...

Thanks!

Questions?