6
$\begingroup$

I would like to programmatically create and extrude polygons. I've found several examples of code (e.g. here), but none of them are currently working for me. As a simple example, I am trying to get things working first with a defined circular face and then extrude that face. Here is the code defining the circular bmesh:

import bpy, bmesh
from math import *

NUMVERTS = 1000
Dphi = 2*pi/NUMVERTS
# calculate x,y coordinate pairs
coords = [(cos(i*Dphi),sin(i*Dphi),0) for i in range(NUMVERTS)]

bm = bmesh.new()
for v in coords:
    bm.verts.new(v)
bm.faces.new(bm.verts)

bm.normal_update()

me = bpy.data.meshes.new("circle")
bm.to_mesh(me)
# add bmesh to scene
ob = bpy.data.objects.new("circle",me)
bpy.context.scene.objects.link(ob)
bpy.context.scene.update()

Which results in a 2D circle

2D circle

I then want to extrude that face in z by some amount resulting in something like:

Extrusion

I would like to do everything in a python script without having to select anything in the GUI. Also, I'm using a circle as a placeholder example here -- I ultimately want to import much more complicated 2D (XY) polygons and extrude them in Z by some amount. Thanks!

$\endgroup$
6
$\begingroup$

Here is the extrusion part filled in:

import bpy, bmesh
from math import *
from mathutils import Vector

NUMVERTS = 1000
Dphi = 2*pi/NUMVERTS
# calculate x,y coordinate pairs
coords = [(cos(i*Dphi),sin(i*Dphi),0) for i in range(NUMVERTS)]

bm = bmesh.new()
for v in coords:
    bm.verts.new(v)

# think of this new vertices as bottom of the extruded shape
bottom = bm.faces.new(bm.verts)

# next we create top via extrude operator, note it doesn't move the new face
# we make our 1 face into a list so it can be accepted to geom
top = bmesh.ops.extrude_face_region(bm, geom=[bottom])

# here we move all vertices returned by the previous extrusion
# filter the "geom" list for vertices using list constructor
bmesh.ops.translate(bm, vec=Vector((0,0,1)), verts=[v for v in top["geom"] if isinstance(v,bmesh.types.BMVert)])

bm.normal_update()

me = bpy.data.meshes.new("circle")
bm.to_mesh(me)
# add bmesh to scene
ob = bpy.data.objects.new("circle",me)
bpy.context.scene.objects.link(ob)
bpy.context.scene.update()

The hard part is grasping the habit of having this dictionary return type from the operations. It's a dictionary containing definition for "geom" that contains a single list where all the verts, edges and faces are listed one after another. You are then supposed to make a list of the verts, edges or faces with python list construction where you check for the element type using isinstance(), depending on what you need for each operation.

enter image description here

$\endgroup$
4
$\begingroup$

Similarly to the link in your q, can use bmesh operators, in this case I've used solidify, Note you must set the normal before calling the operator to get the desired result. Also note that face.normal = (0, 0, -1) (commented out) could (preferably?) be used in place of bm.normal_update().

import bpy, bmesh
from math import radians, sin, cos

NUMVERTS = 100
Dphi = radians(360) / NUMVERTS
# calculate x,y coordinate pairs
coords = [(cos(i * Dphi), sin(i * Dphi), 0) for i in range(NUMVERTS)]

bm = bmesh.new()
verts = [bm.verts.new(v) for v in coords]

face = bm.faces.new(verts)
bm.normal_update()
# or face.normal = (0, 0, -1)
bmesh.ops.solidify(bm, geom=[face], thickness=1.0)

me = bpy.data.meshes.new("circle")
bm.to_mesh(me)
# add bmesh to scene
ob = bpy.data.objects.new("circle",me)
bpy.context.scene.objects.link(ob)

However I've found if you are going to do for multiple faces then making the "wall" faces is significantly faster. (that's my experience using similar to create 1000's of OSM buildings that are basically an extrusion of an ngon.)

import bpy, bmesh
from math import radians, cos, sin

from mathutils import Vector

NUMVERTS = 100
Dphi = radians(360) / NUMVERTS
height = 1.0
# calculate x,y coordinate pairs
coords = [(cos(i * Dphi), sin(i * Dphi), 0) for i in range(NUMVERTS)]

bm = bmesh.new()
verts = [bm.verts.new(v) for v in coords]
roofverts = [bm.verts.new(v.co + Vector((0, 0, height))) for v in verts]
# pop one on the end to make ring
roofverts.append(roofverts[0])  
verts.append(verts[0]) 
for i in range(len(roofverts) - 1):
    wall = bm.faces.new([verts[i], roofverts[i], roofverts[i+1], verts[i+1]])
    #wall.material_index = matidx 
# pop off to remove.
verts.pop()
roofverts.pop()
floor = bm.faces.new(verts)
top = bm.faces.new(roofverts)

me = bpy.data.meshes.new("circle")
bm.to_mesh(me)
# add bmesh to scene
ob = bpy.data.objects.new("circle",me)
bpy.context.scene.objects.link(ob)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.