# -*- coding: utf-8 -*- #!/usr/bin/env python ''' DESCRIPTION. Convert and setup FreeCAD solid objects to 3d assets. Support Blender compiled as a Python Module only! ''' __version__ = '0.6' import json import logging import os from blender.utils.remove_collections import remove_collections from blender.utils.cleanup_orphan_data import cleanup_orphan_data from utils.cmd_proc import cmd_proc from blender.import_cad.build_blender_scene import json_to_blend from blender.processing.restruct_hierarchy_by_lcs import restruct_hierarchy from blender.processing.highpoly_setup import setup_meshes from blender.processing.lowpoly_setup import parts_to_shells from blender.processing.uv_setup import uv_unwrap import bpy import mathutils # from export.dae import export_dae # from export.collision import export_col_stl logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) ''' IMPORT COLLECTIONS NAMIG CONVENTION: Parts - collection for mesh objects LCS - collection for location points Hierarchy - collection for hierarchy locators LCS POINT'S SUFFIXES CONVENTION: '_in' - inlet suffix '_out' - outlet suffix '_root' - root suffix CG ASSETS SUFFIXES CONVENTION: '_hp' - hightpoly asset (reference baking source) '_lp' - lowpoly asset (prepared for game engines) '_render' - root suffix (prepared for render engines) ''' # ENV freecadcmd = 'freecadcmd' fcstd_data_script = 'freecad_to_json.py' # COLLECTIONS NAMIG CONVENTION parts_col_name = 'Parts' lcs_col_name = 'LCS' hierarchy_col_name = 'Hierarchy' lowpoly_col_name = 'Lowpoly' # LCS POINT'S SUFFIXES CONVENTION inlet = '_in' outlet = '_out' root = '_root' # CG ASSETS SUFFIXES CONVENTION hightpoly = '_hp' lowpoly = '_lp' render = '_render' def cg_pipeline(**kwargs): ''' CG asset creation pipeline ''' # prepare blend file remove_collections() cleanup_orphan_data() # convert FreeCAD scene to Blender scene objs_for_render = json_to_blend( json.loads( cmd_proc(freecadcmd, fcstd_data_script, '--', **kwargs ).split('FreeCAD ')[0] ) ) # restructuring hierarchy by lcs points lcs_objects = restruct_hierarchy() # save blender scene if kwargs['blend_path'] is not None: if not os.path.isdir(os.path.dirname(kwargs['blend_path'])): os.makedirs(os.path.dirname(kwargs['blend_path'])) bpy.ops.wm.save_as_mainfile(filepath=kwargs['blend_path']) # prepare highpoly setup_meshes(objs_for_render, sharpness=True, shading=True) # prepare lowpoly part_names = [p.name.split(inlet)[0] for p in lcs_objects if p.name.endswith(inlet)] lowpoly_objs = parts_to_shells(part_names) uv_unwrap(lowpoly_objs) # save blender scene if kwargs['blend_path'] is not None: if not os.path.isdir(os.path.dirname(kwargs['blend_path'])): os.makedirs(os.path.dirname(kwargs['blend_path'])) bpy.ops.wm.save_as_mainfile(filepath=kwargs['blend_path']) # export all objects if kwargs['mesh_export_path'] is not None: obs = bpy.context.selected_objects for ob in obs: ob.matrix_world = mathutils.Matrix() for ob in obs: ob.select_set(state=True) export_dae(kwargs['mesh_export_path']) export_col_stl(kwargs['mesh_export_path']) if __name__ == '__main__': import argparse parser = argparse.ArgumentParser( description='Convert and setup FreeCAD solid objects to 3d assets mesh files.' ) parser.add_argument( '--fcstd_path', type=str, help='Path to source FreeCAD scene', required=True ) parser.add_argument( '--tesselation_method', type=str, help='Select tesselation method: Standard or FEM.', default='Standard', required=False ) parser.add_argument( '--linear_deflection', type=float, help='Max linear distance error', default=0.1, required=False ) parser.add_argument( '--angular_deflection', type=float, help='Max angular distance error', default=20.0, required=False ) parser.add_argument( '--fem_size', type=float, help='For FEM method only! Finite element size in mm', default=50.0, required=False ) parser.add_argument( '--skiphidden', type=bool, help='Skip processing for hidden FreeCAD objects', default=True, required=False ) parser.add_argument( '--property_forse_nonsolid', type=str, help='FreeCAD property to enable processing for nonsolid objects', default='Robossembler_NonSolid', required=False ) parser.add_argument( '--mesh_export_path', type=str, help='Path for export meshes', required=False ) parser.add_argument( '--blend_path', type=str, help='Path for export blend assembly file', required=False ) args = parser.parse_args() kwargs = {key: getattr(args, key) for key in dir(args) if not key.startswith('_')} cg_pipeline(**kwargs) logger.info('CG Pipeline Completed!')