feat(Blender): added basics for spliting out (armature) animations
* all boilerplate , including finding relevant armatures & their objects, exporting animations, settings & ui etc added * renamed material library to "split materials" * a ton of related changes
This commit is contained in:
parent
33f2809682
commit
a3ff1b6c1b
|
@ -0,0 +1,96 @@
|
||||||
|
import os
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
from ....core.helpers_collections import traverse_tree
|
||||||
|
from ..common.duplicate_object import copy_animation_data
|
||||||
|
from ..common.generate_temporary_scene_and_export import generate_temporary_scene_and_export
|
||||||
|
from ..common.export_gltf import (generate_gltf_export_settings)
|
||||||
|
|
||||||
|
def duplicate_object(object, destination_collection):
|
||||||
|
copy = None
|
||||||
|
# for objects which are NOT collection instances or when embeding
|
||||||
|
# we create a copy of our object and its children, to leave the original one as it is
|
||||||
|
original_name = object.name
|
||||||
|
#object.name = original_name + "____bak"
|
||||||
|
copy = object.copy()
|
||||||
|
copy.name = original_name
|
||||||
|
|
||||||
|
|
||||||
|
destination_collection.objects.link(copy)
|
||||||
|
copy_animation_data(object, copy)
|
||||||
|
|
||||||
|
animation_data = copy.animation_data
|
||||||
|
print("COPY ANIMATION DATA", animation_data)
|
||||||
|
|
||||||
|
# we want to hide our objects so we only export their bones if any
|
||||||
|
#copy.hide_set(True)
|
||||||
|
|
||||||
|
|
||||||
|
# clear & remove "hollow scene"
|
||||||
|
def clear_animation_scene_alt(temp_scene):
|
||||||
|
# remove any data we created
|
||||||
|
temp_root_collection = temp_scene.collection
|
||||||
|
temp_scene_objects = [o for o in temp_root_collection.all_objects]
|
||||||
|
for object in temp_scene_objects:
|
||||||
|
#print("removing", object.name)
|
||||||
|
bpy.data.objects.remove(object, do_unlink=True)
|
||||||
|
|
||||||
|
# remove the temporary scene
|
||||||
|
bpy.data.scenes.remove(temp_scene, do_unlink=True)
|
||||||
|
|
||||||
|
# reset original names
|
||||||
|
for object in temp_root_collection.all_objects:
|
||||||
|
if object.name.endswith("____bak"):
|
||||||
|
object.name = object.name.replace("____bak", "")
|
||||||
|
|
||||||
|
# generates a scene for a given animated object
|
||||||
|
def generate_animation_scene_content(root_collection, animation):
|
||||||
|
"""for object in animation["objects"]:
|
||||||
|
duplicate_object(object, root_collection)"""
|
||||||
|
armature_object = animation["armature_object"] # we want the object , not the armature itself (the object is a container, and we can only copy objects to our temporary scene, not armatures)
|
||||||
|
print("generate scene for", armature_object)
|
||||||
|
duplicate_object(armature_object, root_collection)
|
||||||
|
#raise Exception("arg")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def clear_animation_scene(temp_scene):
|
||||||
|
print("CLEAR ANIMATION SCENE")
|
||||||
|
root_collection = temp_scene.collection
|
||||||
|
scene_objects = [o for o in root_collection.objects]
|
||||||
|
for object in scene_objects:
|
||||||
|
try:
|
||||||
|
bpy.data.objects.remove(object, do_unlink=True)
|
||||||
|
except:pass
|
||||||
|
|
||||||
|
bpy.data.scenes.remove(temp_scene)
|
||||||
|
|
||||||
|
|
||||||
|
# exports the animations used inside the current project:
|
||||||
|
# see https://forum.babylonjs.com/t/blender-how-to-export-animations-only-like-elf-glft/45716/2
|
||||||
|
# PROBLEM: it grabs the wrong objects !
|
||||||
|
# we need to hide the meshes that have armatures and keep the armature itself
|
||||||
|
def export_animations(animations_to_export, settings, blueprints_data):
|
||||||
|
gltf_export_settings = generate_gltf_export_settings(settings)
|
||||||
|
animations_path_full = getattr(settings,"animations_path_full", "")
|
||||||
|
|
||||||
|
gltf_export_settings = { **gltf_export_settings,
|
||||||
|
'use_active_scene': True,
|
||||||
|
'use_active_collection':True,
|
||||||
|
'use_active_collection_with_nested':True,
|
||||||
|
'use_visible': True,
|
||||||
|
'use_renderable': False,
|
||||||
|
'export_apply':True,
|
||||||
|
'export_animations': True # since we want to export animations , forced to true
|
||||||
|
}
|
||||||
|
for animation in animations_to_export:
|
||||||
|
print("exporting animation from ", animation)
|
||||||
|
gltf_output_path = os.path.join(animations_path_full, animation["armature"].name)
|
||||||
|
|
||||||
|
generate_temporary_scene_and_export(
|
||||||
|
settings=settings,
|
||||||
|
gltf_export_settings=gltf_export_settings,
|
||||||
|
temp_scene_name="__animation_scene"+ animation["armature"].name,
|
||||||
|
gltf_output_path=gltf_output_path,
|
||||||
|
tempScene_filler= lambda temp_collection: generate_animation_scene_content(temp_collection, animation),
|
||||||
|
tempScene_cleaner= lambda temp_scene, params: clear_animation_scene(temp_scene=temp_scene)
|
||||||
|
)
|
|
@ -0,0 +1,103 @@
|
||||||
|
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: move to helpers
|
||||||
|
|
||||||
|
def find_animations_not_on_disk(animations, animations_path_full, extension):
|
||||||
|
not_found_animations = []
|
||||||
|
for animation in animations:
|
||||||
|
gltf_output_path = os.path.join(animations_path_full, animation["armature"].name + extension)
|
||||||
|
# print("gltf_output_path", gltf_output_path)
|
||||||
|
found = os.path.exists(gltf_output_path) and os.path.isfile(gltf_output_path)
|
||||||
|
if not found:
|
||||||
|
not_found_animations.append(animation)
|
||||||
|
return not_found_animations
|
||||||
|
|
||||||
|
def add_animation_info_to_objects(animations_per, settings):
|
||||||
|
materials_path = getattr(settings, "materials_path")
|
||||||
|
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
|
||||||
|
for object in materials_per_object.keys():
|
||||||
|
material_infos = []
|
||||||
|
for material in materials_per_object[object]:
|
||||||
|
materials_exported_path = posixpath.join(materials_path, f"{material.name}{export_gltf_extension}")
|
||||||
|
material_info = f'(name: "{material.name}", path: "{materials_exported_path}")'
|
||||||
|
material_infos.append(material_info)
|
||||||
|
# problem with using actual components: you NEED the type registry/component infos, so if there is none , or it is not loaded yet, it does not work
|
||||||
|
# for a few components we could hardcode this
|
||||||
|
component_value = f"({material_infos})".replace("'","")
|
||||||
|
'''try:
|
||||||
|
bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value )
|
||||||
|
except:'''
|
||||||
|
object['MaterialInfos'] = f"({material_infos})".replace("'","")
|
||||||
|
#upsert_bevy_component(object, "blenvy::blueprints::materials::MaterialInfos", f"({material_infos})".replace("'","") )
|
||||||
|
#apply_propertyGroup_values_to_item_customProperties_for_component(object, "MaterialInfos")
|
||||||
|
print("adding materialInfos to object", object, "material infos", material_infos)
|
||||||
|
|
||||||
|
|
||||||
|
def get_animations_to_export(changed_animations, changed_export_parameters, blueprints_data, settings):
|
||||||
|
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
|
||||||
|
animations_path_full = getattr(settings,"animations_path_full", "")
|
||||||
|
split_out_animations = getattr(settings.auto_export, "split_out_animations")
|
||||||
|
|
||||||
|
change_detection = getattr(settings.auto_export, "change_detection")
|
||||||
|
|
||||||
|
all_animations = []
|
||||||
|
animations_to_export = []
|
||||||
|
objects_per_armature = {}
|
||||||
|
armature_objects = {} # often we need the object of the armature, not the armature itself
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: how to deal with non armatures ?
|
||||||
|
for object in bpy.data.objects:
|
||||||
|
if len(object.modifiers) > 0:
|
||||||
|
for modifier in object.modifiers:
|
||||||
|
if modifier.type == 'ARMATURE':
|
||||||
|
ref = modifier.object.name
|
||||||
|
armature_name = bpy.data.objects[ref].data.name
|
||||||
|
armature = bpy.data.armatures[armature_name]
|
||||||
|
if not armature.name in objects_per_armature :
|
||||||
|
objects_per_armature[armature.name] = []
|
||||||
|
objects_per_armature[armature.name].append(object)
|
||||||
|
armature_objects[armature.name] = modifier.object
|
||||||
|
print("Object has armature", object, modifier, modifier.object, "armature", armature.name)
|
||||||
|
|
||||||
|
|
||||||
|
"""animation_data = object.animation_data
|
||||||
|
if animation_data is not None:
|
||||||
|
print("ANIMATION DATA", animation_data, "for object", object)
|
||||||
|
if len(object.modifiers) > 0:
|
||||||
|
for modifier in object.modifiers:
|
||||||
|
if modifier.type == 'ARMATURE':
|
||||||
|
print("YOHOHOHO", modifier, modifier.object)
|
||||||
|
|
||||||
|
ref = modifier.object.name
|
||||||
|
armature_name = bpy.data.objects[ref].data.name
|
||||||
|
armature = bpy.data.armatures[armature_name]
|
||||||
|
if not armature.name in objects_per_armature :
|
||||||
|
objects_per_armature[armature.name] = []
|
||||||
|
objects_per_armature[armature.name].append(object)"""
|
||||||
|
|
||||||
|
|
||||||
|
#animations_to_export.append(object)
|
||||||
|
for armature_name in objects_per_armature.keys():
|
||||||
|
all_animations.append({"armature": bpy.data.armatures[armature_name], "armature_object": armature_objects[armature_name], "objects": objects_per_armature[armature_name]})
|
||||||
|
|
||||||
|
|
||||||
|
local_animations = [animation for animation in all_animations if animation["armature_object"].library is None]
|
||||||
|
animations_to_export = []
|
||||||
|
|
||||||
|
if split_out_animations and change_detection:
|
||||||
|
if changed_export_parameters:
|
||||||
|
animations_to_export = local_animations
|
||||||
|
else :
|
||||||
|
# first check if all animations have already been exported before (if this is the first time the exporter is run
|
||||||
|
# in your current Blender session for example)
|
||||||
|
animations_not_on_disk = find_animations_not_on_disk(local_animations, animations_path_full, export_gltf_extension)
|
||||||
|
animations_always_export = []
|
||||||
|
animations_to_export = list(set(changed_animations + animations_not_on_disk + animations_always_export))
|
||||||
|
|
||||||
|
print("animations_to_export", animations_to_export)
|
||||||
|
return animations_to_export
|
|
@ -9,7 +9,8 @@ from ..utils import upsert_blueprint_assets, write_blueprint_metadata_file
|
||||||
def export_blueprints(blueprints, settings, blueprints_data):
|
def export_blueprints(blueprints, settings, blueprints_data):
|
||||||
blueprints_path_full = getattr(settings, "blueprints_path_full")
|
blueprints_path_full = getattr(settings, "blueprints_path_full")
|
||||||
gltf_export_settings = generate_gltf_export_settings(settings)
|
gltf_export_settings = generate_gltf_export_settings(settings)
|
||||||
export_materials_library = getattr(settings.auto_export, "export_materials_library")
|
split_out_materials = getattr(settings.auto_export, "split_out_materials")
|
||||||
|
split_out_animations = getattr(settings.auto_export, "split_out_animations")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# save current active collection
|
# save current active collection
|
||||||
|
@ -21,9 +22,12 @@ def export_blueprints(blueprints, settings, blueprints_data):
|
||||||
gltf_export_settings = { **gltf_export_settings, 'use_active_scene': True, 'use_active_collection': True, 'use_active_collection_with_nested':True}
|
gltf_export_settings = { **gltf_export_settings, 'use_active_scene': True, 'use_active_collection': True, 'use_active_collection_with_nested':True}
|
||||||
|
|
||||||
collection = bpy.data.collections[blueprint.name]
|
collection = bpy.data.collections[blueprint.name]
|
||||||
# if we are using the material library option, do not export materials, use placeholder instead
|
# if we are using the split material option, do not export materials, use placeholder instead
|
||||||
if export_materials_library:
|
if split_out_materials:
|
||||||
gltf_export_settings['export_materials'] = 'PLACEHOLDER'
|
gltf_export_settings['export_materials'] = 'PLACEHOLDER'
|
||||||
|
# if we are using the split animations options, do not export animations
|
||||||
|
if split_out_animations:
|
||||||
|
gltf_export_settings['export_animations'] = False
|
||||||
|
|
||||||
# inject blueprint asset data
|
# inject blueprint asset data
|
||||||
upsert_blueprint_assets(blueprint, blueprints_data=blueprints_data, settings=settings)
|
upsert_blueprint_assets(blueprint, blueprints_data=blueprints_data, settings=settings)
|
||||||
|
|
|
@ -16,6 +16,8 @@ from ..materials.get_materials_to_export import get_materials_to_export
|
||||||
from ..materials.export_materials import cleanup_materials, export_materials
|
from ..materials.export_materials import cleanup_materials, export_materials
|
||||||
from ..levels.bevy_scene_components import remove_scene_components, upsert_scene_components
|
from ..levels.bevy_scene_components import remove_scene_components, upsert_scene_components
|
||||||
|
|
||||||
|
from ..animations.get_animations_to_export import get_animations_to_export
|
||||||
|
from ..animations.export_animations import export_animations
|
||||||
|
|
||||||
"""this is the main 'central' function for all auto export """
|
"""this is the main 'central' function for all auto export """
|
||||||
def auto_export(changes_per_scene, changes_per_collection, changes_per_material, changed_export_parameters, settings):
|
def auto_export(changes_per_scene, changes_per_collection, changes_per_material, changed_export_parameters, settings):
|
||||||
|
@ -26,7 +28,8 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
|
||||||
change_detection = getattr(settings.auto_export, "change_detection")
|
change_detection = getattr(settings.auto_export, "change_detection")
|
||||||
export_scene_settings = getattr(settings.auto_export, "export_scene_settings")
|
export_scene_settings = getattr(settings.auto_export, "export_scene_settings")
|
||||||
export_blueprints_enabled = getattr(settings.auto_export, "export_blueprints")
|
export_blueprints_enabled = getattr(settings.auto_export, "export_blueprints")
|
||||||
export_materials_library = getattr(settings.auto_export, "export_materials_library")
|
split_out_materials = getattr(settings.auto_export, "split_out_materials")
|
||||||
|
split_out_animations = getattr(settings.auto_export, "split_out_animations")
|
||||||
|
|
||||||
# standard gltf export settings are stored differently
|
# standard gltf export settings are stored differently
|
||||||
standard_gltf_exporter_settings = get_standard_exporter_settings()
|
standard_gltf_exporter_settings = get_standard_exporter_settings()
|
||||||
|
@ -73,8 +76,11 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
|
||||||
# export materials & inject materials components into relevant objects
|
# export materials & inject materials components into relevant objects
|
||||||
materials_to_export = get_materials_to_export(changes_per_material, changed_export_parameters, blueprints_data, settings)
|
materials_to_export = get_materials_to_export(changes_per_material, changed_export_parameters, blueprints_data, settings)
|
||||||
|
|
||||||
|
# since seperate animation exports also changes blueprint exports we need to call this before blueprints are exported
|
||||||
|
animations_to_export = get_animations_to_export(changes_per_scene, changed_export_parameters, blueprints_data, settings)
|
||||||
|
|
||||||
# update the list of tracked exports
|
# update the list of tracked exports
|
||||||
exports_total = len(blueprints_to_export) + len(level_scenes_to_export) + (1 if export_materials_library else 0)
|
exports_total = len(blueprints_to_export) + len(level_scenes_to_export) + (1 if split_out_materials else 0)
|
||||||
bpy.context.window_manager.auto_export_tracker.exports_total = exports_total
|
bpy.context.window_manager.auto_export_tracker.exports_total = exports_total
|
||||||
bpy.context.window_manager.auto_export_tracker.exports_count = exports_total
|
bpy.context.window_manager.auto_export_tracker.exports_count = exports_total
|
||||||
|
|
||||||
|
@ -101,10 +107,15 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
|
||||||
old_selections = bpy.context.selected_objects
|
old_selections = bpy.context.selected_objects
|
||||||
|
|
||||||
# deal with materials
|
# deal with materials
|
||||||
if export_materials_library and (not change_detection or changed_export_parameters or len(materials_to_export) > 0) :
|
if split_out_materials and (not change_detection or changed_export_parameters or len(materials_to_export) > 0) :
|
||||||
print("export MATERIALS")
|
print("export MATERIALS")
|
||||||
export_materials(materials_to_export, settings, blueprints_data)
|
export_materials(materials_to_export, settings, blueprints_data)
|
||||||
|
|
||||||
|
# and animations
|
||||||
|
if split_out_animations and (not change_detection or changed_export_parameters or len(animations_to_export) > 0):
|
||||||
|
print("export ANIMATIONS")
|
||||||
|
export_animations(animations_to_export, settings, blueprints_data)
|
||||||
|
|
||||||
# export any level/world scenes
|
# export any level/world scenes
|
||||||
if not change_detection or changed_export_parameters or len(level_scenes_to_export) > 0:
|
if not change_detection or changed_export_parameters or len(level_scenes_to_export) > 0:
|
||||||
print("export LEVELS")
|
print("export LEVELS")
|
||||||
|
@ -123,7 +134,7 @@ def auto_export(changes_per_scene, changes_per_collection, changes_per_material,
|
||||||
# reset selections
|
# reset selections
|
||||||
for obj in old_selections:
|
for obj in old_selections:
|
||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
if export_materials_library:
|
if split_out_materials:
|
||||||
cleanup_materials(blueprints_data.blueprint_names, settings.library_scenes)
|
cleanup_materials(blueprints_data.blueprint_names, settings.library_scenes)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -76,7 +76,6 @@ def duplicate_object(object, parent, combine_mode, destination_collection, bluep
|
||||||
internal_blueprint_names = [blueprint.name for blueprint in blueprints_data.internal_blueprints]
|
internal_blueprint_names = [blueprint.name for blueprint in blueprints_data.internal_blueprints]
|
||||||
# print("COMBINE MODE", combine_mode)
|
# print("COMBINE MODE", combine_mode)
|
||||||
if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in internal_blueprint_names)) ):
|
if object.instance_type == 'COLLECTION' and (combine_mode == 'Split' or (combine_mode == 'EmbedExternal' and (object.instance_collection.name in internal_blueprint_names)) ):
|
||||||
#print("creating empty for", object.name, object.instance_collection.name, internal_blueprint_names, combine_mode)
|
|
||||||
original_collection = object.instance_collection
|
original_collection = object.instance_collection
|
||||||
original_name = object.name
|
original_name = object.name
|
||||||
blueprint_name = original_collection.name
|
blueprint_name = original_collection.name
|
||||||
|
|
|
@ -192,10 +192,10 @@ def mesh_hash(obj):
|
||||||
h = str(h1_hash(vertices_np.tobytes()))
|
h = str(h1_hash(vertices_np.tobytes()))
|
||||||
return h
|
return h
|
||||||
|
|
||||||
# TODO: redo this one, this is essentially modifiec copy & pasted data, not fitting
|
# TODO: redo this one, this is essentially modified copy & pasted data, not fitting
|
||||||
def animation_hash(obj):
|
def animation_hash(obj):
|
||||||
animation_data = obj.animation_data
|
animation_data = obj.animation_data
|
||||||
if not animation_data:
|
if animation_data is None:
|
||||||
return None
|
return None
|
||||||
blender_actions = []
|
blender_actions = []
|
||||||
blender_tracks = {}
|
blender_tracks = {}
|
||||||
|
|
|
@ -18,7 +18,7 @@ parameter_names_whitelist_auto_export = [
|
||||||
'export_scene_settings',
|
'export_scene_settings',
|
||||||
'export_blueprints',
|
'export_blueprints',
|
||||||
'export_separate_dynamic_and_static_objects',
|
'export_separate_dynamic_and_static_objects',
|
||||||
'export_materials_library',
|
'split_out_materials',
|
||||||
'collection_instances_combine_mode',
|
'collection_instances_combine_mode',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,6 @@ def clear_materials_scene(temp_scene):
|
||||||
bpy.data.scenes.remove(temp_scene)
|
bpy.data.scenes.remove(temp_scene)
|
||||||
|
|
||||||
# exports the materials used inside the current project:
|
# exports the materials used inside the current project:
|
||||||
# the name of the output path is <materials_folder>/<name_of_your_blend_file>_materials_library.gltf/glb
|
|
||||||
def export_materials(materials_to_export, settings, blueprints_data):
|
def export_materials(materials_to_export, settings, blueprints_data):
|
||||||
gltf_export_settings = generate_gltf_export_settings(settings)
|
gltf_export_settings = generate_gltf_export_settings(settings)
|
||||||
materials_path_full = getattr(settings,"materials_path_full")
|
materials_path_full = getattr(settings,"materials_path_full")
|
||||||
|
|
|
@ -4,19 +4,17 @@ from ....materials.materials_helpers import find_materials_not_on_disk
|
||||||
|
|
||||||
def get_materials_to_export(changes_per_material, changed_export_parameters, blueprints_data, settings):
|
def get_materials_to_export(changes_per_material, changed_export_parameters, blueprints_data, settings):
|
||||||
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
|
export_gltf_extension = getattr(settings, "export_gltf_extension", ".glb")
|
||||||
blueprints_path_full = getattr(settings,"blueprints_path_full", "")
|
|
||||||
materials_path_full = getattr(settings, "materials_path_full", "")
|
materials_path_full = getattr(settings, "materials_path_full", "")
|
||||||
|
|
||||||
change_detection = getattr(settings.auto_export, "change_detection")
|
change_detection = getattr(settings.auto_export, "change_detection")
|
||||||
export_materials_library = getattr(settings.auto_export, "export_materials_library")
|
split_out_materials = getattr(settings.auto_export, "split_out_materials")
|
||||||
collection_instances_combine_mode = getattr(settings.auto_export, "collection_instances_combine_mode")
|
|
||||||
|
|
||||||
all_materials = bpy.data.materials
|
all_materials = bpy.data.materials
|
||||||
local_materials = [material for material in all_materials if material.library is None]
|
local_materials = [material for material in all_materials if material.library is None]
|
||||||
materials_to_export = []
|
materials_to_export = []
|
||||||
|
|
||||||
# print("export_materials_library", export_materials_library, "change detection", change_detection, "changed_export_parameters", changed_export_parameters)
|
# print("split_out_materials", split_out_materials, "change detection", change_detection, "changed_export_parameters", changed_export_parameters)
|
||||||
if export_materials_library and change_detection:
|
if split_out_materials and change_detection:
|
||||||
if changed_export_parameters:
|
if changed_export_parameters:
|
||||||
materials_to_export = local_materials
|
materials_to_export = local_materials
|
||||||
else :
|
else :
|
||||||
|
|
|
@ -72,13 +72,19 @@ class AutoExportSettings(PropertyGroup):
|
||||||
update=save_settings
|
update=save_settings
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
export_materials_library: BoolProperty(
|
split_out_materials: BoolProperty(
|
||||||
name='Export materials library',
|
name='Split out materials',
|
||||||
description='remove materials from blueprints and use the material library instead',
|
description='removes materials from blueprints and exports them separately ',
|
||||||
default=True,
|
default=True,
|
||||||
update=save_settings
|
update=save_settings
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
|
split_out_animations: BoolProperty(
|
||||||
|
name='Split out animations',
|
||||||
|
description='removes animations/armatures from blueprints and exports them separately ',
|
||||||
|
default=False,
|
||||||
|
update=save_settings
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
""" combine mode can be
|
""" combine mode can be
|
||||||
- 'Split' (default): replace with an empty, creating links to sub blueprints
|
- 'Split' (default): replace with an empty, creating links to sub blueprints
|
||||||
|
|
|
@ -57,7 +57,10 @@ def draw_settings_ui(layout, auto_export_settings):
|
||||||
section.separator()
|
section.separator()
|
||||||
|
|
||||||
# materials
|
# materials
|
||||||
section.prop(auto_export_settings, "export_materials_library")
|
section.prop(auto_export_settings, "split_out_materials")
|
||||||
|
|
||||||
|
# animations
|
||||||
|
section.prop(auto_export_settings, "split_out_animations")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,5 +25,5 @@ def inject_export_path_into_internal_blueprints(internal_blueprints, blueprints_
|
||||||
blueprint_exported_path = posixpath.join(blueprints_path, f"{blueprint.name}{gltf_extension}")
|
blueprint_exported_path = posixpath.join(blueprints_path, f"{blueprint.name}{gltf_extension}")
|
||||||
# print("injecting blueprint path", blueprint_exported_path, "for", blueprint.name)
|
# print("injecting blueprint path", blueprint_exported_path, "for", blueprint.name)
|
||||||
blueprint.collection["export_path"] = blueprint_exported_path
|
blueprint.collection["export_path"] = blueprint_exported_path
|
||||||
"""if export_materials_library:
|
"""if split_out_materials:
|
||||||
blueprint.collection["materials_path"] = materials_exported_path"""
|
blueprint.collection["materials_path"] = materials_exported_path"""
|
||||||
|
|
|
@ -115,16 +115,28 @@ class BlenvyManager(PropertyGroup):
|
||||||
|
|
||||||
materials_path: StringProperty(
|
materials_path: StringProperty(
|
||||||
name='Materials path',
|
name='Materials path',
|
||||||
description='path to export the materials libraries to (relative to the assets folder)',
|
description='path to export the materials to (relative to the assets folder)',
|
||||||
default='materials',
|
default='materials',
|
||||||
update= save_settings
|
update= save_settings
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
# computed property for the absolute path of blueprints
|
# computed property for the absolute path of materials
|
||||||
materials_path_full: StringProperty(
|
materials_path_full: StringProperty(
|
||||||
get=lambda self: os.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), self.project_root_path, self.assets_path, self.materials_path))
|
get=lambda self: os.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), self.project_root_path, self.assets_path, self.materials_path))
|
||||||
) # type: ignore
|
) # type: ignore
|
||||||
|
|
||||||
|
animations_path: StringProperty(
|
||||||
|
name='Animations path',
|
||||||
|
description='path to export the animations to (relative to the assets folder)',
|
||||||
|
default='animations',
|
||||||
|
update= save_settings
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
|
# computed property for the absolute path of animations
|
||||||
|
animations_path_full: StringProperty(
|
||||||
|
get=lambda self: os.path.abspath(os.path.join(os.path.dirname(bpy.data.filepath), self.project_root_path, self.assets_path, self.animations_path))
|
||||||
|
) # type: ignore
|
||||||
|
|
||||||
# sub ones
|
# sub ones
|
||||||
auto_export: PointerProperty(type=AutoExportSettings) # type: ignore
|
auto_export: PointerProperty(type=AutoExportSettings) # type: ignore
|
||||||
components: PointerProperty(type=ComponentsSettings) # type: ignore
|
components: PointerProperty(type=ComponentsSettings) # type: ignore
|
||||||
|
|
|
@ -121,6 +121,8 @@ def draw_common_settings_ui(layout, settings):
|
||||||
draw_folder_browser(layout=row, label="Levels Folder", prop_origin=blenvy, target_property="levels_path")
|
draw_folder_browser(layout=row, label="Levels Folder", prop_origin=blenvy, target_property="levels_path")
|
||||||
row = layout.row()
|
row = layout.row()
|
||||||
draw_folder_browser(layout=row, label="Materials Folder", prop_origin=blenvy, target_property="materials_path")
|
draw_folder_browser(layout=row, label="Materials Folder", prop_origin=blenvy, target_property="materials_path")
|
||||||
|
row = layout.row()
|
||||||
|
draw_folder_browser(layout=row, label="Animations Folder", prop_origin=blenvy, target_property="animations_path")
|
||||||
|
|
||||||
layout.separator()
|
layout.separator()
|
||||||
# scenes selection
|
# scenes selection
|
||||||
|
|
|
@ -93,9 +93,9 @@ def add_material_info_to_objects(materials_per_object, settings):
|
||||||
# problem with using actual components: you NEED the type registry/component infos, so if there is none , or it is not loaded yet, it does not work
|
# problem with using actual components: you NEED the type registry/component infos, so if there is none , or it is not loaded yet, it does not work
|
||||||
# for a few components we could hardcode this
|
# for a few components we could hardcode this
|
||||||
component_value = f"({material_infos})".replace("'","")
|
component_value = f"({material_infos})".replace("'","")
|
||||||
try:
|
'''try:
|
||||||
bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value )
|
bpy.ops.blenvy.component_add(target_item_name=object.name, target_item_type="OBJECT", component_type="blenvy::blueprints::materials::MaterialInfos", component_value=component_value )
|
||||||
except:
|
except:'''
|
||||||
object['MaterialInfos'] = f"({material_infos})".replace("'","")
|
object['MaterialInfos'] = f"({material_infos})".replace("'","")
|
||||||
#upsert_bevy_component(object, "blenvy::blueprints::materials::MaterialInfos", f"({material_infos})".replace("'","") )
|
#upsert_bevy_component(object, "blenvy::blueprints::materials::MaterialInfos", f"({material_infos})".replace("'","") )
|
||||||
#apply_propertyGroup_values_to_item_customProperties_for_component(object, "MaterialInfos")
|
#apply_propertyGroup_values_to_item_customProperties_for_component(object, "MaterialInfos")
|
||||||
|
|
|
@ -106,7 +106,7 @@ def test_export_complex(setup_data):
|
||||||
blenvy.auto_export.auto_export = True
|
blenvy.auto_export.auto_export = True
|
||||||
blenvy.auto_export.export_scene_settings = True
|
blenvy.auto_export.export_scene_settings = True
|
||||||
blenvy.auto_export.export_blueprints = True
|
blenvy.auto_export.export_blueprints = True
|
||||||
blenvy.auto_export.export_materials_library = True
|
blenvy.auto_export.split_out_materials = True
|
||||||
|
|
||||||
bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene
|
bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene
|
||||||
bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene
|
bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene
|
||||||
|
|
|
@ -53,7 +53,7 @@ def test_export_external_blueprints(setup_data):
|
||||||
blenvy.auto_export.auto_export = True
|
blenvy.auto_export.auto_export = True
|
||||||
blenvy.auto_export.export_scene_settings = True
|
blenvy.auto_export.export_scene_settings = True
|
||||||
blenvy.auto_export.export_blueprints = True
|
blenvy.auto_export.export_blueprints = True
|
||||||
#blenvy.auto_export.export_materials_library = True
|
#blenvy.auto_export.split_out_materials = True
|
||||||
|
|
||||||
print("SCENES", bpy.data.scenes)
|
print("SCENES", bpy.data.scenes)
|
||||||
for scene in bpy.data.scenes:
|
for scene in bpy.data.scenes:
|
||||||
|
|
|
@ -107,7 +107,7 @@ def test_export_complex(setup_data):
|
||||||
blenvy.auto_export.auto_export = True
|
blenvy.auto_export.auto_export = True
|
||||||
blenvy.auto_export.export_scene_settings = True
|
blenvy.auto_export.export_scene_settings = True
|
||||||
blenvy.auto_export.export_blueprints = True
|
blenvy.auto_export.export_blueprints = True
|
||||||
blenvy.auto_export.export_materials_library = True
|
blenvy.auto_export.split_out_materials = True
|
||||||
|
|
||||||
bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene
|
bpy.data.scenes['World'].blenvy_scene_type = 'Level' # set scene as main/level scene
|
||||||
bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene
|
bpy.data.scenes['Library'].blenvy_scene_type = 'Library' # set scene as Library scene
|
||||||
|
|
|
@ -81,7 +81,7 @@ def test_export_no_parameters(setup_data):
|
||||||
auto_export_operator(
|
auto_export_operator(
|
||||||
auto_export=True,
|
auto_export=True,
|
||||||
direct_mode=True,
|
direct_mode=True,
|
||||||
export_materials_library=True,
|
split_out_materials=True,
|
||||||
project_root_path = os.path.abspath(setup_data["root_path"]),
|
project_root_path = os.path.abspath(setup_data["root_path"]),
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
)
|
)
|
||||||
|
@ -106,7 +106,7 @@ def test_export_auto_export_parameters_only(setup_data):
|
||||||
direct_mode=True,
|
direct_mode=True,
|
||||||
project_root_path = os.path.abspath(setup_data["root_path"]),
|
project_root_path = os.path.abspath(setup_data["root_path"]),
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_materials_library=True
|
split_out_materials=True
|
||||||
)
|
)
|
||||||
|
|
||||||
world_file_path = os.path.join(setup_data["levels_path"], "World.glb")
|
world_file_path = os.path.join(setup_data["levels_path"], "World.glb")
|
||||||
|
@ -144,7 +144,7 @@ def test_export_changed_parameters(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library=True
|
split_out_materials=True
|
||||||
)
|
)
|
||||||
|
|
||||||
world_file_path = os.path.join(setup_data["levels_path"], "World.glb")
|
world_file_path = os.path.join(setup_data["levels_path"], "World.glb")
|
||||||
|
@ -163,7 +163,7 @@ def test_export_changed_parameters(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library=True
|
split_out_materials=True
|
||||||
)
|
)
|
||||||
|
|
||||||
modification_times_no_change = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
modification_times_no_change = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
||||||
|
@ -188,7 +188,7 @@ def test_export_changed_parameters(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library=True
|
split_out_materials=True
|
||||||
)
|
)
|
||||||
|
|
||||||
modification_times_changed_gltf = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
modification_times_changed_gltf = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
||||||
|
@ -204,7 +204,7 @@ def test_export_changed_parameters(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library=True
|
split_out_materials=True
|
||||||
)
|
)
|
||||||
|
|
||||||
modification_times_changed_gltf = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
modification_times_changed_gltf = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
||||||
|
@ -218,7 +218,7 @@ def test_export_changed_parameters(setup_data):
|
||||||
export_props = {
|
export_props = {
|
||||||
"level_scene_names" : ['World'],
|
"level_scene_names" : ['World'],
|
||||||
"library_scene_names": ['Library'],
|
"library_scene_names": ['Library'],
|
||||||
"export_materials_library": False # we need to add it here, as the direct settings set on the operator will only be used for the NEXT run
|
"split_out_materials": False # we need to add it here, as the direct settings set on the operator will only be used for the NEXT run
|
||||||
}
|
}
|
||||||
|
|
||||||
# store settings for the auto_export part
|
# store settings for the auto_export part
|
||||||
|
@ -233,7 +233,7 @@ def test_export_changed_parameters(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library=False
|
split_out_materials=False
|
||||||
)
|
)
|
||||||
|
|
||||||
modification_times_changed_auto = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
modification_times_changed_auto = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
||||||
|
@ -249,7 +249,7 @@ def test_export_changed_parameters(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library=False
|
split_out_materials=False
|
||||||
)
|
)
|
||||||
|
|
||||||
modification_times_changed_gltf = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
modification_times_changed_gltf = list(map(lambda file_path: os.path.getmtime(file_path), model_library_file_paths))
|
||||||
|
|
|
@ -137,7 +137,7 @@ def test_export_materials_library(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library = True
|
split_out_materials = True
|
||||||
)
|
)
|
||||||
|
|
||||||
assert os.path.exists(os.path.join(setup_data["blueprints_path"], "Blueprint1.glb")) == True
|
assert os.path.exists(os.path.join(setup_data["blueprints_path"], "Blueprint1.glb")) == True
|
||||||
|
@ -164,7 +164,7 @@ def test_export_materials_library_custom_path(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library = True,
|
split_out_materials = True,
|
||||||
materials_path="assets/other_materials"
|
materials_path="assets/other_materials"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ def run_auto_export(setup_data):
|
||||||
export_output_folder="./models",
|
export_output_folder="./models",
|
||||||
export_scene_settings=True,
|
export_scene_settings=True,
|
||||||
export_blueprints=True,
|
export_blueprints=True,
|
||||||
export_materials_library=False
|
split_out_materials=False
|
||||||
)
|
)
|
||||||
|
|
||||||
levels_path = setup_data["levels_path"]
|
levels_path = setup_data["levels_path"]
|
||||||
|
|
Loading…
Reference in New Issue