2
$\begingroup$

I am trying to merge two close boxes into one single cuboid, from the GUI I am able to successfully create the two boxes and set a boolean modifier to the first box to unify(UNION) with the second box before deleting it. But when I run the following script

import bpy
import ast

def delete(obj0):
    bpy.ops.object.select_all(action='DESELECT')
    obj0.select = True
    bpy.ops.object.delete()

def Merge(obj0,obj1):
    bpy.ops.object.select_all(action='DESELECT')
    obj0.select = True #selecting obj0 so the bpy modifier is constructed for it
    bpy.ops.object.modifier_add(type='BOOLEAN')
    bpy.context.object.modifiers["Boolean"].object = obj1
    bpy.context.object.modifiers["Boolean"].operation = 'UNION'
    bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
    delete(obj1) #deleting obj1 since it's no longer needed
    return obj0 #returning obj0 which shoulda become the cuboid just incase a future need arises to merge with another box

def AddBox(x,y,z,width,height,depth):
    bpy.ops.mesh.primitive_cube_add(location=(x, y, z))
    bpy.ops.transform.resize(value=(width, height, depth))
    return bpy.context.active_object

#creating the two boxes and naming them
box0 = AddBox(0,0,0, .5,.5,.5)
box0.name='box0'
box1 = AddBox(0,1,0, .5,.5,.5)
box1.name='box1'

#merging them into a cuboid
Merge(box0,box1)   

I get the following exception

TypeError: bpy_struct: item.attr = val: BooleanModifier.object ID type does not support assignment to itself

$\endgroup$
0

1 Answer 1

2
$\begingroup$

Need to set the active object.

The issue here is that operators work on the context.object to set an object to "active state" use both

in 2.7x

context.scene.objects.active = ob0
ob0.select = True  

in 2.80

context.view_layer.objects.active = ob0
ob0.select_set(True)

Then when you run an operator it sees ob0 as context.

Just setting ob0.select = True is not #selecting obj0 so the bpy modifier is constructed for it

Without the above, because you added ob1 last, it was still context.object and hence you were trying to set its union object to itself.

An object can be active but not selected, selected but not active.

Again from a previous answer https://blender.stackexchange.com/a/133292/15543 I showed how to add a modifier using api methods to get its reference IMO this is far simpler than using an operator.

Surely

bool = ob0.modifiers.new(name='booly', type='BOOLEAN')
bool.object = ob1
bool.operation = 'UNION'

is more readable (, and simpler) than

bpy.ops.object.select_all(action='DESELECT')
bpy.context.scene.objects.active = obj0
obj0.select = True 
bpy.ops.object.modifier_add(type='BOOLEAN')
bpy.context.object.modifiers["Boolean"].object = obj1
bpy.context.object.modifiers["Boolean"].operation = 'UNION'

Soapbox TLDR:

Recommend getting out of the habit of always addressing via bpy.context.foo.bar.blah For example in test code if the line context = bpy.context is added at the top, removes the need to use bpy.context.... every bloody time, if later we choose to copy paste our code into operators or panels then the context matches the argument context in draw and execute methods etc.

Or after adding modifier with operator

bpy.ops.object.modifier_add(type='BOOLEAN')  
mod = obj0.modifiers[-1] # it's the last added
mod.object = obj1
mod.operation = 'UNION'

Here I've referred to the newly created modifier as a variable "mod", over obj0.modifiers["Boolean"] and definitely rather than the long winded bpy.context.object.modifiers["Boolean"]

$\endgroup$
2
  • $\begingroup$ lol @ "bloody". $\endgroup$
    – linker
    Mar 4, 2019 at 20:11
  • $\begingroup$ thanks man... You are 2X a life saver. saved a drowning brother twice. really appreciate. I express my deepest BATARANGS $\endgroup$
    – linker
    Mar 4, 2019 at 20:15

You must log in to answer this question.

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