1
$\begingroup$

I'm trying to use the boolean difference modifier to make a cut in my mesh. Instead the mesh looses all vertices and becomes empty, and in the terminal I get about 10 messages that look like:

group 0D0F8A30 is unclassified!

As far as I can tell, my normals are all consistent, I don't have any duplicate vertices, and both my meshes are manifolds. The really strange aspect is that all operations are being performed by a python script I wrote, but the script only fails some of the time. The script is entirely deterministic (as far as I can tell), but sometimes it will run correctly and sometimes it will fail, return an empty mesh and print some of the above messages into the terminal.

enter image description here

The highlighted mesh will have the boolean modifier applied to it and the small cube is the object for this modifier. The intersection of the meshes is nice and transverse.

The strangest aspect of all of this to me is that my apparently deterministic script succeeds some of the time and fails some of the time. When it fails, the point at which it fails will differ. Any insight would be appreciated.

Edit: I've included the code below. Hopefully it's understandable. When the error occurs, it occurs in the section that begins

if clip_edges
    for edge in cut_edges(ADDR, n)

Note that this section is in many ways similar to the section that begins

for addr in ADDR_to_remove

However no error ever occurs in that section. The boolean operations in the latter mentioned section involve punching holes through solid faces of the mesh. The boolean operations in the former mentioned (error containing) section involve cutting solid edges of the mesh. I typically see both success and failure after running the code at most 10 times. Between runs of the code all I do is delete the one mesh that is produced by the code.

Also sorry if my code is hard to understand. I'm not used to writing code that others will look at or use.

import bpy
from time import localtime, time
from mathutils import Vector

start_time = time()

