Asset Pipeline v2 #145
2
scripts-blender/addons/asset_pipeline_2/.gitignore
vendored
Normal file
2
scripts-blender/addons/asset_pipeline_2/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Temporary for Testing
|
||||||
|
testing/test_chr
|
@ -0,0 +1,74 @@
|
|||||||
|
import bpy
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def import_data_from_lib(
|
||||||
|
libpath: Path,
|
||||||
|
data_category: str,
|
||||||
|
data_name: str,
|
||||||
|
link: bool = False,
|
||||||
|
) -> bpy.data:
|
||||||
|
"""Appends/Links data from an external file into the current file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
libpath (Path): path to .blend file that contains library
|
||||||
|
data_category (str): bpy.types, like object or collection
|
||||||
|
data_name (str): name of datablock to link/append
|
||||||
|
link (bool, optional): Set to link library otherwise append. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bpy.data: returns whichever data_category/type that was linked/appended
|
||||||
|
"""
|
||||||
|
|
||||||
|
noun = "Appended"
|
||||||
|
if link:
|
||||||
|
noun = "Linked"
|
||||||
|
|
||||||
|
with bpy.data.libraries.load(libpath.as_posix(), relative=True, link=link) as (
|
||||||
|
data_from,
|
||||||
|
data_to,
|
||||||
|
):
|
||||||
|
if data_name not in eval(f"data_from.{data_category}"):
|
||||||
|
print(
|
||||||
|
f"Failed to import {data_category} {data_name} from {libpath.as_posix()}. Doesn't exist in file.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if datablock with same name already exists in blend file.
|
||||||
|
try:
|
||||||
|
eval(f"bpy.data.{data_category}['{data_name}']")
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"{data_name} already in bpy.data.{data_category} of this blendfile.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Append data block.
|
||||||
|
eval(f"data_to.{data_category}.append('{data_name}')")
|
||||||
|
print(f"{noun}:{data_name} from library: {libpath.as_posix()}")
|
||||||
|
|
||||||
|
if link:
|
||||||
|
return eval(
|
||||||
|
f"bpy.data.{data_category}['{data_name}', '{bpy.path.relpath(libpath.as_posix())}']"
|
||||||
|
)
|
||||||
|
|
||||||
|
return eval(f"bpy.data.{data_category}['{data_name}']")
|
||||||
|
|
||||||
|
|
||||||
|
## EXECUTION
|
||||||
|
task_layer_name = Path(bpy.data.filepath).name.split(".")[1]
|
||||||
|
task_layer_col = bpy.data.collections[task_layer_name]
|
||||||
|
external_file = (
|
||||||
|
Path(bpy.data.filepath)
|
||||||
|
.parent.parent.parent.joinpath("resources")
|
||||||
|
.joinpath("sky_for_asset_test.blend")
|
||||||
|
)
|
||||||
|
appended_col = import_data_from_lib(
|
||||||
|
external_file, "collections", f"sky.{task_layer_name.lower()}"
|
||||||
|
)
|
||||||
|
bpy.context.scene.collection.children.link(appended_col)
|
||||||
|
|
||||||
|
for obj in appended_col.objects:
|
||||||
|
task_layer_col.objects.link(obj)
|
||||||
|
|
||||||
|
bpy.data.collections.remove(appended_col)
|
@ -0,0 +1,172 @@
|
|||||||
|
import bpy
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def import_data_from_lib(
|
||||||
|
libpath: Path,
|
||||||
|
data_category: str,
|
||||||
|
data_name: str,
|
||||||
|
link: bool = False,
|
||||||
|
) -> bpy.data:
|
||||||
|
"""Appends/Links data from an external file into the current file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
libpath (Path): path to .blend file that contains library
|
||||||
|
data_category (str): bpy.types, like object or collection
|
||||||
|
data_name (str): name of datablock to link/append
|
||||||
|
link (bool, optional): Set to link library otherwise append. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bpy.data: returns whichever data_category/type that was linked/appended
|
||||||
|
"""
|
||||||
|
|
||||||
|
noun = "Appended"
|
||||||
|
if link:
|
||||||
|
noun = "Linked"
|
||||||
|
|
||||||
|
with bpy.data.libraries.load(libpath.as_posix(), relative=True, link=link) as (
|
||||||
|
data_from,
|
||||||
|
data_to,
|
||||||
|
):
|
||||||
|
if data_name not in eval(f"data_from.{data_category}"):
|
||||||
|
print(
|
||||||
|
f"Failed to import {data_category} {data_name} from {libpath.as_posix()}. Doesn't exist in file.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if datablock with same name already exists in blend file.
|
||||||
|
try:
|
||||||
|
eval(f"bpy.data.{data_category}['{data_name}']")
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"{data_name} already in bpy.data.{data_category} of this blendfile.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Append data block.
|
||||||
|
eval(f"data_to.{data_category}.append('{data_name}')")
|
||||||
|
print(f"{noun}:{data_name} from library: {libpath.as_posix()}")
|
||||||
|
|
||||||
|
if link:
|
||||||
|
return eval(
|
||||||
|
f"bpy.data.{data_category}['{data_name}', '{bpy.path.relpath(libpath.as_posix())}']"
|
||||||
|
)
|
||||||
|
|
||||||
|
return eval(f"bpy.data.{data_category}['{data_name}']")
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_constraint(constraint_name, target_obj, source_obj):
|
||||||
|
context = bpy.context
|
||||||
|
# remove old and sync existing modifiers
|
||||||
|
old_mod = target_obj.constraints.get(constraint_name)
|
||||||
|
if old_mod:
|
||||||
|
target_obj.constraints.remove(old_mod)
|
||||||
|
|
||||||
|
# transfer new modifiers
|
||||||
|
for i, constraint in enumerate(source_obj.constraints):
|
||||||
|
if constraint.name == constraint_name:
|
||||||
|
constraint_new = target_obj.constraints.new(constraint.type)
|
||||||
|
constraint_new.name = constraint.name
|
||||||
|
# sort new modifier at correct index (default to beginning of the stack)
|
||||||
|
idx = 0
|
||||||
|
if i > 0:
|
||||||
|
name_prev = source_obj.constraints[i - 1].name
|
||||||
|
for target_mod_i, target_constraint in enumerate(
|
||||||
|
target_obj.constraints
|
||||||
|
):
|
||||||
|
if target_constraint.name == name_prev:
|
||||||
|
idx = target_mod_i + 1
|
||||||
|
|
||||||
|
if idx != i:
|
||||||
|
with override_obj_visability(obj=target_obj):
|
||||||
|
with context.temp_override(object=target_obj):
|
||||||
|
bpy.ops.constraint.move_to_index(
|
||||||
|
constraint=constraint_new.name, index=idx
|
||||||
|
)
|
||||||
|
constraint_target = target_obj.constraints.get(constraint.name)
|
||||||
|
props = [
|
||||||
|
p.identifier for p in constraint.bl_rna.properties if not p.is_readonly
|
||||||
|
]
|
||||||
|
for prop in props:
|
||||||
|
value = getattr(constraint, prop)
|
||||||
|
setattr(constraint_target, prop, value)
|
||||||
|
|
||||||
|
# HACK to cover edge case of armature constraints
|
||||||
|
if constraint.type == "ARMATURE":
|
||||||
|
for target_item in constraint.targets:
|
||||||
|
new_target = constraint_new.targets.new()
|
||||||
|
new_target.target = target_item.target
|
||||||
|
new_target.subtarget = target_item.subtarget
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_vertex_groups(context, target_obj, source_obj):
|
||||||
|
with context.temp_override(
|
||||||
|
object=source_obj, selected_editable_objects=[target_obj, source_obj]
|
||||||
|
):
|
||||||
|
bpy.ops.object.data_transfer(
|
||||||
|
data_type="VGROUP_WEIGHTS",
|
||||||
|
use_create=True,
|
||||||
|
vert_mapping='POLYINTERP_NEAREST',
|
||||||
|
layers_select_src="ALL",
|
||||||
|
layers_select_dst="NAME",
|
||||||
|
mix_mode="REPLACE",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
## EXECUTION
|
||||||
|
task_layer_name = Path(bpy.data.filepath).name.split(".")[1]
|
||||||
|
task_layer_col = bpy.data.collections[task_layer_name]
|
||||||
|
external_file = (
|
||||||
|
Path(bpy.data.filepath)
|
||||||
|
.parent.parent.parent.joinpath("resources")
|
||||||
|
.joinpath("sky_for_asset_test.blend")
|
||||||
|
)
|
||||||
|
appended_col = import_data_from_lib(
|
||||||
|
external_file, "collections", f"sky.{task_layer_name.lower()}"
|
||||||
|
)
|
||||||
|
bpy.context.scene.collection.children.link(appended_col)
|
||||||
|
|
||||||
|
rig = None
|
||||||
|
|
||||||
|
|
||||||
|
# Link Armature into Scene
|
||||||
|
for obj in appended_col.objects:
|
||||||
|
if obj.type == "ARMATURE":
|
||||||
|
task_layer_col.objects.link(obj)
|
||||||
|
rig = obj
|
||||||
|
|
||||||
|
|
||||||
|
for obj in bpy.data.collections["Modeling"].objects:
|
||||||
|
source_obj = bpy.data.objects[f"{obj.name}.rigging"]
|
||||||
|
|
||||||
|
## Set Parent
|
||||||
|
obj.parent = rig
|
||||||
|
obj.matrix_parent_inverse = source_obj.parent.matrix_world.inverted()
|
||||||
|
|
||||||
|
## Transfer Vertex Groups
|
||||||
|
transfer_vertex_groups(bpy.context, obj, source_obj)
|
||||||
|
|
||||||
|
## Copy Constraints
|
||||||
|
for constraint in source_obj.constraints:
|
||||||
|
transfer_constraint(constraint.name, obj, source_obj)
|
||||||
|
|
||||||
|
|
||||||
|
main_body_obj = bpy.data.objects["GEO-Body"]
|
||||||
|
mod = main_body_obj.modifiers.new("Armature", type="ARMATURE")
|
||||||
|
mod.object = rig
|
||||||
|
|
||||||
|
|
||||||
|
for col in appended_col.children:
|
||||||
|
task_layer_col.children.link(col)
|
||||||
|
|
||||||
|
for obj in task_layer_col.all_objects:
|
||||||
|
if obj.name.endswith(".rigging"):
|
||||||
|
obj.name = obj.name.replace(".rigging", "")
|
||||||
|
|
||||||
|
|
||||||
|
## REMOVE EVERYTHING ELSE
|
||||||
|
for obj in bpy.data.objects:
|
||||||
|
if obj.name.endswith(".rigging"):
|
||||||
|
bpy.data.objects.remove(obj)
|
||||||
|
|
||||||
|
bpy.data.collections.remove(appended_col)
|
@ -0,0 +1,126 @@
|
|||||||
|
import bpy
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def import_data_from_lib(
|
||||||
|
libpath: Path,
|
||||||
|
data_category: str,
|
||||||
|
data_name: str,
|
||||||
|
link: bool = False,
|
||||||
|
) -> bpy.data:
|
||||||
|
"""Appends/Links data from an external file into the current file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
libpath (Path): path to .blend file that contains library
|
||||||
|
data_category (str): bpy.types, like object or collection
|
||||||
|
data_name (str): name of datablock to link/append
|
||||||
|
link (bool, optional): Set to link library otherwise append. Defaults to False.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bpy.data: returns whichever data_category/type that was linked/appended
|
||||||
|
"""
|
||||||
|
|
||||||
|
noun = "Appended"
|
||||||
|
if link:
|
||||||
|
noun = "Linked"
|
||||||
|
|
||||||
|
with bpy.data.libraries.load(libpath.as_posix(), relative=True, link=link) as (
|
||||||
|
data_from,
|
||||||
|
data_to,
|
||||||
|
):
|
||||||
|
if data_name not in eval(f"data_from.{data_category}"):
|
||||||
|
print(
|
||||||
|
f"Failed to import {data_category} {data_name} from {libpath.as_posix()}. Doesn't exist in file.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if datablock with same name already exists in blend file.
|
||||||
|
try:
|
||||||
|
eval(f"bpy.data.{data_category}['{data_name}']")
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"{data_name} already in bpy.data.{data_category} of this blendfile.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Append data block.
|
||||||
|
eval(f"data_to.{data_category}.append('{data_name}')")
|
||||||
|
print(f"{noun}:{data_name} from library: {libpath.as_posix()}")
|
||||||
|
|
||||||
|
if link:
|
||||||
|
return eval(
|
||||||
|
f"bpy.data.{data_category}['{data_name}', '{bpy.path.relpath(libpath.as_posix())}']"
|
||||||
|
)
|
||||||
|
|
||||||
|
return eval(f"bpy.data.{data_category}['{data_name}']")
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_material_slots(target_obj: bpy.types.Object, source_obj):
|
||||||
|
# Delete all material slots of target object.
|
||||||
|
target_obj.data.materials.clear()
|
||||||
|
|
||||||
|
# Transfer material slots
|
||||||
|
for idx in range(len(source_obj.material_slots)):
|
||||||
|
target_obj.data.materials.append(source_obj.material_slots[idx].material)
|
||||||
|
target_obj.material_slots[idx].link = source_obj.material_slots[idx].link
|
||||||
|
|
||||||
|
|
||||||
|
def transfer_attribute(
|
||||||
|
attribute_name: str,
|
||||||
|
target_obj: bpy.types.Object,
|
||||||
|
source_obj: bpy.types.Object,
|
||||||
|
):
|
||||||
|
source_attributes = source_obj.data.attributes
|
||||||
|
target_attributes = target_obj.data.attributes
|
||||||
|
source_attribute = source_attributes.get(attribute_name)
|
||||||
|
|
||||||
|
target_attribute = target_attributes.get(attribute_name)
|
||||||
|
if target_attribute:
|
||||||
|
target_attributes.remove(target_attribute)
|
||||||
|
|
||||||
|
target_attribute = target_attributes.new(
|
||||||
|
name=attribute_name,
|
||||||
|
type=source_attribute.data_type,
|
||||||
|
domain=source_attribute.domain,
|
||||||
|
)
|
||||||
|
# print(f"Transfering Attribute {attribute_name}")
|
||||||
|
for source_data_item in source_attribute.data.items():
|
||||||
|
index = source_data_item[0]
|
||||||
|
source_data = source_data_item[1]
|
||||||
|
keys = set(source_data.bl_rna.properties.keys()) - set(
|
||||||
|
bpy.types.Attribute.bl_rna.properties.keys()
|
||||||
|
)
|
||||||
|
for key in list(keys):
|
||||||
|
target_data = target_attribute.data[index]
|
||||||
|
setattr(target_data, key, getattr(source_data, key))
|
||||||
|
|
||||||
|
|
||||||
|
## EXECUTION
|
||||||
|
task_layer_name = Path(bpy.data.filepath).name.split(".")[1]
|
||||||
|
task_layer_col = bpy.data.collections[task_layer_name]
|
||||||
|
external_file = (
|
||||||
|
Path(bpy.data.filepath)
|
||||||
|
.parent.parent.parent.joinpath("resources")
|
||||||
|
.joinpath("sky_for_asset_test.blend")
|
||||||
|
)
|
||||||
|
appended_col = import_data_from_lib(
|
||||||
|
external_file, "collections", f"sky.{task_layer_name.lower()}"
|
||||||
|
)
|
||||||
|
bpy.context.scene.collection.children.link(appended_col)
|
||||||
|
|
||||||
|
source_body_obj = bpy.data.objects["GEO-Body.shading"]
|
||||||
|
target_body_obj = bpy.data.objects["GEO-Body"]
|
||||||
|
|
||||||
|
|
||||||
|
for obj in bpy.data.collections["Modeling"].objects:
|
||||||
|
source_obj = bpy.data.objects[f"{obj.name}.shading"]
|
||||||
|
transfer_material_slots(obj, source_obj)
|
||||||
|
|
||||||
|
transfer_attribute(
|
||||||
|
attribute_name="material_index",
|
||||||
|
target_obj=target_body_obj,
|
||||||
|
source_obj=source_body_obj,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
bpy.data.collections.remove(appended_col)
|
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:221d07c3dc474f9c349b7ce0eaaa9892167b78c373f8418e9d863815b5bb6246
|
||||||
|
size 2054192
|
Loading…
Reference in New Issue
Block a user