Asset Pipeline v2 #145
@ -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 = [
|
||||||
(
|
(
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user