From a82c9e1e405c84b9ab8b5c1f31d7e135ab41c101 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 11 Oct 2021 21:28:06 +1100 Subject: Fix T91169: bpy_extras.io_utils.create_derived_objects -> duplis error This function now takes a depsgraph and a list of objects to avoid inefficient O(n^2) iteration when extracting instances from all objects in the scene. Returning an object -> instance map. Note that keeping compatibility with the existing API wasn't practical in this case since instances can no longer be generated from the scene and it's objects. --- release/scripts/modules/bpy_extras/io_utils.py | 50 +++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) (limited to 'release/scripts/modules') diff --git a/release/scripts/modules/bpy_extras/io_utils.py b/release/scripts/modules/bpy_extras/io_utils.py index 9e3c5bb64e0..a3b39853b3a 100644 --- a/release/scripts/modules/bpy_extras/io_utils.py +++ b/release/scripts/modules/bpy_extras/io_utils.py @@ -25,7 +25,6 @@ __all__ = ( "axis_conversion", "axis_conversion_ensure", "create_derived_objects", - "free_derived_objects", "unpack_list", "unpack_face_list", "path_reference", @@ -348,21 +347,40 @@ def axis_conversion_ensure(operator, forward_attr, up_attr): return False -# return a tuple (free, object list), free is True if memory should be freed -# later with free_derived_objects() -def create_derived_objects(scene, ob): - if ob.parent and ob.parent.instance_type in {'VERTS', 'FACES'}: - return False, None - - if ob.instance_type != 'NONE': - ob.dupli_list_create(scene) - return True, [(dob.object, dob.matrix) for dob in ob.dupli_list] - else: - return False, [(ob, ob.matrix_world)] - - -def free_derived_objects(ob): - ob.dupli_list_clear() +def create_derived_objects(depsgraph, objects): + """ + This function takes a sequence of objects, returning their instances. + + :arg depsgraph: The evaluated depsgraph. + :type depsgraph: :class:`bpy.types.Depsgraph` + :arg objects: A sequencer of objects. + :type objects: sequence of :class:`bpy.types.Object` + :return: A dictionary where each key is an object from `objects`, + values are lists of (:class:`bpy.types.Object`, :class:`mathutils.Matrix`) tuples representing instances. + :rtype: dict + """ + result = {} + has_instancer = False + for ob in objects: + ob_parent = ob.parent + if ob_parent and ob_parent.instance_type in {'VERTS', 'FACES'}: + continue + result[ob] = [] if ob.is_instancer else [(ob, ob.matrix_world.copy())] + + if result: + for dup in depsgraph.object_instances: + dup_parent = dup.parent + if dup_parent is None: + continue + dup_parent_original = dup_parent.original + if not dup_parent_original.is_instancer: + # The instance has already been added (on assignment). + continue + instance_list = result.get(dup_parent_original) + if instance_list is None: + continue + instance_list.append((dup.instance_object.original, dup.matrix_world.copy())) + return result def unpack_list(list_of_tuples): -- cgit v1.2.3