Python Based Inset Tool (Blender 2.5)

Hi all,
This is my first post here. I’ve been using Blender for a while and have always found the lack of an inset/offset tool a bit frustrating. I’ve had a crack at writing one myself but Python coding is still relatively new to me and I would appreciate any feedback on my script. Note that this script must be used with Blender 2.5.
It has a few limitations listed below;

  • Currently can only be used for a single face
  • Can only be used on faces with convex edge loops

To use the script;

  • Go into edit mode and select a face
  • Extrude the face 0 units (e-key, esc)
  • Set the Inset value in the script and run it

from bpy import *
import mathutils

inset = 0.3 #this defines the distance the edges will be moved inwards

obj = #the active object

faces = []
edges = []
verts = []
vertNums = []
edgeVecs = []
edgeReq = []
vertEdges = []
vertEdgesSign = []
listTemp = []
listTemp2 = []

bpy.ops.object.editmode_toggle() #shift out of edit mode

for f in obj.faces: #here all the selected objects faces are looped through to determine which are selected
    if f.selected == True:
        faceNormal = f.normal #face normal is recorded

for e in obj.edges: #all edges are looped through to see which are selected
    if e.selected == True:
        edges.append(e.verts[:]) #which vertices make up the edge
        vertNums.append(e.verts[0]) #which number vertices are involved

vertNums = set(vertNums) #making it a set eliminates doubles
vertNums = list(vertNums) #convert back to list to use

for v in obj.verts: #make a list of the coordinates of all verts in selected object

#find the normal vector and get the edge vectors
for i in edges: #find the unit vectors representing the direction of each edge

for v in vertNums: #for all the vertices determine the 2 edges meeting at the vertex and whether they enter/exit them
    for e in range(len(edges)):
        if v == edges[e][0]:
        elif v == edges[e][1]:
            listTemp2.append(-1) #if the edge has been defined as entering the vertex it must be flipped so that it exits it, hence the -1 factor which will be used later
    listTemp = []
    listTemp2 = []

for v in range(len(vertNums)): #now for all the verts we find the required edge vectors which enter/exit the vertex
    a = 1 #this factor determines whether the in plane vector points in between the edges or outside it
    if (edgeReq[0].cross(edgeReq[1])).dot(faceNormal) > 0:
        a = -1 #if the first edge's in plane vector points outward it must be flipped
    tempVar = (((a*edgeReq[0].cross(faceNormal)).dot(edgeReq[1]))*(edgeReq[0].dot(edgeReq[1]))+((-a*edgeReq[1].cross(faceNormal)).dot(edgeReq[0])))/(1-pow(edgeReq[0].dot(edgeReq[1]),2))
    obj.verts[vertNums[v]].co += inset*(tempVar * edgeReq[0] + (a*edgeReq[0].cross(faceNormal))) #move the vertex
    edgeReq = []

bpy.ops.object.editmode_toggle() #return to edit mode

Any pointers to improve the code, corrections, or areas where I’ve made any rookie errors are welcome.


Be pretty easy to turn that into an operator so you could assign it to a hotkey.

The script template menu has some examples to look at.

Great script. Thanks Truman.

maybe you’d be interested in this script:
which works in 2.49 on more than 1 face, although not perfectly correct.

Thanks pildanovak, that’s certainly a great script. I might try and fix some of those problems if I get the chance. I think the main problem is that to fix them new faces must be added to the mesh and it probably won’t be easy to do this in a consistent way so that everyone’s nice models don’t get ruined by adding unnecessary faces.