diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e32151..aa88dbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,11 @@ Activate / deactivate layer opaticty according to prefix Activate / deactivate all masks using MA layers --> +0.5.7 + +- added: timeout on scene plit and autocrop border to avoid freezing blender +- ui: minor correction + 0.5.6 - feat: `check layers` new `clear frame out of range` option (Disabled by default) diff --git a/OP_add_layer.py b/OP_add_layer.py index 315668f..4f89892 100644 --- a/OP_add_layer.py +++ b/OP_add_layer.py @@ -93,7 +93,7 @@ class GPEXP_OT_add_objects_to_render(bpy.types.Operator): class GPEXP_OT_split_to_scene(bpy.types.Operator): bl_idname = "gp.split_to_scene" bl_label = "Split Objects To Scene" - bl_description = "Take selected objects and send them to separate scene" + bl_description = "Take selected objects and send them to separate scene\n(new scene is named after active object)" bl_options = {"REGISTER"} @classmethod @@ -103,7 +103,10 @@ class GPEXP_OT_split_to_scene(bpy.types.Operator): mode : bpy.props.StringProperty(default='ALL', options={'SKIP_SAVE'}) def execute(self, context): - fn.split_object_to_scene() + err = fn.split_object_to_scene() + if err: + self.report({'ERROR'}, err) + return {"CANCELLED"} return {"FINISHED"} diff --git a/OP_crop_to_object.py b/OP_crop_to_object.py index 598139f..6ca5ece 100644 --- a/OP_crop_to_object.py +++ b/OP_crop_to_object.py @@ -13,7 +13,11 @@ class GPEXP_OT_set_crop_from_selection(bpy.types.Operator): def execute(self, context): scn = context.scene - fn.set_box_from_selected_objects(scn=scn, cam=scn.camera) + err = fn.set_box_from_selected_objects(scn=scn, cam=scn.camera) + if err: + self.report({'ERROR'}, err) + return {"CANCELLED"} + scn.render.use_border = True scn.render.use_crop_to_border = True return {"FINISHED"} diff --git a/__init__.py b/__init__.py index c1c9bc0..f5dabb6 100644 --- a/__init__.py +++ b/__init__.py @@ -2,7 +2,7 @@ bl_info = { "name": "GP Render", "description": "Organise export of gp layers through compositor output", "author": "Samuel Bernou", - "version": (0, 5, 6), + "version": (0, 5, 7), "blender": (2, 93, 0), "location": "View3D", "warning": "", diff --git a/fn.py b/fn.py index e599000..249b817 100644 --- a/fn.py +++ b/fn.py @@ -803,7 +803,10 @@ def export_crop_to_json(): return coord_dic def set_border_region_from_coord(coords, scn=None, margin=30, export_json=True): - '''Get a list of point coord in worldcamera view space (0 to 1) on each axis''' + '''Get a list of point coord in worldcamera view space (0 to 1) on each axis + set border (of passed scene :scn: ) with given coordinate + return the coords list as pixel coordinate + ''' scn = scn or bpy.context.scene @@ -883,14 +886,16 @@ def has_anim(ob): # TODO make a better check (check if there is only one key in each channel, count as not animated) return ob.animation_data and ob.animation_data.action -def get_gp_box_all_frame_selection(oblist=None, scn=None, cam=None): +def get_gp_box_all_frame_selection(oblist=None, scn=None, cam=None, timeout=40): ''' get points of all selection return 2d bbox in pixels + return None if timeout (too long to process, better to do it visually) ''' from bpy_extras.object_utils import world_to_camera_view + t0 = time() coords_cam_list = [] scn = scn or bpy.context.scene oblist = oblist or [o for o in scn.objects if o.select_get()] @@ -912,6 +917,10 @@ def get_gp_box_all_frame_selection(oblist=None, scn=None, cam=None): if len(s.points) == 1: # skip isolated points continue coords_cam_list += [world_to_camera_view(scn, cam, ob.matrix_world @ p.co) for p in s.points] + + if time() - t0 > timeout: + print(f'timeout (more than {timeout}s to calculate) evaluating frame position of objects {oblist}') + return else: print(f'No anim') for ob in oblist: @@ -920,12 +929,16 @@ def get_gp_box_all_frame_selection(oblist=None, scn=None, cam=None): if l.hide or l.opacity == 0.0: continue for f in l.frames: + if time() - t0 > timeout: + print(f'timeout (more than {timeout}s to calculate) evaluating frame position of objects {oblist}') + return if not (scn.frame_start <= f.frame_number <= scn.frame_end): continue for s in f.strokes: if len(s.points) == 1: # skip isolated points continue coords_cam_list += [world_to_camera_view(scn, cam, ob.matrix_world @ p.co) for p in s.points] + print(f'{len(coords_cam_list)} gp points listed {time() - start:.1f}s') return coords_cam_list @@ -954,6 +967,9 @@ def set_box_from_selected_objects(scn=None, cam=None, export_json=False): selection = [o for o in scn.objects if o.select_get()] # selected_objects coords = get_gp_box_all_frame_selection(oblist=selection, scn=scn, cam=cam) + if not coords: + return f'Border not set: Timeout during analysis of {len(selection)} objects' + _bbox_px = set_border_region_from_coord(coords, margin=30, scn=scn, export_json=export_json) @@ -1032,6 +1048,8 @@ def split_object_to_scene(): # border to GP objects of the scene gp_objs = [o for o in new.objects if o.type == 'GPENCIL'] coords = get_gp_box_all_frame_selection(oblist=gp_objs, scn=new, cam=new.camera) + if not coords: + return f'Scene "{scene_name}" created. But Border was not set (Timeout during GP analysis), should be done by hand if needed then use export crop to json' set_border_region_from_coord(coords, margin=30, scn=new, export_json=True) export_crop_to_json() diff --git a/ui.py b/ui.py index 4eb416b..196c497 100644 --- a/ui.py +++ b/ui.py @@ -130,10 +130,10 @@ class GPEXP_PT_gp_node_ui(Panel): layout.separator() layout.label(text='Sub Scenes:') - layout.operator('gp.split_to_scene', icon='DUPLICATE', text='Split To Scene') + layout.operator('gp.split_to_scene', icon='DUPLICATE', text='Split Selected Obj To Scene') row = layout.row(align=True) - row.operator('gp.set_crop_from_selection', icon='CON_OBJECTSOLVER', text='Set Crop') + row.operator('gp.set_crop_from_selection', icon='CON_OBJECTSOLVER', text='Autoset Crop') row.operator('gp.export_crop_coord_to_json', icon='FILE', text='Export json') layout.operator('gp.render_all_scenes', icon='RENDER_ANIMATION', text='Render All Sub-Scene')