Asset Pipeline: Improve Performance #235

Merged
2 changed files with 107 additions and 110 deletions
Showing only changes of commit a5015a740a - Show all commits

View File

@ -121,84 +121,69 @@ def apply_transfer_data(context: bpy.types.Context, transfer_data_map) -> None:
def apply_transfer_data_items(context, td_type_key: str, transfer_data_items: List[PropertyGroup]): def apply_transfer_data_items(context, td_type_key: str, transfer_data_items: List[PropertyGroup]):
for transfer_data_item in transfer_data_items: # Get source/target from first item in list, because all items in list are same object/type
target_obj = transfer_data_item.target_obj target_obj = transfer_data_items[0].target_obj
source_obj = transfer_data_item.obj source_obj = transfer_data_items[0].obj
if target_obj is None: if target_obj is None:
logger.warning(f"Failed to Transfer Data for {transfer_data_item.id_data.name}") print(f"Failed to Transfer Data for {transfer_data_item.id_data.name}")
continue return
if transfer_data_item is None:
continue for transfer_data_item in transfer_data_items:
if source_obj != target_obj: transfer_data_item.copy_transfer_data_ownership()
if transfer_data_item.type == constants.VERTEX_GROUP_KEY:
logger.debug( if source_obj == target_obj:
f"Transferring Vertex Group {transfer_data_item.name} from {source_obj.name} to {target_obj.name}." return
)
vertex_groups.transfer_vertex_group( if td_type_key == constants.VERTEX_GROUP_KEY:
context=context, # Transfer All Vertex Groups in one go
vertex_group_name=transfer_data_item.name, print(f"Transferring all Vertex Groups from {source_obj.name} to {target_obj.name}")
vertex_groups.transfer_vertex_groups(
vertex_group_names=[item.name for item in transfer_data_items],
target_obj=target_obj, target_obj=target_obj,
source_obj=source_obj, source_obj=source_obj,
) )
if transfer_data_item.type == constants.MODIFIER_KEY: if td_type_key == constants.MODIFIER_KEY:
logger.debug( for transfer_data_item in transfer_data_items:
f"Transferring Modifier{transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
modifers.transfer_modifier( modifers.transfer_modifier(
modifier_name=transfer_data_item.name, modifier_name=transfer_data_item.name,
target_obj=target_obj, target_obj=target_obj,
source_obj=source_obj, source_obj=source_obj,
) )
if transfer_data_item.type == constants.CONSTRAINT_KEY: if td_type_key == constants.CONSTRAINT_KEY:
logger.debug( for transfer_data_item in transfer_data_items:
f"Transferring Constraint {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
constraints.transfer_constraint( constraints.transfer_constraint(
constraint_name=transfer_data_item.name, constraint_name=transfer_data_item.name,
target_obj=target_obj, target_obj=target_obj,
source_obj=source_obj, source_obj=source_obj,
) )
if transfer_data_item.type == constants.MATERIAL_SLOT_KEY: if td_type_key == constants.MATERIAL_SLOT_KEY:
logger.debug(f"Transferring Materiald from {source_obj.name} to {target_obj.name}.") for transfer_data_item in transfer_data_items:
materials.transfer_materials( materials.transfer_materials(
target_obj=target_obj, target_obj=target_obj,
source_obj=source_obj, source_obj=source_obj,
) )
if transfer_data_item.type == constants.SHAPE_KEY_KEY: if td_type_key == constants.SHAPE_KEY_KEY:
logger.debug( for transfer_data_item in transfer_data_items:
f"Transferring Shape Key {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
shape_keys.transfer_shape_key( shape_keys.transfer_shape_key(
context=context, context=context,
target_obj=target_obj, target_obj=target_obj,
source_obj=source_obj, source_obj=source_obj,
shape_key_name=transfer_data_item.name, shape_key_name=transfer_data_item.name,
) )
if transfer_data_item.type == constants.ATTRIBUTE_KEY: if td_type_key == constants.ATTRIBUTE_KEY:
logger.debug( for transfer_data_item in transfer_data_items:
f"Transferring Attribute {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
attributes.transfer_attribute( attributes.transfer_attribute(
target_obj=target_obj, target_obj=target_obj,
source_obj=source_obj, source_obj=source_obj,
attribute_name=transfer_data_item.name, attribute_name=transfer_data_item.name,
) )
if transfer_data_item.type == constants.PARENT_KEY: if td_type_key == constants.PARENT_KEY:
logger.debug( for transfer_data_item in transfer_data_items:
f"Transferring Parent Relationship from {source_obj.name} to {target_obj.name}."
)
parent.transfer_parent( parent.transfer_parent(
target_obj=target_obj, target_obj=target_obj,
source_obj=source_obj, source_obj=source_obj,
) )
logger.debug(
f"Copying Ownership Data for {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
copy_transfer_data_ownership(
transfer_data_item=transfer_data_item,
target_obj=target_obj,
)
transfer_data_item.copy_transfer_data_ownership()
def apply_transfer_data(context: bpy.types.Context, transfer_data_map) -> None: def apply_transfer_data(context: bpy.types.Context, transfer_data_map) -> None:

View File

@ -35,33 +35,26 @@ def init_vertex_groups(scene, obj):
) )
def transfer_vertex_group( def transfer_vertex_groups(
context, vertex_group_names: List[str],
vertex_group_name: str,
target_obj: bpy.types.Object, target_obj: bpy.types.Object,
source_obj: bpy.types.Object, source_obj: bpy.types.Object,
): ):
logger = logging.get_logger() for vertex_group_name in vertex_group_names:
if target_obj == source_obj:
return
if not source_obj.vertex_groups.get(vertex_group_name): if not source_obj.vertex_groups.get(vertex_group_name):
logger.error(f"Vertex Group {vertex_group_name} not found in {source_obj.name}") print(f"ERROR Vertex Group {vertex_group_name} not found in {source_obj.name}")
return return
# If topology matches transfer directly, otherwise use vertex proximity # If topology matches transfer directly, otherwise use vertex proximity
if is_obdata_identical(source_obj, target_obj): if is_obdata_identical(source_obj, target_obj):
transfer_single_vgroup_by_topology( for vertex_group_name in vertex_group_names:
source_obj, target_obj, vertex_group_name transfer_single_vgroup_by_topology(source_obj, target_obj, vertex_group_name)
)
else: else:
precalc_and_transfer_single_group( precalc_and_transfer_multiple_groups(source_obj, target_obj, vertex_group_names, expand=2)
source_obj, target_obj, vertex_group_name, expand=2
)
def transfer_single_vgroup_by_topology(source_obj, target_obj, vgroup_name): def transfer_single_vgroup_by_topology(source_obj, target_obj, vgroup_name):
""" Function to quickly transfer single vertex group between mesh objects in case of matching topology. """Function to quickly transfer single vertex group between mesh objects in case of matching topology."""
"""
# Remove group from the target obj if it already exists. TODO: de-duplicate # Remove group from the target obj if it already exists. TODO: de-duplicate
tgt_vg = target_obj.vertex_groups.get(vgroup_name) tgt_vg = target_obj.vertex_groups.get(vgroup_name)
@ -75,6 +68,33 @@ def transfer_single_vgroup_by_topology(source_obj, target_obj, vgroup_name):
if vgroup_src.index in [g.group for g in v.groups]: if vgroup_src.index in [g.group for g in v.groups]:
vgroup_tgt.add([v.index], vgroup_src.weight(v.index), 'REPLACE') vgroup_tgt.add([v.index], vgroup_src.weight(v.index), 'REPLACE')
def precalc_and_transfer_multiple_groups(source_obj, target_obj, vgroup_names, expand=2):
"""Convenience function to transfer a single group. For transferring multiple groups,
this is very inefficient and shouldn't be used.
Instead, you should:
- build_kd_tree ONCE per source mesh.
- build_vert_influence_map and transfer_vertex_groups ONCE per object pair.
"""
# Remove group from the target obj if it already exists. TODO: de-duplicate
vgroups = [source_obj.vertex_groups[name] for name in vgroup_names]
for vgroup_name in vgroup_names:
target_vgroup = target_obj.vertex_groups.get(vgroup_name)
if target_vgroup:
target_obj.vertex_groups.remove(target_vgroup)
kd_tree = build_kdtree(source_obj.data)
vert_influence_map = build_vert_influence_map(source_obj, target_obj, kd_tree, expand)
transfer_multiple_vertex_groups(
source_obj,
target_obj,
vert_influence_map,
vgroups,
)
def precalc_and_transfer_single_group(source_obj, target_obj, vgroup_name, expand=2): def precalc_and_transfer_single_group(source_obj, target_obj, vgroup_name, expand=2):
"""Convenience function to transfer a single group. For transferring multiple groups, """Convenience function to transfer a single group. For transferring multiple groups,
this is very inefficient and shouldn't be used. this is very inefficient and shouldn't be used.
@ -90,10 +110,9 @@ def precalc_and_transfer_single_group(source_obj, target_obj, vgroup_name, expan
target_obj.vertex_groups.remove(tgt_vg) target_obj.vertex_groups.remove(tgt_vg)
kd_tree = build_kdtree(source_obj.data) kd_tree = build_kdtree(source_obj.data)
vert_influence_map = build_vert_influence_map( vert_influence_map = build_vert_influence_map(source_obj, target_obj, kd_tree, expand)
source_obj, target_obj, kd_tree, expand
) transfer_multiple_vertex_groups(
transfer_vertex_groups(
source_obj, source_obj,
target_obj, target_obj,
vert_influence_map, vert_influence_map,
@ -110,9 +129,7 @@ def build_kdtree(mesh):
def build_vert_influence_map(obj_from, obj_to, kd_tree, expand=2): def build_vert_influence_map(obj_from, obj_to, kd_tree, expand=2):
verts_of_edge = { verts_of_edge = {i: (e.vertices[0], e.vertices[1]) for i, e in enumerate(obj_from.data.edges)}
i: (e.vertices[0], e.vertices[1]) for i, e in enumerate(obj_from.data.edges)
}
edges_of_vert: Dict[int, List[int]] = {} edges_of_vert: Dict[int, List[int]] = {}
for edge_idx, edge in enumerate(obj_from.data.edges): for edge_idx, edge in enumerate(obj_from.data.edges):
@ -166,29 +183,24 @@ def get_source_vert_influences(
parts_sum = sum(parts) parts_sum = sum(parts)
influences = [ influences = [
(idx, 1 if dist == 0 else part / parts_sum) (idx, 1 if dist == 0 else part / parts_sum) for part, dist in zip(parts, distances)
for part, dist in zip(parts, distances)
] ]
return influences return influences
def get_nearest_vert( def get_nearest_vert(coords: Vector, kd_tree: kdtree.KDTree) -> Tuple[Vector, int, float]:
coords: Vector, kd_tree: kdtree.KDTree
) -> Tuple[Vector, int, float]:
"""Return coordinate, index, and distance of nearest vert to coords in kd_tree.""" """Return coordinate, index, and distance of nearest vert to coords in kd_tree."""
return kd_tree.find(coords) return kd_tree.find(coords)
def other_vert_of_edge( def other_vert_of_edge(edge: int, vert: int, verts_of_edge: Dict[int, Tuple[int, int]]) -> int:
edge: int, vert: int, verts_of_edge: Dict[int, Tuple[int, int]]
) -> int:
verts = verts_of_edge[edge] verts = verts_of_edge[edge]
assert vert in verts, f"Vert {vert} not part of edge {edge}." assert vert in verts, f"Vert {vert} not part of edge {edge}."
return verts[0] if vert == verts[1] else verts[1] return verts[0] if vert == verts[1] else verts[1]
def transfer_vertex_groups(obj_from, obj_to, vert_influence_map, src_vgroups): def transfer_multiple_vertex_groups(obj_from, obj_to, vert_influence_map, src_vgroups):
"""Transfer src_vgroups in obj_from to obj_to using a pre-calculated vert_influence_map.""" """Transfer src_vgroups in obj_from to obj_to using a pre-calculated vert_influence_map."""
for src_vg in src_vgroups: for src_vg in src_vgroups: