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
Notes: blender-bot 2023-02-14 04:07:50 +01:00
Referenced by issue #91169, bpy_extras.io_utils.create_derived_objects -> error with duplis
1 changed files with 32 additions and 14 deletions

View File

@ -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
def create_derived_objects(depsgraph, objects):
"""
This function takes a sequence of objects, returning their instances.
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)]
: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())]
def free_derived_objects(ob):
ob.dupli_list_clear()
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):