# -*- coding: utf-8 -*- # Copyright (C) 2023 Ilia Kurochkin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. ''' DESCRIPTION. - Build Blender scene from JSON data. - Setup hierarchy. - Setup materials. - Setup LCS points. - Apply Bledner scene transforms. ''' __version__ = '0.1' import collections import logging import random import bpy from blender.utils.object_transforms import apply_transforms from blender.import_cad.import_hierarchy import (fc_placement, hierarchy) from blender.import_cad.import_materials import (assign_materials, assign_black) logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) # COLLECTIONS NAMIG CONVENTION part_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' scene_scale = 0.001 blackbody_mat_name = 'Robossembler_Black_Body' def json_to_blend(js_data): ''' Reads JSON data and creates Blender scene ''' part_collection = bpy.data.collections.new(part_col_name) bpy.context.scene.collection.children.link(part_collection) lcs_collection = bpy.data.collections.new(lcs_col_name) bpy.context.scene.collection.children.link(lcs_collection) hierarchy_collection = bpy.data.collections.new(hierarchy_col_name) bpy.context.scene.collection.children.link(hierarchy_collection) fc_file = list(js_data.keys())[0] imported_objects = collections.defaultdict(list) for js_obj in js_data[fc_file]: bobj = None if js_data[fc_file][js_obj]['type'] == 'LCS': bobj = bpy.data.objects.new(js_obj, None) bobj.empty_display_type = 'ARROWS' bobj.empty_display_size = round(random.uniform(0.05, 0.15), 3) bobj.show_in_front = True lcs_collection.objects.link(bobj) imported_objects['objs_lcs'].append(bobj.name) elif js_data[fc_file][js_obj]['type'] == 'PART': if js_data[fc_file][js_obj].get('mesh'): verts = js_data[fc_file][js_obj]['mesh'][0] edges = [] faces = js_data[fc_file][js_obj]['mesh'][1] # create blender object data bmesh = bpy.data.meshes.new(name=js_obj) bmesh.from_pydata(verts, edges, faces) bmesh.update() bobj = bpy.data.objects.new(js_obj, bmesh) part_collection.objects.link(bobj) if bobj: fc_placement(bobj, js_data[fc_file][js_obj]['fc_location'], js_data[fc_file][js_obj]['fc_rotation'], scene_scale) if bobj.type == 'MESH': bobj.scale = (scene_scale, scene_scale, scene_scale) apply_transforms(bobj, scale=True) # construct assembly hierarchy hierarchy_objs = hierarchy(bobj, js_data[fc_file][js_obj]['hierarchy'], scene_scale) for hierarchy_obj in hierarchy_objs: hierarchy_collection.objects.link(hierarchy_obj) imported_objects['objs_hierarchy'].append(hierarchy_obj.name) # one material for the whole object if bobj.type == 'MESH': if js_data[fc_file][js_obj].get('material'): fem_mat = js_data[fc_file][js_obj]['material'] assign_materials(bobj, fem_mat) imported_objects['objs_foreground'].append(bobj.name) else: assign_black(bobj) imported_objects['objs_background'].append(bobj.name) # losted root lcs inlet workaround if imported_objects['objs_lcs']: root_lcs = None for obj_name in imported_objects['objs_lcs']: if obj_name.endswith(root): root_lcs = bpy.data.objects[obj_name] break if root_lcs: root_inlet_name = '{}{}'.format(root_lcs.name.split(root)[0], inlet) if not bpy.data.objects.get(root_inlet_name): root_inlet = bpy.data.objects.new(root_inlet_name, None) root_inlet.empty_display_type = 'ARROWS' root_inlet.empty_display_size = 0.1 root_inlet.show_in_front = True root_inlet.location = root_lcs.location root_inlet.rotation_euler = root_lcs.rotation_euler root_inlet.parent = root_lcs.parent lcs_collection.objects.link(root_inlet) imported_objects['objs_lcs'].append(root_inlet.name) logger.info('Root Inlet LCS object created!') else: logger.info('Root Inlet LCS object already exists!') else: logger.info('Lost Root LCS object!') else: logger.info('No LCS objects found!') # TODO # update do not dork logger.info('Generated %s objects without errors', len(sum(list(imported_objects.values()), []))) return imported_objects