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.
This commit is contained in:
Campbell Barton 2021-10-11 21:28:06 +11:00
parent 0ceded7bc9
commit a82c9e1e40

@ -25,7 +25,6 @@ __all__ = (
"axis_conversion", "axis_conversion",
"axis_conversion_ensure", "axis_conversion_ensure",
"create_derived_objects", "create_derived_objects",
"free_derived_objects",
"unpack_list", "unpack_list",
"unpack_face_list", "unpack_face_list",
"path_reference", "path_reference",
@ -348,21 +347,40 @@ def axis_conversion_ensure(operator, forward_attr, up_attr):
return False return False
# return a tuple (free, object list), free is True if memory should be freed def create_derived_objects(depsgraph, objects):
# later with free_derived_objects() """
def create_derived_objects(scene, ob): This function takes a sequence of objects, returning their instances.
if ob.parent and ob.parent.instance_type in {'VERTS', 'FACES'}:
return False, None
if ob.instance_type != 'NONE': :arg depsgraph: The evaluated depsgraph.
ob.dupli_list_create(scene) :type depsgraph: :class:`bpy.types.Depsgraph`
return True, [(dob.object, dob.matrix) for dob in ob.dupli_list] :arg objects: A sequencer of objects.
else: :type objects: sequence of :class:`bpy.types.Object`
return False, [(ob, ob.matrix_world)] :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:
def free_derived_objects(ob): for dup in depsgraph.object_instances:
ob.dupli_list_clear() 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): def unpack_list(list_of_tuples):