See #4481. Optimise object visibility even further by using foreach_set.

Note: now we are using hide_viewport not hide_set anymore. There might
be pending issues from this. Also, now because we use foreach_set, we
can quickly also apply hide_render, which saves time during underlay
generation.
This commit is contained in:
Dion Moult
2025-10-05 23:20:32 +11:00
parent f8ccdf1170
commit 86880e9e62
2 changed files with 16 additions and 51 deletions
@@ -435,10 +435,6 @@ class CreateDrawing(bpy.types.Operator):
if os.path.isfile(svg_path) and self.props.should_use_underlay_cache:
return svg_path
visible_object_names = {obj.name for obj in bpy.context.visible_objects}
for obj in bpy.context.view_layer.objects:
obj.hide_render = obj.name not in visible_object_names
assert context.scene and context.view_layer and context.screen
context.scene.render.filepath = str(Path(svg_path).with_suffix(".png"))
assert (drawing_style := self.cprops.get_active_drawing_style())
@@ -449,7 +445,7 @@ class CreateDrawing(bpy.types.Operator):
previous_visibility: dict[str, bool] = {}
collection = tool.Blender.get_object_bim_props(self.camera).collection
assert collection
# Hie annotations.
# Hide annotations.
for obj in collection.objects:
if context.view_layer.objects.get(obj.name):
previous_visibility[obj.name] = obj.hide_get()
@@ -2171,27 +2167,10 @@ class ActivateModel(bpy.types.Operator):
if model_props.show_cut_decorator:
CutDecorator.uninstall()
# Preserve current visibility statuses for:
# - non-ifc objects
# - type product
# - annotations (so we won't unhide other drawings)
ifc_file = tool.Ifc.get()
visibility_status: dict[bpy.types.Object, bool] = {}
for obj in bpy.data.objects:
element = tool.Ifc.get_entity(obj)
if not element:
hide = obj.hide_get()
elif element.is_a("IfcAnnotation"):
hide = True
elif element.is_a("IfcTypeProduct"):
hide = obj.hide_get()
else:
continue
visibility_status[obj] = hide
if not bpy.app.background:
with context.temp_override(**tool.Blender.get_viewport_context()):
bpy.ops.object.hide_view_clear(select=False)
bpy.ops.bim.activate_status_filters(only_if_enabled=True)
elements = {e for obj in context.visible_objects if (e := tool.Ifc.get_entity(obj))}
@@ -2241,9 +2220,12 @@ class ActivateModel(bpy.types.Operator):
should_sync_changes_first=True,
)
# restore visibility after hide_view_clear()
for obj, hide_status in visibility_status.items():
obj.hide_set(hide_status)
for obj in bpy.context.view_layer.objects:
obj.update_tag() # Ensure refresh viewport after foreach_set visibility
should_hides = np.full(len(bpy.context.view_layer.objects), 0, dtype=np.uint8)
should_hides = np.ascontiguousarray(should_hides)
bpy.context.view_layer.objects.foreach_set("hide_viewport", should_hides)
bpy.context.view_layer.objects.foreach_set("hide_render", should_hides)
tool.Blender.update_viewport()
bonsai.bim.handler.refresh_ui_data()
+9 -26
View File
@@ -2188,9 +2188,6 @@ class Drawing(bonsai.core.tool.Drawing):
@classmethod
def activate_drawing(cls, camera: bpy.types.Object) -> None:
selected_objects_before = bpy.context.selected_objects
non_ifc_objects_hide = {o: o.hide_get() for o in bpy.context.view_layer.objects if not tool.Ifc.get_entity(o)}
# Sync viewport objects visibility with selectors from EPset_Drawing/Include and /Exclude
drawing = tool.Ifc.get_entity(camera)
assert drawing and isinstance(camera.data, bpy.types.Camera)
@@ -2202,13 +2199,7 @@ class Drawing(bonsai.core.tool.Drawing):
target_view = cls.get_drawing_target_view(drawing)
subcontexts = cls.get_drawing_subcontexts(target_view)
# Hide everything first, then selectively show. This is significantly faster.
with bpy.context.temp_override(**tool.Blender.get_viewport_context()):
bpy.ops.object.hide_view_set(unselected=False)
bpy.ops.object.hide_view_set(unselected=True)
# switch representations and hide elements without representations
element_obj_names = set()
# Switch representations
for element in filtered_elements:
obj = tool.Ifc.get_object(element)
if not obj:
@@ -2239,27 +2230,19 @@ class Drawing(bonsai.core.tool.Drawing):
has_context = True
break
# Don't hide IfcAnnotations or Aggregates as some of them might exist without representations
if has_context or element.is_a("IfcAnnotation") or element.IsDecomposedBy:
element_obj_names.add(obj.name)
# Note that render visibility is only set on drawing generation time for speed.
should_hides = []
for obj in bpy.context.view_layer.objects:
if obj.name in element_obj_names:
obj.hide_set(False)
obj.hide_render = False
continue
if (hide := non_ifc_objects_hide.get(obj)) is not None:
obj.hide_set(hide)
obj.hide_render = hide
if element := tool.Ifc.get_entity(obj):
should_hides.append(0 if element in filtered_elements else 1)
else:
obj.hide_render = True
should_hides.append(obj.hide_viewport)
obj.update_tag() # Ensure refresh viewport after foreach_set visibility
should_hides = np.fromiter(should_hides, dtype=np.uint8, count=len(should_hides))
bpy.context.view_layer.objects.foreach_set("hide_viewport", should_hides)
bpy.context.view_layer.objects.foreach_set("hide_render", should_hides)
cls.import_camera_props(drawing, camera.data)
for obj in selected_objects_before:
obj.select_set(True)
@classmethod
def get_elements_in_camera_view(
cls, camera: bpy.types.Object, objs: list[bpy.types.Object]