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]):
for transfer_data_item in transfer_data_items:
target_obj = transfer_data_item.target_obj
source_obj = transfer_data_item.obj
# Get source/target from first item in list, because all items in list are same object/type
target_obj = transfer_data_items[0].target_obj
source_obj = transfer_data_items[0].obj
if target_obj is None:
logger.warning(f"Failed to Transfer Data for {transfer_data_item.id_data.name}")
continue
if transfer_data_item is None:
continue
if source_obj != target_obj:
if transfer_data_item.type == constants.VERTEX_GROUP_KEY:
logger.debug(
f"Transferring Vertex Group {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
vertex_groups.transfer_vertex_group(
context=context,
vertex_group_name=transfer_data_item.name,
print(f"Failed to Transfer Data for {transfer_data_item.id_data.name}")
return
for transfer_data_item in transfer_data_items:
transfer_data_item.copy_transfer_data_ownership()
if source_obj == target_obj:
return
if td_type_key == constants.VERTEX_GROUP_KEY:
# Transfer All Vertex Groups in one go
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,
source_obj=source_obj,
)
if transfer_data_item.type == constants.MODIFIER_KEY:
logger.debug(
f"Transferring Modifier{transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
if td_type_key == constants.MODIFIER_KEY:
for transfer_data_item in transfer_data_items:
modifers.transfer_modifier(
modifier_name=transfer_data_item.name,
target_obj=target_obj,
source_obj=source_obj,
)
if transfer_data_item.type == constants.CONSTRAINT_KEY:
logger.debug(
f"Transferring Constraint {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
if td_type_key == constants.CONSTRAINT_KEY:
for transfer_data_item in transfer_data_items:
constraints.transfer_constraint(
constraint_name=transfer_data_item.name,
target_obj=target_obj,
source_obj=source_obj,
)
if transfer_data_item.type == constants.MATERIAL_SLOT_KEY:
logger.debug(f"Transferring Materiald from {source_obj.name} to {target_obj.name}.")
if td_type_key == constants.MATERIAL_SLOT_KEY:
for transfer_data_item in transfer_data_items:
materials.transfer_materials(
target_obj=target_obj,
source_obj=source_obj,
)
if transfer_data_item.type == constants.SHAPE_KEY_KEY:
logger.debug(
f"Transferring Shape Key {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
if td_type_key == constants.SHAPE_KEY_KEY:
for transfer_data_item in transfer_data_items:
shape_keys.transfer_shape_key(
context=context,
target_obj=target_obj,
source_obj=source_obj,
shape_key_name=transfer_data_item.name,
)
if transfer_data_item.type == constants.ATTRIBUTE_KEY:
logger.debug(
f"Transferring Attribute {transfer_data_item.name} from {source_obj.name} to {target_obj.name}."
)
if td_type_key == constants.ATTRIBUTE_KEY:
for transfer_data_item in transfer_data_items:
attributes.transfer_attribute(
target_obj=target_obj,
source_obj=source_obj,
attribute_name=transfer_data_item.name,
)
if transfer_data_item.type == constants.PARENT_KEY:
logger.debug(
f"Transferring Parent Relationship from {source_obj.name} to {target_obj.name}."
)
if td_type_key == constants.PARENT_KEY:
for transfer_data_item in transfer_data_items:
parent.transfer_parent(
target_obj=target_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:

View File

@ -35,33 +35,26 @@ def init_vertex_groups(scene, obj):
)
def transfer_vertex_group(
context,
vertex_group_name: str,
def transfer_vertex_groups(
vertex_group_names: List[str],
target_obj: bpy.types.Object,
source_obj: bpy.types.Object,
):
logger = logging.get_logger()
if target_obj == source_obj:
return
for vertex_group_name in vertex_group_names:
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
# If topology matches transfer directly, otherwise use vertex proximity
if is_obdata_identical(source_obj, target_obj):
transfer_single_vgroup_by_topology(
source_obj, target_obj, vertex_group_name
)
for vertex_group_name in vertex_group_names:
transfer_single_vgroup_by_topology(source_obj, target_obj, vertex_group_name)
else:
precalc_and_transfer_single_group(
source_obj, target_obj, vertex_group_name, expand=2
)
precalc_and_transfer_multiple_groups(source_obj, target_obj, vertex_group_names, expand=2)
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
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]:
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):
"""Convenience function to transfer a single group. For transferring multiple groups,
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)
kd_tree = build_kdtree(source_obj.data)
vert_influence_map = build_vert_influence_map(
source_obj, target_obj, kd_tree, expand
)
transfer_vertex_groups(
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,
@ -110,9 +129,7 @@ def build_kdtree(mesh):
def build_vert_influence_map(obj_from, obj_to, kd_tree, expand=2):
verts_of_edge = {
i: (e.vertices[0], e.vertices[1]) for i, e in enumerate(obj_from.data.edges)
}
verts_of_edge = {i: (e.vertices[0], e.vertices[1]) for i, e in enumerate(obj_from.data.edges)}
edges_of_vert: Dict[int, List[int]] = {}
for edge_idx, edge in enumerate(obj_from.data.edges):
@ -166,29 +183,24 @@ def get_source_vert_influences(
parts_sum = sum(parts)
influences = [
(idx, 1 if dist == 0 else part / parts_sum)
for part, dist in zip(parts, distances)
(idx, 1 if dist == 0 else part / parts_sum) for part, dist in zip(parts, distances)
]
return influences
def get_nearest_vert(
coords: Vector, kd_tree: kdtree.KDTree
) -> Tuple[Vector, int, float]:
def get_nearest_vert(coords: Vector, kd_tree: kdtree.KDTree) -> Tuple[Vector, int, float]:
"""Return coordinate, index, and distance of nearest vert to coords in kd_tree."""
return kd_tree.find(coords)
def other_vert_of_edge(
edge: int, vert: int, verts_of_edge: Dict[int, Tuple[int, int]]
) -> int:
def other_vert_of_edge(edge: int, vert: int, verts_of_edge: Dict[int, Tuple[int, int]]) -> int:
verts = verts_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]
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."""
for src_vg in src_vgroups: