0
$\begingroup$

I'm starting to use blender and I stumbled into a couple of problems.

I have several 2d shapes, mostly circles and closed polygons. For the sake of simplicity I started to work with them as if they live on z=0 plane. My final goal is to be able to perform something like boolean modifiers on the 2d shapes in order to extrude the results, for example making two circular holes on a rectangle, using the python API.

First question. If I take a rectangle on the z=0 plane and then apply a bmesh.ops.extrude_face_region on the mesh...the face along the first edge is missing:

import bpy
import bmesh

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]
rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)
bpy.context.scene.objects.link(obj_rect)
me_rect.from_pydata(rect_v, rect_e, rect_f)
me_rect.update()

bm4 = bmesh.new()
bm4.from_mesh(me_rect)        
bmesh.ops.translate(bm4,verts=bm4.verts, vec=(0.0, 0.0, -1.0))

edges_start = bm4.edges[:]
faces_start = bm4.faces[:]
verts_start = bm4.verts[:]
ret = bmesh.ops.extrude_face_region(bm4, geom = edges_start + faces_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]
bmesh.ops.translate(bm4,verts=verts_extrude_b, vec=(0.0, 0.0, 2.0))
bm4.to_mesh(me_rect)

me_rect.update()

enter image description here

Can someone tell me why this is happenning?

Second question. I addition to my initial rectangle I create two circles. I join them into a single mesh. Then I extrude them by the edges and finally I try to perform a boolean difference between the 2d rectangle and the extruded circles (I came up with this workaround when I found that extrusions didn't work well on ovelapped shapes, this procedure actually works in other instances, for example want to generate a 2d ring from two concentric circles -no joint mesh in that case- see the end of this post). When the modifier is executed the application crashes, and running the script on console throws an EXCEPTION_ACCESS_VIOLATION. I checked for the normals on the objects and they look fine to me.

The full script:

import bpy
import bmesh

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]

rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)
bpy.context.scene.objects.link(obj_rect)
me_rect.from_pydata(rect_v, rect_e, rect_f)
me_rect.update()
# end Rectangle


c1mesh = bpy.data.meshes.new("Disk1")
c1object = bpy.data.objects.new("Disk1", c1mesh)
bpy.context.scene.objects.link(c1object)
bm1 = bmesh.new()
bm1.from_mesh(c1mesh)
bmesh.ops.create_circle(bm1, cap_ends=False, diameter=1, segments=128)
bm1.to_mesh(c1mesh)
#bm1.free()


c2mesh = bpy.data.meshes.new("Disk2")
c2object = bpy.data.objects.new("Disk2", c2mesh)
bpy.context.scene.objects.link(c2object)
bm2 = bmesh.new()
bm2.from_mesh(c2mesh)
bmesh.ops.create_circle(bm2, cap_ends=False, diameter=1, segments=128)
bmesh.ops.translate(bm2, verts=bm2.verts, vec=(3.0, 0.0, 0.0))
bm2.to_mesh(c2mesh)


me = bpy.data.meshes.new("Joint")
joint_obj = bpy.data.objects.new("Joint", me)
bpy.context.scene.objects.link(joint_obj)

bm3 = bmesh.new()
bm3.from_mesh(c1mesh)
bm3.from_mesh(c2mesh)

bm3.to_mesh(me)


# ancillary extrude
bmesh.ops.translate(bm3, verts=bm3.verts, vec=(0.0, 0.0, -1.01))
edges_start = bm3.edges[:]
faces_start = []
verts_start = bm3.verts[:]

ret = bmesh.ops.extrude_edge_only(bm3, edges = edges_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]

bmesh.ops.translate(bm3,verts=verts_extrude_b, vec=(0.0, 0.0, 2.02))
bm3.to_mesh(me)
bm3.free()
me.update()


bm4.to_mesh(me_rect)

# this crashes blender, also if I comment this out and try to do it from
# the GUI it also crashes
obj_rect.select= True
bpy.context.scene.objects.active = obj_rect
bool_one = obj_rect.modifiers.new(type="BOOLEAN", name="bool1")
bool_one.object = joint_obj
bool_one.operation = 'DIFFERENCE'

bpy.ops.object.modifier_apply(apply_as='DATA', modifier="bool1")    

Here is a working example of what I'm trying to achieve (cylinder with hole from two concentric circles):

import bmesh
import bpy

c1mesh = bpy.data.meshes.new("Disk1")
c1object = bpy.data.objects.new("Disk1", c1mesh)
bpy.context.scene.objects.link(c1object)
bm = bmesh.new()
bm.from_mesh(c1mesh)
bmesh.ops.create_circle(bm, cap_ends=True, diameter=2, segments=128)
bm.to_mesh(c1mesh)
bm.free()

c2mesh = bpy.data.meshes.new("Disk2")
c2object = bpy.data.objects.new("Disk2", c2mesh)
bpy.context.scene.objects.link(c2object)

bm = bmesh.new()
bm.from_mesh(c2mesh)
bmesh.ops.create_circle(bm, cap_ends=False, diameter=1, segments=128)
bmesh.ops.translate(
        bm,
        verts=bm.verts,
        vec=(0.0, 0.0, -0.01))

edges_start = bm.edges[:]
faces_start = []
verts_start = bm.verts[:]
ret = bmesh.ops.extrude_edge_only(bm, edges = edges_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]

bmesh.ops.translate(
        bm,
        verts=verts_extrude_b,
        vec=(0.0, 0.0, 0.02))

bm.to_mesh(c2mesh)
c1object.select= True
bpy.context.scene.objects.active = c1object
bool_one = c1object.modifiers.new(type="BOOLEAN", name="bool1")
bool_one.object = c2object
bool_one.operation = 'DIFFERENCE'

bpy.ops.object.modifier_apply(apply_as='DATA', modifier="bool1")
bpy.ops.object.select_all(action='DESELECT')
c2object.select = True
bpy.ops.object.delete()
bm.free()

bm = bmesh.new()
bm.from_mesh(c1mesh)
edges_start = bm.edges[:]
verts_start = bm.verts[:]
faces_start = bm.faces[:]

ret = bmesh.ops.extrude_face_region(bm, geom = edges_start + faces_start)
geom_extrude_mid = ret["geom"]
verts_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
                   if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]


bmesh.ops.translate(
        bm,
        verts=verts_extrude_b,
        vec=(0.0, 0.0, 2))

bm.to_mesh(c1mesh)
c1mesh.update()
bm.free()

Thanks in advance.

$\endgroup$

1 Answer 1

0
$\begingroup$

The answer to my problem was that my 2d polygons (the rectangle in my example) was non-manifold.

After hours of googling around and playing with the GUI I discovered that if I changed the way that I create the polygon mesh:

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]

rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)
bpy.context.scene.objects.link(obj_rect)
me_rect.from_pydata(rect_v, rect_e, rect_f)
me_rect.update()

to

rect_v = [(-2,-2,0),(5,-2,0),(5,2,0),(-2,2,0)]
#rect_e = [(i,(i+1)%len(rect_v)) for i in range(len(rect_v))]
rect_e = []
rect_f = [tuple(range(len(rect_v)))]

me_rect = bpy.data.meshes.new("Rect")
obj_rect = bpy.data.objects.new("Rect", me_rect)
bpy.context.scene.objects.link(obj_rect)
me_rect.from_pydata(rect_v, rect_e, rect_f)
me_rect.update(calc_edges = True)

Then my 2d polygons are manifold-like, and everithing works as expected.

I'm not quite certain of what is missing on the first code snippet. But the bottom line is, if you try to perform boolean modifiers on non-manifold meshes blender will crash (at least it did on all my tests).

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .