2.91 Python-API Keine Änderung nach Anwendung des booleschen Modifikatoroperators
Wie 'wende' ich die Boolesche Differenzoperation an ? Ich habe Python geschrieben, das visuell ein hohles Objekt erzeugt, aber tatsächlich nicht hohl ist. Optisch bekomme ich das Richtige:
Beim Exportieren in STL sind weiterhin beide Objekte vorhanden (keine leere Shell). Ich kann die Anwendung der Booleschen Operation manuell durch "Anwenden" abschließen.
und Löschen des inneren Objekts. Dann ist der Export in die STL-Datei korrekt.
Hier ist der Code, den ich geschrieben habe. Kann mir jemand mitteilen, welche Aufrufe ich ausführen kann, um die boolesche Modifikatoraktion anzuwenden und das Objekt zu löschen, mit dem ich in das andere Objekt geschnitten habe?
import sys
import bpy
D = bpy.data
C = bpy.context
from mathutils import *
import math
bpy.app.debug=True
########################################################################
# Stitch together vertices to create a face in the arc
def face(column, row, columns, rows):
v3 = ((column + 1) * rows) + row
v3 = (((v3 // 4) * 4) + (v3 + 1) % 4)
v4 = (column * rows + 1) + row
v4a = (((v4 // 4) * 4) + (v4) % 4)
if v4a == v3:
v4 = v4a - 4
return (column* rows + row,
(column + 1) * rows + row,
v3,
v4)
########################################################################
# Create an arc, start and eng angle, a scale to convert units, inner/outer size, height and the number of segments
def arc_segment(nme, start_ang, end_ang, scale, outer_size, inner_size, height, segs):
# Assuming arguments are in centimeters and in degrees, adjust o meters and radians.
# Change from degrees to radians
start_ang = (math.tau / 360.0) * start_ang
end_ang = (math.tau / 360.0) * end_ang
if start_ang > end_ang:
start_ang, end_ang = end_ang, start_ang
# Change from meters (unit of measure in Blender) to centimeters
outer_size = scale * outer_size
inner_size = scale * inner_size
# We're creating the arc, beginning with the newmericly smaller angle.
if outer_size < inner_size:
outer_size, inner_size = inner_size, outer_size
# Arc will be created withe center at 0, 1/2 infront and 1/2 behing X/Y plane
height = scale * height
# Use z for "height", center is 0, so 1/2 height away (plus), and 1/2 height close (minus)
p_height = (height * 0.5)
m_height = (height * -0.5)
# Think of the arc as a tube. This loop connects the faces to create the tube.
verts = []
for seg in range(0, segs + 1):
verts.append((math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size, p_height))
verts.append((math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size, m_height))
verts.append((math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size, m_height))
verts.append((math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size, p_height))
sides = 4
args = (segs, sides)
faces = [face(x, y, segs, sides) for x in range(segs) for y in range(sides)]
# Now cap the ends of the tube
faces.append((0, 1, 2, 3))
vbase = segs * sides
faces.append((vbase + 3, vbase + 2, vbase + 1, vbase))
# Create object, link it into the scene, make it 'active'.
mesh_data = bpy.data.meshes.new(nme)
mesh_data.from_pydata(verts, [], faces)
mesh_data.update() # (calc_edges=True) not needed here
cube_object = bpy.data.objects.new(nme, mesh_data)
scene = bpy.context.scene
bpy.context.collection.objects.link(cube_object)
cube_object.select_set(state=True)
########################################################################
# Solids modeling (CSG) take away coliding parts of one shape from another.
def csg(prim, cut, new_name, objects, operation):
o_prim = objects[prim]
o_cut = objects[cut]
cut_work = o_prim.modifiers.new(type="BOOLEAN", name=new_name)
cut_work.object = o_cut
cut_work.operation = 'DIFFERENCE'
o_cut.hide_set(True) # Hidden--But will still exist in an STL export.
# -- -- -- -- -- -- -- -- -- -- -- -- --
# What calls do I add here to "apply" the "difference" and delete the o_cut object?
# -- -- -- -- -- -- -- -- -- -- -- -- --
########################################################################
#
objects = bpy.data.objects
set_scale = 2.54 * 2
#
# Create some arcs
arc_segment("big_display_hull", 5.0, 90.0, set_scale, 11.5, 8.0, 4.5, 34)
arc_segment("big_hollow_hull", 6.5, 88.5, set_scale, 11.6, 7.7, 4.1, 34)
csg("big_display_hull", "big_hollow_hull", "o1", objects, 'DIFFERENCE')
arc_segment("attach_hulls", 360 + 110, 360 - 110.0, set_scale, 9.0, 8.0, 4.9, 120)
arc_segment("attach_hollow_hulls", 360 + 113, 360 - 113.0, set_scale, 9.2, 7.9, 4.1, 120)
csg("attach_hulls", "attach_hollow_hulls", "o3", objects, 'DIFFERENCE')
arc_segment("small_display_hull", 360 - 10, 360 - 65, set_scale, 11.5, 8.0, 4.5, 22)
arc_segment("small_hollow_hull", 360 - 11.5, 360 - 63.5, set_scale, 11.6, 7.7, 4.1, 22)
csg("small_display_hull", "small_hollow_hull", "o3", objects, 'DIFFERENCE')
Ich habe eine vorgeschlagene Lösung ausprobiert. Scripting: Wie füge ich einem Objekt einen booleschen Modifikator korrekt hinzu? Nachdem ein Problem mit "'apply_as' nicht erkannt" behoben wurde, wurde es ausgeführt. Ich sehe jedoch, dass der Boolesche Wert immer noch nicht angewendet wird. Kann jemand ein vollständiges Python-Boolesches Beispiel (CSG) veröffentlichen, in dem die resultierenden Netze die "fertigen" Objekte sind, da sich Blender 2.90.1 so stark von Version 2.79 unterscheidet? - Außerdem habe ich gesehen, dass 2.91 (Beta) etwas hat, das als "exakter Löser" bezeichnet wird. Könnte jemand einen ähnlichen Code posten, um den "exakten Löser" zu verwenden?
Antworten
Aktivieren Sie Entwickler-Extras / verwenden Sie die automatische Vervollständigung in der Konsole.
Bitte verwenden Sie 4 Leerzeichen (nicht 3).
Wie bereits erwähnt, hat der Apply-Modifikator keine "apply_as" -Eigenschaft mehr.
Setzen Sie für den genauen Löser das
solverAttribut auf genau, was ohnehin der Standardwert ist. Aktivieren Sie Entwickler-Extras in den Benutzereinstellungen, um einen Tooltip anzuzeigen, der dies anzeigt, oder verwenden Sie die automatische Vervollständigung in der Konsole.>>> C.object.modifiers['o1'] bpy.data.objects['big_display_hull'].modifiers["o1"] >>> C.object.modifiers['o1'].solver 'EXACT' >>> C.object.modifiers['o1'].solver = 'FOO' Traceback (most recent call last): File "<blender_console>", line 1, in <module> TypeError: bpy_struct: item.attr = val: enum "FOO" not found in ('FAST', 'EXACT')Operatoren arbeiten an den aktiven und ausgewählten Objekten. Habe den Operator so überschrieben, dass das aktive Objekt der Prim ist. Kann das aktive Objekt mit setzen
context.view_layer.objects.active = ob(Sie haben nur ausgewählt)Der Operator zum Anwenden des Modifikators schlägt stillschweigend fehl. Das aktive Objekt für den Testlauf enthält keine Modifikatoren
>>> bpy.ops.object.modifier_apply() {'CANCELLED'}Entfernen Sie alle Objekte mit
bpy.data.objects.remove(ob)Dies wurde hier gut dokumentiert und beantwortet
Änderungen für 2.91 mit genauem Löser. Es muss nicht festgelegt werden, da dies die Standardeinstellung ist, wenn der Modifikator hinzugefügt wird
def csg(prim, cut, new_name, objects, operation):
o_prim = objects[prim]
o_cut = objects[cut]
cut_work = o_prim.modifiers.new(type="BOOLEAN", name=new_name)
cut_work.object = o_cut
cut_work.operation = 'DIFFERENCE'
o_cut.hide_set(True) # Hidden--But will still exist in an STL export.
# -- -- -- -- -- -- -- -- -- -- -- -- --
# What calls do I add here to "apply" the "difference" and delete the o_cut object?
#cut_work.solver = 'EXACT' # it's the default anyhow.
bpy.ops.object.modifier_apply(
{"object" : o_prim},
modifier=cut_work.name,
)
# -- -
Ergebnis des Laufens mit den obigen Änderungen.
Habe es!
Das Hauptziel ist jetzt gelöst: eine STL-Datei, die genauso aussieht wie in Blender. Der korrigierte Code ist unten.
- Der Modifikator Boolean DIFFERENCE wird erfolgreich ausgeführt - Anscheinend kann er "leise" fehlschlagen. <Gibt es einen Einblick in weitere Informationen dazu?>
- Sobald ein Objekt zum Ausschneiden von "Material" verwendet wird, löscht der Code es jetzt erfolgreich.
- Code verwendet jetzt die Implikation, dass ein Modifikator "als untergeordnetes Element" des aktuell aktiven Objekts erstellt wird
import sys
import bpy
D = bpy.data
C = bpy.context
from mathutils import *
import math
bpy.app.debug = True
########################################################################
# Stitch together vertices to create a face in the arc
def face(column, row, columns, rows):
v3 = ((column + 1) * rows) + row
v3 = ((v3 // 4) * 4) + (v3 + 1) % 4
v4 = (column * rows + 1) + row
v4a = ((v4 // 4) * 4) + (v4) % 4
if v4a == v3:
v4 = v4a - 4
return (column * rows + row, (column + 1) * rows + row, v3, v4)
########################################################################
# Create an arc, start and eng angle, a scale to convert units, inner/outer size, height and the number of segments
def arc_segment(nme, start_ang, end_ang, scale, outer_size, inner_size, height, segs):
# Assuming arguments are in centimeters and in degrees, adjust o meters and radians.
# Change from degrees to radians
start_ang = (math.tau / 360.0) * start_ang
end_ang = (math.tau / 360.0) * end_ang
if start_ang > end_ang:
start_ang, end_ang = end_ang, start_ang
# Change from meters (unit of measure in Blender) to centimeters
outer_size = scale * outer_size
inner_size = scale * inner_size
# We're creating the arc, beginning with the newmericly smaller angle.
if outer_size < inner_size:
outer_size, inner_size = inner_size, outer_size
# Arc will be created withe center at 0, 1/2 infront and 1/2 behing X/Y plane
height = scale * height
# Use z for "height", center is 0, so 1/2 height away (plus), and 1/2 height close (minus)
p_height = height * 0.5
m_height = height * -0.5
# Think of the arc as a tube. This loop connects the faces to create the tube.
verts = []
for seg in range(0, segs + 1):
verts.append(
(
math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size,
p_height,
)
)
verts.append(
(
math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * inner_size,
m_height,
)
)
verts.append(
(
math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size,
m_height,
)
)
verts.append(
(
math.cos(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size,
math.sin(start_ang + (end_ang - start_ang) * (seg / segs)) * outer_size,
p_height,
)
)
sides = 4
args = (segs, sides)
faces = [face(x, y, segs, sides) for x in range(segs) for y in range(sides)]
# Now cap the ends of the tube
faces.append((0, 1, 2, 3))
vbase = segs * sides
faces.append((vbase + 3, vbase + 2, vbase + 1, vbase))
# Create object, link it into the scene, make it 'active'.
mesh_data = bpy.data.meshes.new(nme)
mesh_data.from_pydata(verts, [], faces)
mesh_data.update() # (calc_edges=True) not needed here
cube_object = bpy.data.objects.new(nme, mesh_data)
scene = bpy.context.scene
bpy.context.collection.objects.link(cube_object)
cube_object.select_set(state=True)
########################################################################
# Solids modeling (CSG) take away coliding parts of one shape from another.
# The main corrections (the "answer") are in this method here:
#
def csg(prim, cut, new_name, objects, operation):
o_prim = objects[prim]
o_cut = objects[cut]
bpy.context.view_layer.objects.active = o_prim #Setting the primary object as active.
cut_work = o_prim.modifiers.new(type="BOOLEAN", name=new_name)
cut_work.object = o_cut
cut_work.operation = "DIFFERENCE"
o_cut.hide_set(True) # Hidden--But will still exist in an STL export.
rs = bpy.ops.object.modifier_apply({"object": cut_work.object}, modifier=cut_work.name)
print(rs) # If this quietly fails, this prints {'CANCELLED'}. How can one know what to fix? Maybe logs or something that can be looked at to find out why?
########################################################################
#
objects = bpy.data.objects
set_scale = 2.54 * 2
#
# Create some arcs
arc_segment("big_display_hull", 5.0, 90.0, set_scale, 11.5, 8.0, 4.5, 34)
arc_segment("big_hollow_hull", 6.5, 88.5, set_scale, 11.6, 7.7, 4.1, 34)
csg("big_display_hull", "big_hollow_hull", "o1", objects, "DIFFERENCE")
arc_segment("attach_hulls", 360 + 110, 360 - 110.0, set_scale, 9.0, 8.0, 4.9, 120)
arc_segment(
"attach_hollow_hulls", 360 + 113, 360 - 113.0, set_scale, 9.2, 7.9, 4.1, 120
)
csg("attach_hulls", "attach_hollow_hulls", "o2", objects, "DIFFERENCE")
arc_segment("small_display_hull", 360 - 10, 360 - 65, set_scale, 11.5, 8.0, 4.5, 22)
arc_segment("small_hollow_hull", 360 - 11.5, 360 - 63.5, set_scale, 11.6, 7.7, 4.1, 22)
csg("small_display_hull", "small_hollow_hull", "o3", objects, "DIFFERENCE")
```