n = 3
final_size = 3.1                    #makerware units are mm
final_wall_thickness = .1         #minimum 0.0275591 for wsf
clip_edges = True
export_save = False
export_name = "acyclic_surface"
#n=2 ADDR = [('x', (1, 0, 1)), ('z', (0, 1, 2)), ('x', (0, 0, 1)), ('y', (0, 0, 1)), ('z', (1, 0, 0)), ('z', (1, 1, 1)), ('x', (2, 0, 0)), ('x', (1, 1, 1)), ('z', (0, 0, 2)), ('y', (1, 0, 0)), ('y', (0, 2, 1)), ('x', (0, 1, 1)), ('y', (1, 1, 0)), ('x', (1, 0, 0))]
ADDR = [('z', (1, 1, 0)), ('z', (0, 0, 1)), ('x', (3, 0, 1)), ('y', (2, 0, 1)), ('y', (2, 1, 1)), ('z', (0, 1, 0)), ('x', (0, 1, 0)), ('z', (2, 0, 2)), ('z', (2, 2, 1)), ('x', (2, 0, 1)), ('y', (0, 1, 0)), ('y', (1, 2, 0)), ('y', (0, 2, 0)), ('z', (1, 2, 1)), ('x', (2, 1, 0)), ('z', (1, 0, 1)), ('y', (1, 1, 0)), ('z', (0, 2, 1)), ('z', (2, 1, 1))]
#n=4 ADDR = [('x', (4, 1, 1)), ('z', (3, 2, 1)), ('y', (1, 0, 1)), ('y', (3, 1, 1)), ('z', (3, 0, 2)), ('x', (3, 1, 1)), ('y', (0, 1, 0)), ('x', (1, 1, 0)), ('x', (3, 2, 1)), ('z', (0, 1, 0)), ('x', (0, 0, 1)), ('z', (2, 0, 2)), ('y', (0, 2, 0)), ('x', (2, 0, 1)), ('z', (2, 3, 2)), ('z', (1, 0, 1)), ('x', (0, 1, 1)), ('z', (0, 0, 1)), ('x', (4, 2, 1)), ('z', (1, 2, 2)), ('x', (3, 3, 1)), ('y', (1, 1, 1)), ('x', (1, 2, 1)), ('z', (1, 1, 2)), ('x', (4, 3, 1)), ('z', (0, 2, 1)), ('y', (0, 3, 1)), ('z', (3, 1, 1)), ('z', (0, 3, 2)), ('z', (2, 2, 2)), ('z', (1, 3, 2)), ('x', (0, 2, 1)), ('y', (0, 0, 1)), ('z', (3, 3, 1)), ('x', (1, 1, 1)), ('y', (3, 4, 1)), ('x', (0, 1, 0)), ('z', (2, 1, 2))]
#n=5 ADDR = [('z', (3, 2, 0)), ('x', (2, 4, 2)), ('y', (3, 3, 1)), ('y', (2, 2, 0)), ('y', (3, 2, 0)), ('x', (1, 0, 1)), ('x', (2, 4, 3)), ('x', (5, 0, 1)), ('y', (4, 3, 0)), ('z', (3, 0, 0)), ('y', (1, 0, 1)), ('x', (0, 2, 2)), ('z', (2, 1, 3)), ('x', (3, 1, 2)), ('x', (3, 1, 1)), ('z', (2, 2, 0)), ('z', (1, 3, 1)), ('y', (0, 1, 0)), ('x', (5, 1, 1)), ('z', (0, 0, 2)), ('z', (1, 4, 4)), ('z', (2, 0, 1)), ('z', (1, 2, 1)), ('z', (0, 4, 4)), ('x', (1, 1, 2)), ('z', (2, 3, 1)), ('y', (1, 4, 0)), ('z', (1, 1, 0)), ('z', (2, 4, 2)), ('z', (0, 1, 0)), ('y', (0, 5, 2)), ('z', (0, 3, 4)), ('y', (2, 0, 1)), ('y', (2, 1, 1)), ('z', (1, 3, 0)), ('z', (1, 1, 1)), ('x', (2, 3, 2)), ('z', (3, 3, 2)), ('x', (0, 3, 2)), ('x', (0, 3, 3)), ('y', (2, 1, 2)), ('y', (1, 5, 2)), ('z', (4, 3, 2)), ('y', (1, 3, 3)), ('x', (2, 3, 3)), ('y', (2, 2, 1)), ('z', (2, 3, 2)), ('z', (1, 0, 0)), ('x', (1, 0, 0)), ('z', (4, 4, 2)), ('y', (1, 0, 0)), ('y', (4, 0, 0)), ('z', (1, 2, 0)), ('y', (1, 3, 2)), ('y', (0, 3, 3)), ('z', (1, 2, 2)), ('z', (3, 4, 2)), ('y', (0, 5, 3)), ('y', (3, 0, 1)), ('z', (0, 1, 1)), ('y', (1, 1, 1)), ('x', (5, 2, 0)), ('x', (0, 3, 0)), ('x', (2, 0, 0)), ('z', (0, 2, 0)), ('z', (1, 1, 2)), ('y', (3, 3, 0)), ('y', (2, 4, 0)), ('x', (3, 3, 0)), ('x', (2, 1, 2)), ('y', (3, 0, 0)), ('x', (5, 1, 0)), ('x', (2, 1, 0)), ('y', (1, 5, 3)), ('z', (4, 0, 0)), ('y', (4, 3, 1)), ('z', (3, 1, 1)), ('z', (2, 3, 0)), ('y', (2, 2, 2)), ('y', (3, 1, 0)), ('z', (0, 2, 1)), ('z', (1, 3, 4)), ('x', (3, 0, 0)), ('y', (0, 4, 0)), ('z', (0, 3, 0)), ('y', (4, 0, 1)), ('x', (0, 1, 0)), ('z', (0, 3, 1)), ('x', (5, 2, 1)), ('x', (1, 2, 2)), ('y', (2, 3, 1)), ('z', (4, 1, 0)), ('z', (4, 2, 0)), ('x', (0, 1, 2)), ('x', (0, 4, 2)), ('x', (2, 2, 1)), ('x', (0, 4, 3)), ('y', (0, 1, 2)), ('z', (0, 1, 3)), ('x', (4, 1, 0)), ('z', (0, 2, 3)), ('x', (0, 2, 0)), ('x', (5, 0, 0))]

def approx(a, b, epsilon):
    return abs(a - b) < epsilon

def t_add(t1, t2):
    return tuple(map(lambda a,b:a+b, t1, t2))

def cycle_mode():
    bpy.ops.object.mode_set(mode = 'EDIT')
    bpy.ops.object.mode_set(mode = 'OBJECT')

def addresses(nx, ny=None, nz=None, diams = False):
    if ny == None:
        ny = nx
    if nz == None:
        nz = nx
    if not diams:
        diams = (1,1,1)
    elif diams == 'big':
        diams = (n1, n2, n3)
    addr = []
    for i in range(nx+1):
        for j in range(ny+1-diams[1]):
            for k in range(nz+1-diams[2]):
                addr.append(('x', (i,j,k)))
    for i in range(nx+1-diams[0]):
        for j in range(ny+1):
            for k in range(nz+1-diams[2]):
                addr.append(('y', (i,j,k)))
    for i in range(nx+1-diams[0]):
        for j in range(ny+1-diams[1]):
            for k in range(nz+1):
                addr.append(('z', (i,j,k)))
    return addr

def addr_complement(addr, dims):
    addr_s = set(addr)
    all_addr_s = set(addresses(dims))
    return list(all_addr_s.difference(addr_s))

def hole_addresses(nx, ny=None, nz=None):
    if ny == None:
        ny = nx
    if nz == None:
        nz = nx
    ADDR = []
    for x in range(nx):
        for y in range(ny):
            for z in range(nz):
                ADDR.append((x,y,z))
    return ADDR

def cut_edges(addrs, nx, ny=None, nz=None):
    #addresses to keep
    if ny == None:
        ny = nx
    if nz == None:
        nz = nx
    edges = set()
    for addr in addrs:
        point = addr[1]
        if addr[0] == 'x':
            edges.update(set([('x', t_add(point, (i,j,k))) for i in (-1,0) for j in (0,1) for k in (0,1)]))
            edges.update(set([('y', t_add(point, (0,j,k))) for j in (-1,1) for k in (0,1)]))
            edges.update(set([('z', t_add(point, (0,j,k))) for j in (0,1) for k in (-1,1)]))
        elif addr[0] == 'y':
            edges.update(set([('y', t_add(point, (i,j,k))) for i in (0,1) for j in (-1,1) for k in (0,1)]))
            edges.update(set([('x', t_add(point, (i,0,k))) for i in (-1,1) for k in (0,1)]))
            edges.update(set([('z', t_add(point, (i,0,k))) for i in (0,1) for k in (-1,1)]))
        elif addr[0] == 'z':
            edges.update(set([('z', t_add(point, (i,j,k))) for i in (0,1) for j in (0,1) for k in (-1,0)]))
            edges.update(set([('x', t_add(point, (i,j,0))) for i in (-1,1) for j in (0,1)]))
            edges.update(set([('y', t_add(point, (i,j,0))) for i in (0,1) for j in (-1,1)]))
    to_delete = set()
    for edge in edges:
        if min(edge[1])<0 or (edge[0]=='x' and edge[1][0]>=nx) or (edge[0]=='y' and edge[1][1]>=ny) or (edge[0]=='z' and edge[1][2]>=nz):
            to_delete.add(edge)
    edges.difference_update(to_delete)
    for addr in addrs:
        point = addr[1]
        if addr[0] == 'x':
            edges.discard(('y',point))
            edges.discard(('z',point))
            edges.discard(('y',t_add(point, (0,0,1))))
            edges.discard(('z',t_add(point, (0,1,0))))
        elif addr[0] == 'y':
            edges.discard(('x',point))
            edges.discard(('z',point))
            edges.discard(('x',t_add(point, (0,0,1))))
            edges.discard(('z',t_add(point, (1,0,0))))
        elif addr[0] == 'z':
            edges.discard(('x',point))
            edges.discard(('y',point))
            edges.discard(('x',t_add(point, (0,1,0))))
            edges.discard(('y',t_add(point, (1,0,0))))
    return edges

working_wall_thickness = (n*final_wall_thickness)/(final_size - final_wall_thickness) 
wwt = working_wall_thickness
ADDR_to_remove = addr_complement(ADDR, n)

bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
main = bpy.context.active_object
main.name = 'main'
bpy.ops.transform.resize(value = ((n+wwt)/2.0, (n+wwt)/2.0, (n+wwt)/2.0))
main.location = ((n+wwt)/2.0, (n+wwt)/2.0, (n+wwt)/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)
bpy.ops.object.mode_set(mode = 'EDIT')
bpy.ops.mesh.subdivide(number_cuts = n-1)

bpy.ops.object.mode_set(mode = 'OBJECT')
bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
hole = bpy.context.active_object
hole.name = 'hole'
bpy.ops.transform.resize(value = ((1-wwt)/2.0, (1-wwt)/2.0, (1-wwt)/2.0))
hole.location = ((1+wwt)/2.0, (1+wwt)/2.0, (1+wwt)/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)
bpy.ops.object.mode_set(mode = 'EDIT')
bpy.ops.mesh.select_all(action = 'SELECT')
bpy.ops.mesh.flip_normals()

bpy.ops.object.mode_set(mode = 'OBJECT')
for addr in hole_addresses(n):
    bpy.ops.object.select_all(action = 'DESELECT')
    hole.select = True
    bpy.ops.object.duplicate()
    hole_temp = bpy.context.selectable_objects[0]
    hole_temp.location = addr
    bpy.ops.object.select_all(action = 'DESELECT')
    main.select = True
    hole_temp.select = True
    bpy.context.scene.objects.active = main
    bpy.ops.object.join()

bpy.ops.object.select_all(action = 'DESELECT')
hole.select = True
bpy.ops.object.delete()

bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
punch_x = bpy.context.active_object
punch_x.name = 'punch_x'
bpy.ops.transform.resize(value = (wwt, .1, .1))
punch_x.location = (wwt/2.0, (1+wwt)/2.0, (1+wwt)/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)

bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
punch_y = bpy.context.active_object
punch_y.name = 'punch_y'
bpy.ops.transform.resize(value = (.1, wwt, .1))
punch_y.location = ((1+wwt)/2.0, wwt/2.0, (1+wwt)/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)

bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
punch_z = bpy.context.active_object
punch_z.name = 'punch_z'
bpy.ops.transform.resize(value = (.1, .1, wwt))
punch_z.location = ((1+wwt)/2.0, (1+wwt)/2.0, wwt/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)

bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
knife_x = bpy.context.active_object
knife_x.name = 'knife_x'
bpy.ops.transform.resize(value = (.1, wwt, wwt))
knife_x.location = ((1+wwt)/2.0, wwt/2.0, wwt/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)

bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
knife_y = bpy.context.active_object
knife_y.name = 'knife_y'
bpy.ops.transform.resize(value = (wwt, .1, wwt))
knife_y.location = (wwt/2.0, (1+wwt)/2.0, wwt/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)

bpy.ops.mesh.primitive_cube_add(location = (0,0,0))
knife_z = bpy.context.active_object
knife_z.name = 'knife_z'
bpy.ops.transform.resize(value = (wwt, wwt, .1))
knife_z.location = (wwt/2.0, wwt/2.0, (1+wwt)/2.0)
bpy.ops.object.transform_apply(scale = True, location = True)

for addr in ADDR_to_remove:
    x = addr[1][0]
    y = addr[1][1]
    z = addr[1][2]
    if addr[0] == 'x':
        punch_x.location = addr[1]
        bpy.context.scene.objects.active = main
        bpy.ops.object.modifier_add(type = 'BOOLEAN')
        main.modifiers[0].object = punch_x
        main.modifiers[0].operation = 'DIFFERENCE'
        bpy.ops.object.modifier_apply(modifier = 'Boolean')
        for vertex in main.data.vertices:
            if approx(vertex.co[1], y + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[0], x, 2*wwt):
                vertex.co[1] = y + 1
                vertex.co[2] = z + 1
            elif approx(vertex.co[1], y + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[0], x, 2*wwt):
                vertex.co[1] = y + 1
                vertex.co[2] = z + wwt
            elif approx(vertex.co[1], y + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[0], x, 2*wwt):
                vertex.co[1] = y + wwt
                vertex.co[2] = z + 1
            elif approx(vertex.co[1], y + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[0], x, 2*wwt):
                vertex.co[1] = y + wwt
                vertex.co[2] = z + wwt
    elif addr[0] == 'y':
        punch_y.location = addr[1]
        bpy.context.scene.objects.active = main
        bpy.ops.object.modifier_add(type = 'BOOLEAN')
        main.modifiers[0].object = punch_y
        main.modifiers[0].operation = 'DIFFERENCE'
        bpy.ops.object.modifier_apply(modifier = 'Boolean')
        for vertex in main.data.vertices:
            if approx(vertex.co[0], x + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[1], y, 2*wwt):
                vertex.co[0] = x + 1
                vertex.co[2] = z + 1
            elif approx(vertex.co[0], x + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[1], y, 2*wwt):
                vertex.co[0] = x + 1
                vertex.co[2] = z + wwt
            elif approx(vertex.co[0], x + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[1], y, 2*wwt):
                vertex.co[0] = x + wwt
                vertex.co[2] = z + 1
            elif approx(vertex.co[0], x + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[2], z + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[1], y, 2*wwt):
                vertex.co[0] = x + wwt
                vertex.co[2] = z + wwt
    elif addr[0] == 'z':
        punch_z.location = addr[1]
        bpy.context.scene.objects.active = main
        bpy.ops.object.modifier_add(type = 'BOOLEAN')
        main.modifiers[0].object = punch_z
        main.modifiers[0].operation = 'DIFFERENCE'
        bpy.ops.object.modifier_apply(modifier = 'Boolean')
        for vertex in main.data.vertices:
            if approx(vertex.co[0], x + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[1], y + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[2], z, 2*wwt):
                vertex.co[0] = x + 1
                vertex.co[1] = y + 1
            elif approx(vertex.co[0], x + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[1], y + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[2], z, 2*wwt):
                vertex.co[0] = x + 1
                vertex.co[1] = y + wwt
            elif approx(vertex.co[0], x + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[1], y + (1+wwt)/2.0 + 0.1, .001) and approx(vertex.co[2], z, 2*wwt):
                vertex.co[0] = x + wwt
                vertex.co[1] = y + 1
            elif approx(vertex.co[0], x + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[1], y + (1+wwt)/2.0 - 0.1, .001) and approx(vertex.co[2], z, 2*wwt):
                vertex.co[0] = x + wwt
                vertex.co[1] = y + wwt

bpy.ops.object.mode_set(mode = 'EDIT')
bpy.ops.mesh.remove_doubles()
bpy.ops.object.mode_set(mode = 'OBJECT')

