Asset Pipeline v2 #145

Closed
Nick Alberelli wants to merge 431 commits from (deleted):feature/asset-pipeline-v2 into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
4 changed files with 146 additions and 2 deletions
Showing only changes of commit 1641a433cf - Show all commits

View File

@ -19,6 +19,7 @@ TRANSFER_DATA_TYPES = [
("CONSTRAINT", "Constraint", ""), ("CONSTRAINT", "Constraint", ""),
("MATERIAL", "Material Slot", ""), ("MATERIAL", "Material Slot", ""),
("GROUP_UVS", "UV Maps", ""), ("GROUP_UVS", "UV Maps", ""),
("SHAPEKEY_DATA", "Shape Key", ""),
] ]
TRANSFER_DATA_KEYS = [transfer_data[0] for transfer_data in TRANSFER_DATA_TYPES] TRANSFER_DATA_KEYS = [transfer_data[0] for transfer_data in TRANSFER_DATA_TYPES]
@ -29,7 +30,7 @@ MODIFIER_KEY = TRANSFER_DATA_KEYS[3]
CONSTRAINT_KEY = TRANSFER_DATA_KEYS[4] CONSTRAINT_KEY = TRANSFER_DATA_KEYS[4]
MATERIAL_SLOT_KEY = TRANSFER_DATA_KEYS[5] MATERIAL_SLOT_KEY = TRANSFER_DATA_KEYS[5]
UV_LAYERS_KEY = TRANSFER_DATA_KEYS[6] UV_LAYERS_KEY = TRANSFER_DATA_KEYS[6]
SHAPE_KEY_KEY = TRANSFER_DATA_KEYS[7]
PUBLISH_TYPES = [ PUBLISH_TYPES = [
( (

View File

@ -31,6 +31,7 @@ def transfer_data_clean(obj):
transfer_functions.modifiers_clean(obj) transfer_functions.modifiers_clean(obj)
transfer_functions.constraints_clean(obj) transfer_functions.constraints_clean(obj)
transfer_functions.material_slot_clean(obj) transfer_functions.material_slot_clean(obj)
transfer_functions.shape_keys_clean(obj)
def transfer_data_is_missing(transfer_data_item) -> bool: def transfer_data_is_missing(transfer_data_item) -> bool:
@ -48,6 +49,7 @@ def transfer_data_is_missing(transfer_data_item) -> bool:
or transfer_functions.material_slot_is_missing(transfer_data_item) or transfer_functions.material_slot_is_missing(transfer_data_item)
or transfer_functions.constraint_is_missing(transfer_data_item) or transfer_functions.constraint_is_missing(transfer_data_item)
or transfer_functions.uv_layer_is_missing(transfer_data_item) or transfer_functions.uv_layer_is_missing(transfer_data_item)
or transfer_functions.shape_key_is_missing(transfer_data_item)
) )
@ -68,6 +70,7 @@ def init_transfer_data(
transfer_functions.init_constraints(scene, obj) transfer_functions.init_constraints(scene, obj)
transfer_functions.init_vertex_colors(scene, obj) transfer_functions.init_vertex_colors(scene, obj)
transfer_functions.init_uv_layers(scene, obj) transfer_functions.init_uv_layers(scene, obj)
transfer_functions.init_shap_keys(scene, obj)
def apply_transfer_data(context: bpy.types.Context, transfer_data_map) -> None: def apply_transfer_data(context: bpy.types.Context, transfer_data_map) -> None:
@ -131,6 +134,12 @@ def apply_transfer_data(context: bpy.types.Context, transfer_data_map) -> None:
source_obj=source_obj, source_obj=source_obj,
uv_name=transfer_info.name, uv_name=transfer_info.name,
) )
if transfer_info.type == constants.SHAPE_KEY_KEY:
transfer_functions.transfer_shape_key(
target_obj=target_obj,
source_obj=source_obj,
shape_key_name=transfer_info.name,
)
copy_transfer_data_ownership( copy_transfer_data_ownership(
transfer_data_item=transfer_info, transfer_data_item=transfer_info,

View File

@ -2,6 +2,9 @@ import bpy
from bpy import context from bpy import context
from . import transfer_core from . import transfer_core
from .. import asset_suffix, constants from .. import asset_suffix, constants
import mathutils
import bmesh
import numpy as np
## FUNCTIONS SPECFIC TO TRANSFER DATA TYPES ## FUNCTIONS SPECFIC TO TRANSFER DATA TYPES
@ -315,3 +318,130 @@ def transfer_material_slot(material_slot_name, target_obj, source_obj):
for pol_to, pol_from in zip(target_obj.data.polygons, source_obj.data.polygons): for pol_to, pol_from in zip(target_obj.data.polygons, source_obj.data.polygons):
pol_to.material_index = pol_from.material_index pol_to.material_index = pol_from.material_index
pol_to.use_smooth = pol_from.use_smooth pol_to.use_smooth = pol_from.use_smooth
# SHAPE KEYS
def shape_key_closest_face_to_point(bm_source, p_target, bvh_tree=None):
if not bvh_tree:
bvh_tree = mathutils.bvhtree.BVHTree.FromBMesh(bm_source)
(loc, norm, index, distance) = bvh_tree.find_nearest(p_target)
return bm_source.faces[index]
def shape_key_tris_per_face(bm_source):
tris_source = bm_source.calc_loop_triangles()
tris_dict = dict()
for face in bm_source.faces:
tris_face = []
for i in range(len(tris_source))[::-1]:
if tris_source[i][0] in face.loops:
tris_face.append(tris_source.pop(i))
tris_dict[face] = tris_face
return tris_dict
def shape_key_closest_tri_on_face(tris_dict, face, p):
points = []
dist = []
tris = []
for tri in tris_dict[face]:
point = mathutils.geometry.closest_point_on_tri(
p, *[tri[i].vert.co for i in range(3)]
)
tris.append(tri)
points.append(point)
dist.append((point - p).length)
min_idx = np.argmin(np.array(dist))
point = points[min_idx]
tri = tris[min_idx]
return (tri, point)
def shape_keys_clean(obj):
if obj.type != "MESH" or obj.data.shape_keys is None:
return
transfer_data = obj.transfer_data_ownership
for shape_key in obj.data.shape_keys.key_blocks:
if not asset_suffix.get_basename(shape_key.name) in transfer_data.keys():
obj.shape_key_remove(shape_key)
def shape_key_is_missing(transfer_info):
return transfer_core.transfer_info_is_missing(
transfer_info,
constants.SHAPE_KEY_KEY,
transfer_info.id_data.data.shape_keys.key_blocks,
)
def init_shap_keys(scene, obj):
if obj.type != "MESH" or obj.data.shape_keys is None:
return
transfer_core.transfer_info_init(
scene, obj, obj.data.shape_keys.key_blocks, constants.SHAPE_KEY_KEY
)
def transfer_shape_key(
shape_key_name: str,
target_obj: bpy.types.Object,
source_obj: bpy.types.Object,
):
# BASIS SHAPE KEY MUST BE PASSED FIRST OTHERWISE THIS WILL ERROR OUT
sk_source = source_obj.data.shape_keys.key_blocks.get(shape_key_name)
# TODO Restore Shape Key Index Position after Transfer
# If key is relative to another key that doesn't exist yet
if sk_source.relative_key != sk_source:
relative_key = target_obj.data.shape_keys.key_blocks.get(
sk_source.relative_key.name
)
if not relative_key:
print(
f"Shape Key '{sk_source.name}' failed to find Relative Key '{sk_source.relative_key.name}' on Object '{target_obj.name}'"
)
return
# Remove existing shape keys that match name
if target_obj.data.shape_keys is not None:
old_sk = target_obj.data.shape_keys.key_blocks.get(shape_key_name)
if old_sk:
target_obj.shape_key_remove(old_sk)
sk_target = target_obj.shape_key_add()
sk_target.name = sk_source.name
sk_target.vertex_group = sk_source.vertex_group
sk_target.relative_key = target_obj.data.shape_keys.key_blocks[
sk_source.relative_key.name
]
bm_source = bmesh.new()
bm_source.from_mesh(source_obj.data)
bm_source.faces.ensure_lookup_table()
bvh_tree = mathutils.bvhtree.BVHTree.FromBMesh(bm_source)
tris_dict = shape_key_tris_per_face(bm_source)
for i, vert in enumerate(target_obj.data.vertices):
p = vert.co
face = shape_key_closest_face_to_point(bm_source, p, bvh_tree)
(tri, point) = shape_key_closest_tri_on_face(tris_dict, face, p)
if not tri:
continue
weights = mathutils.interpolate.poly_3d_calc(
[tri[i].vert.co for i in range(3)], point
)
vals_weighted = [
weights[i]
* (
sk_source.data[tri[i].vert.index].co
- source_obj.data.vertices[tri[i].vert.index].co
)
for i in range(3)
]
val = mathutils.Vector(sum(np.array(vals_weighted)))
sk_target.data[i].co = vert.co + val

View File

@ -30,6 +30,7 @@ def draw_transfer_data(
modifiers = [] modifiers = []
constraints = [] constraints = []
uv_layers = [] uv_layers = []
shape_keys = []
for transfer_info in transfer_data: for transfer_info in transfer_data:
if transfer_info.type == constants.VERTEX_GROUP_KEY: if transfer_info.type == constants.VERTEX_GROUP_KEY:
@ -43,7 +44,9 @@ def draw_transfer_data(
if transfer_info.type == constants.CONSTRAINT_KEY: if transfer_info.type == constants.CONSTRAINT_KEY:
constraints.append(transfer_info) constraints.append(transfer_info)
if transfer_info.type == constants.UV_LAYERS_KEY: if transfer_info.type == constants.UV_LAYERS_KEY:
modifiers.append(transfer_info) uv_layers.append(transfer_info)
if transfer_info.type == constants.SHAPE_KEY_KEY:
shape_keys.append(transfer_info)
draw_transfer_data_type(layout, vertex_groups) draw_transfer_data_type(layout, vertex_groups)
draw_transfer_data_type(layout, vertex_colors) draw_transfer_data_type(layout, vertex_colors)
@ -51,3 +54,4 @@ def draw_transfer_data(
draw_transfer_data_type(layout, material_slots) draw_transfer_data_type(layout, material_slots)
draw_transfer_data_type(layout, constraints) draw_transfer_data_type(layout, constraints)
draw_transfer_data_type(layout, uv_layers) draw_transfer_data_type(layout, uv_layers)
draw_transfer_data_type(layout, shape_keys)