0
$\begingroup$

I'm trying to do a simple boolean difference and export the result as an stl file. My script is below - it just makes a cube and a sphere and subtracts the cube from the sphere:

import bpy

# clear any objects
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.data.objects:
    obj.select_set(True)
    bpy.ops.object.delete()

# add a cube
bpy.ops.mesh.primitive_cube_add()
cube = bpy.context.active_object

#add a sphere
bpy.ops.mesh.primitive_uv_sphere_add(location=[1.5, 0, 0])
sphere = bpy.context.active_object

# subtract the cube from the sphere
bool_one = sphere.modifiers.new(type="BOOLEAN", name="bool 1")
bool_one.object = cube
bool_one.operation = 'DIFFERENCE'
bpy.context.view_layer.objects.active = sphere
bpy.ops.object.modifier_apply(modifier="bool 1")

# delete the cube
bpy.ops.object.select_all(action='DESELECT')
cube.select_set(True)
bpy.ops.object.delete()

# export sphere
bpy.ops.object.select_all(action='DESELECT')
sphere.select_set(True)
stl_path = f"/Users/danilo/Desktop/test_{sphere.name}.stl"
print(stl_path)
bpy.ops.export_mesh.stl(
    filepath=stl_path,
    use_selection=True
)

When I run this within blender, I get the expected result:

stl file produced by running script within blender

When I run the same script in an ipython notebook, an stl file is made, but it's essentially empty (84 bytes instead of 48kb like the above) and it doesn't open in an stl viewer.

One more thing I tried is just exporting the cube and the sphere separately before doing the boolean op. This works as expected in the ipython notebook.

I'm running:

  • macOS 12.6
  • Apple M1 Max processor
  • blender 3.6.5
  • python 3.10.13
  • bpy version 4.1.0 Alpha (built from git revision 583bd9662e Nov 11 2023)

Any help is appreciated. Thanks!

$\endgroup$
5
  • $\begingroup$ I tested your script (only needed to modify the output path), and it worked fine. I verified by importing the STL file into Blender. $\endgroup$
    – Mr A
    Nov 20 at 23:23
  • $\begingroup$ Just to clarify - it worked for you in python (outside blender)? $\endgroup$
    – danilo
    Nov 21 at 0:18
  • $\begingroup$ Yes, like this blender --background --python test.py. $\endgroup$
    – Mr A
    Nov 21 at 0:26
  • $\begingroup$ Interesting, that worked for me too; had to do this: /Applications/Blender.app/Contents/MacOS/Blender --background --python test_stl.py. If you just run your script like python test.py do you get a weird empty file? That's what happens for me. And if I modify the file to comment out the lines that make and apply the boolean modifier, I get a normal file of the full sphere. $\endgroup$
    – danilo
    Nov 21 at 0:52
  • $\begingroup$ I can't run it like that as I don't have the bpy module. This is the output I get when I run python3 test_stl.py: Traceback (most recent call last): File "/home/mra/Desktop/test_stl.py", line 1, in <module> import bpy ModuleNotFoundError: No module named 'bpy' This seems to be an issue with Blender 4.0 and above. I posted a workaround answer below. $\endgroup$
    – Mr A
    Nov 21 at 10:20

1 Answer 1

0
$\begingroup$

It turned out that in Blender 4.0 and probably in 4.1.0 Alpha the Boolean modifier is broken. I tested it in Blender 4.0. However, the Edit Mode version seems to be working fine. I modified the code to carry out the boolean in Edit Mode. It should work now.

import bpy

# clear any objects
bpy.ops.object.select_all(action='DESELECT')
for obj in bpy.data.objects:
    obj.select_set(True)
    bpy.ops.object.delete()

# add a cube
bpy.ops.mesh.primitive_cube_add()

# deselect cube vertices for the boolean operation performed later
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.editmode_toggle()

# add a sphere
bpy.ops.mesh.primitive_uv_sphere_add(location=[1.5, 0, 0])

# select and join objects
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.join()

# subtract the unselected vertices from the selected one
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.intersect_boolean(use_swap=True, use_self=False)
bpy.ops.object.editmode_toggle()

# export boolean result
bpy.ops.object.select_all(action='SELECT')
stl_path = f"/Users/danilo/Desktop/test_Sphere.stl"
print(stl_path)
bpy.ops.export_mesh.stl(
    filepath=stl_path,
    use_selection=True
)
$\endgroup$

You must log in to answer this question.

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