From 95437a452772bd5745e12ccc9fb2025123ec31c7 Mon Sep 17 00:00:00 2001 From: brothermechanic Date: Wed, 8 Feb 2023 10:47:54 +0300 Subject: [PATCH] subassembly models setup from SDFormat file --- cg/blender/export/collision.py | 42 ++++++++++++++++++ cg/blender/export/dae.py | 2 +- cg/blender/export/obj.py | 2 +- cg/blender/export/stl.py | 10 +---- cg/pipeline/README.md | 22 +++++++++- cg/pipeline/asp_sdf_to_asset.py | 77 +++++++++++++++++++++++++++++++++ cg/pipeline/freecad_to_asset.py | 4 +- 7 files changed, 145 insertions(+), 14 deletions(-) create mode 100644 cg/blender/export/collision.py create mode 100644 cg/pipeline/asp_sdf_to_asset.py diff --git a/cg/blender/export/collision.py b/cg/blender/export/collision.py new file mode 100644 index 0000000..b75f4e0 --- /dev/null +++ b/cg/blender/export/collision.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +""" +DESCRIPTION. +STL mesh exporter. +Exports all objects in scene. +You can set export path and subdir. +""" +__version__ = "0.1" + +import logging +import sys +import bpy +import os + +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + + +def export_col_stl(path, subdir=""): + """ STL mesh exporter. Exports all objects in scene. """ + for ob in bpy.context.scene.objects: + # deselect all but just one object and make it active + bpy.ops.object.select_all(action='DESELECT') + ob.select_set(state=True) + bpy.context.view_layer.objects.active = ob + filename = bpy.context.active_object.name + # create collision hull mesh + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + bpy.ops.mesh.convex_hull() + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.modifier_add(type='DECIMATE') + bpy.context.object.modifiers["Decimate"].ratio = 0.2 + + # export stl + stl_path = os.path.join(path, subdir).replace('\\', '/') + if not os.path.isdir(stl_path): + os.makedirs(stl_path) + outpath = os.path.join(stl_path, filename+'.stl') + logger.debug('collision:', outpath) + + bpy.ops.export_mesh.stl(filepath=outpath, check_existing=False, filter_glob='*.stl', use_selection=True, global_scale=1.0, use_scene_unit=False, ascii=False, use_mesh_modifiers=True, batch_mode='OFF', axis_forward='Y', axis_up='Z') diff --git a/cg/blender/export/dae.py b/cg/blender/export/dae.py index 7c432f8..b85a2b0 100644 --- a/cg/blender/export/dae.py +++ b/cg/blender/export/dae.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) -def export_dae(path, subdir="dae"): +def export_dae(path, subdir=""): """ Collada mesh exporter. Exports all objects in scene. """ for ob in bpy.context.scene.objects: # deselect all but just one object and make it active diff --git a/cg/blender/export/obj.py b/cg/blender/export/obj.py index 17ea293..c5f12ff 100644 --- a/cg/blender/export/obj.py +++ b/cg/blender/export/obj.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) -def export_obj(path, subdir="obj"): +def export_obj(path, subdir=""): """ OBJ mesh exporter. Exports all objects in scene. """ for ob in bpy.context.scene.objects: # deselect all but just one object and make it active diff --git a/cg/blender/export/stl.py b/cg/blender/export/stl.py index 61b1697..fd5d5cd 100644 --- a/cg/blender/export/stl.py +++ b/cg/blender/export/stl.py @@ -16,7 +16,7 @@ logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) -def export_stl(path, subdir="stl"): +def export_stl(path, subdir=""): """ STL mesh exporter. Exports all objects in scene. """ for ob in bpy.context.scene.objects: # deselect all but just one object and make it active @@ -24,14 +24,6 @@ def export_stl(path, subdir="stl"): ob.select_set(state=True) bpy.context.view_layer.objects.active = ob filename = bpy.context.active_object.name - # create collision hull mesh - bpy.ops.object.mode_set(mode='EDIT') - bpy.ops.mesh.select_all(action='SELECT') - bpy.ops.mesh.convex_hull() - bpy.ops.object.mode_set(mode='OBJECT') - bpy.ops.object.modifier_add(type='DECIMATE') - bpy.context.object.modifiers["Decimate"].ratio = 0.2 - # export stl stl_path = os.path.join(path, subdir).replace('\\', '/') if not os.path.isdir(stl_path): diff --git a/cg/pipeline/README.md b/cg/pipeline/README.md index 3912997..99d92bc 100644 --- a/cg/pipeline/README.md +++ b/cg/pipeline/README.md @@ -1,4 +1,6 @@ -## Пакетное производство 3д ассетов из объектов сцены Freecad +### freecad_to_asset.py + +Пакетное производство 3д ассетов из объектов сцены Freecad Поддерживается работа поверх Blender в качестве модуля! @@ -10,3 +12,21 @@ - обработку mesh объектов для использования в качестве ассетов - импорт FEM материалов и назначение их для mesh объектов - экспорт mesh объектов в требуемые форматы + +### asp_sdf_to_asset.py + +Пакетное производство 3д ассетов из объектов сцены Freecad по описанию Генератора подсборок ASP + +Поддерживается работа поверх Blender в качестве модуля! + +Сценарий производит: +- импорт solid объектов в Blender сцену +- имена solid объектов в mesh объекты +- тесселяцию solid объектов с заданным уровнем +- выбор состава подсборки из SDF файла описания +- позиция деталей подсборки из SDF файла описания +- ретопологию mesh объектов с заданным уровнем +- обработку mesh объектов для использования в качестве ассетов +- импорт FEM материалов и назначение их для mesh объектов +- экспорт mesh объектов в STL mesh +- экспорт ассета подсборки BLEND diff --git a/cg/pipeline/asp_sdf_to_asset.py b/cg/pipeline/asp_sdf_to_asset.py new file mode 100644 index 0000000..f67a82e --- /dev/null +++ b/cg/pipeline/asp_sdf_to_asset.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +""" +DESCRIPTION. +Subassembly models setup from SDFormat file. +Script selected, transform, exported subassembly models. +Support Blender compiled as a Python Module only! +""" +__version__ = "0.1" + +import logging +import sys +import xml.etree.ElementTree as ET +import os +sys.path.append('../blender/') +from import_fcstd.importer import importer +from utils.remove_collections import remove_collections +from utils.cleanup_orphan_data import cleanup_orphan_data +from remesh import asset_setup +from export.stl import export_stl + +sys.path.append('/home/bm/bin/blender-git/blender_bin') # import blender module +import bpy + +logger = logging.getLogger(__name__) +logging.basicConfig(level=logging.INFO) + + +def sdf_to_subassembly(assembly_path): + """ Setup scene by SDFormat file description """ + assembly_sdf = os.path.join(assembly_path, 'assembly.sdf').replace('\\', '/') + + mytree = ET.parse(assembly_sdf) + myroot = mytree.getroot() + + models_transforms = {} + for models in myroot.iter('model'): + for models_childs in models: + # if hasattr(models_childs.find('pose'), 'text'): is this better? + if models_childs.find('pose') is not None: + pose = models_childs.find('pose').text + logger.debug(models.attrib['name'], pose) + pose_vectors = [float(x) * 0.001 for x in pose.split()] + models_transforms[models.attrib['name']] = pose_vectors + + # TODO add models <==> objects compare validation + + for obj in bpy.context.scene.objects: + if obj.name in models_transforms: + obj_transforms = models_transforms[obj.name] + obj.location = obj_transforms[:3] + obj.rotation_mode = 'XYZ' + obj.rotation_euler = obj_transforms[3:] # may be TODO + else: + bpy.data.objects.remove(bpy.data.objects[obj.name], do_unlink=True) + logger.info(obj.name, '- is not in assemly objects. Deleted!') + + +def asp_asset_pipeline(fcstd_path, export_path, assembly_path, tessellation=20): + """ Setup FreeCAD scene to CG asset """ + remove_collections() + cleanup_orphan_data() + importer(fcstd_path, tessellation) + sdf_to_subassembly(assembly_path) + asset_setup() + bpy.ops.wm.save_as_mainfile(filepath=blend_path) + export_stl(export_path) + + +if __name__ == '__main__': + fcstd_path = '/media/disk/robossembler/project/pipeline/asp/1.FCStd' + blend_path = '/media/disk/robossembler/project/pipeline/asp/1.blend' + assembly_path = '/media/disk/robossembler/project/pipeline/asp/asp-generation' + assembly_meshes_path = os.path.join(assembly_path, 'meshes').replace('\\', '/') + export_path = assembly_meshes_path + + asp_asset_pipeline(fcstd_path, export_path, assembly_path, tessellation=20) + logger.info("Assets setup finished without errors") diff --git a/cg/pipeline/freecad_to_asset.py b/cg/pipeline/freecad_to_asset.py index 436dc03..4d9939a 100644 --- a/cg/pipeline/freecad_to_asset.py +++ b/cg/pipeline/freecad_to_asset.py @@ -14,7 +14,7 @@ from utils.remove_collections import remove_collections from utils.cleanup_orphan_data import cleanup_orphan_data from remesh import asset_setup from export.dae import export_dae -from export.stl import export_stl +from export.collision import export_col_stl sys.path.append('/home/bm/bin/blender-git/blender_bin') # import blender module import bpy @@ -31,7 +31,7 @@ def freecad_asset_pipeline(fcstd_path, export_path, tessellation=20): asset_setup() bpy.ops.wm.save_as_mainfile(filepath="/home/bm/test.blend") export_dae(export_path) - export_stl(export_path) + export_col_stl(export_path) if __name__ == '__main__':