if clip_edges:
    for edge in cut_edges(ADDR, n):
        print(edge)
        x = edge[1][0]
        y = edge[1][1]
        z = edge[1][2]
        if edge[0] == 'x':
            knife_x.location = edge[1]
            bpy.context.scene.objects.active = main
            bpy.ops.object.modifier_add(type = 'BOOLEAN')
            main.modifiers[0].object = knife_x
            main.modifiers[0].operation = 'DIFFERENCE'
            bpy.ops.object.modifier_apply(modifier = 'Boolean')
            for vertex in main.data.vertices:
                if approx(vertex.co[1], y, 2*wwt) and approx(vertex.co[2], z, 2*wwt) and approx(vertex.co[0], x + (wwt+1)/2.0 - 0.1, .001):
                    vertex.co[0] -= (1-wwt)/2.0 - 0.1
                elif approx(vertex.co[1], y, 2*wwt) and approx(vertex.co[2], z, 2*wwt) and approx(vertex.co[0], x + (wwt+1)/2.0 + 0.1, .001):
                    vertex.co[0] += (1-wwt)/2.0 - 0.1
        elif edge[0] == 'y':
            knife_y.location = edge[1]
            bpy.context.scene.objects.active = main
            bpy.ops.object.modifier_add(type = 'BOOLEAN')
            main.modifiers[0].object = knife_y
            main.modifiers[0].operation = 'DIFFERENCE'
            bpy.ops.object.modifier_apply(modifier = 'Boolean')
            for vertex in main.data.vertices:
                if approx(vertex.co[0], x, 2*wwt) and approx(vertex.co[2], z, 2*wwt) and approx(vertex.co[1], y + (wwt+1)/2.0 - 0.1, .001):
                    vertex.co[1] -= (1-wwt)/2.0 - 0.1
                elif approx(vertex.co[0], x, 2*wwt) and approx(vertex.co[2], z, 2*wwt) and approx(vertex.co[1], y + (wwt+1)/2.0 + 0.1, .001):
                    vertex.co[1] += (1-wwt)/2.0 - 0.1
        elif edge[0] == 'z':
            knife_z.location = edge[1]
            bpy.context.scene.objects.active = main
            bpy.ops.object.modifier_add(type = 'BOOLEAN')
            main.modifiers[0].object = knife_z
            main.modifiers[0].operation = 'DIFFERENCE'
            bpy.ops.object.modifier_apply(modifier = 'Boolean')
            for vertex in main.data.vertices:
                if approx(vertex.co[0], x, 2*wwt) and approx(vertex.co[1], y, 2*wwt) and approx(vertex.co[2], z + (wwt+1)/2.0 - 0.1, .001):
                    vertex.co[2] -= (1-wwt)/2.0 - 0.1
                elif approx(vertex.co[0], x, 2*wwt) and approx(vertex.co[1], y, 2*wwt) and approx(vertex.co[2], z + (wwt+1)/2.0 + 0.1, .001):
                    vertex.co[2] += (1-wwt)/2.0 - 0.1
        bpy.ops.object.mode_set(mode = 'EDIT')
        bpy.ops.mesh.remove_doubles()
        bpy.ops.mesh.normals_make_consistent(inside=False)
        bpy.ops.object.mode_set(mode = 'OBJECT')

bpy.ops.object.select_all(action = 'DESELECT')
punch_x.select = True
punch_y.select = True
punch_z.select = True
knife_x.select = True
knife_y.select = True
knife_z.select = True
bpy.ops.object.delete()

c = final_wall_thickness/wwt
bpy.ops.object.select_all()
bpy.ops.transform.resize(value = (c, c, c))
bpy.ops.object.transform_apply(scale = True)

print(time() - start_time)
$\endgroup$
  • $\begingroup$ Could you post your python script? $\endgroup$ – GiantCowFilms Aug 22 '14 at 22:21
  • $\begingroup$ Can it be uploaded as a separate file? The code is a few hundred lines long. $\endgroup$ – Kyle Parsons Aug 22 '14 at 22:30
  • $\begingroup$ @Kyle If you use code formatting (indented by four spaces) it will be put in a scrollable box of fixed size, so it won't make the post much longer. $\endgroup$ – gandalf3 Aug 22 '14 at 23:19
  • $\begingroup$ Just to update, I've worked around the problem by manipulating the mesh in a more hands on manner and not using boolean modifiers. $\endgroup$ – Kyle Parsons Aug 27 '14 at 21:35

Your Answer

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

Browse other questions tagged or ask your own question.