From 2f7aebef8548b8f2ae3aa02b0247ae89a51abfe9 Mon Sep 17 00:00:00 2001 From: hgn Date: Wed, 3 Aug 2022 12:07:03 +0100 Subject: [PATCH] init --- blender_graphics_cropper.py | 199 ++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 blender_graphics_cropper.py diff --git a/blender_graphics_cropper.py b/blender_graphics_cropper.py new file mode 100644 index 0000000..ad12dfc --- /dev/null +++ b/blender_graphics_cropper.py @@ -0,0 +1,199 @@ +import bpy, math, gpu, blf +from mathutils import * +from gpu_extras.batch import batch_for_shader + +bl_info = { + "name":"Graphics Cropper", + "author": "Harry Godden (hgn)", + "version": (0,1), + "blender":(3,1,0), + "location":"", + "descriptin":"", + "warning":"", + "wiki_url":"", + "category":"", +} + +# Clicky clicky GUI +# ------------------------------------------------------------------------------ + +cropper_view_draw_handler = None +cropper_ui_draw_handler = None +cropper_view_shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR') + +def cropper_draw_ui(): + mtx = bpy.context.region_data.perspective_matrix + w = bpy.context.region.width + h = bpy.context.region.height + + for obj in bpy.context.scene.objects: + if obj.cropper_data.enabled: + x = obj.cropper_data.resolution[0] + y = obj.cropper_data.resolution[1] + c = Vector((1,1,0,1)) if obj.select_get() else Vector((0.6,0.4,0,1)) + p0 = obj.matrix_world @ Vector((0,0,0)) + p1 = obj.matrix_world @ Vector((x,0,0)) + p2 = obj.matrix_world @ Vector((x,y,0)) + p3 = obj.matrix_world @ Vector((0,y,0)) + + co = mtx @ Vector((p3[0],p3[1],p3[2],1.0)) + + co[0] /= co[3] + co[1] /= co[3] + co[0] *= 0.5 + co[1] *= 0.5 + co[0] += 0.5 + co[1] += 0.5 + co[0] *= w + co[1] *= h + + blf.position(0,co[0],co[1]+8,0) + blf.size(0,20,48) + blf.color(0,c[0],c[1],c[2],c[3]) + blf.draw(0,obj.cropper_data.filename) + +def cropper_draw(): + global cropper_view_shader + + verts = [] + colours = [] + + for obj in bpy.context.scene.objects: + if obj.cropper_data.enabled: + x = obj.cropper_data.resolution[0] + y = obj.cropper_data.resolution[1] + c = Vector((1,1,0,1)) if obj.select_get() else Vector((0.6,0.4,0,1)) + p0 = obj.matrix_world @ Vector((0,0,0)) + p1 = obj.matrix_world @ Vector((x,0,0)) + p2 = obj.matrix_world @ Vector((x,y,0)) + p3 = obj.matrix_world @ Vector((0,y,0)) + + verts += [p0,p1,p1,p2,p2,p3,p3,p0] + colours += [c,c,c,c,c,c,c,c] + + cropper_view_shader.bind() + gpu.state.depth_mask_set(False) + gpu.state.line_width_set(2.0) + gpu.state.face_culling_set('BACK') + gpu.state.depth_test_set('NONE') + gpu.state.blend_set('NONE') + lines = batch_for_shader( cropper_view_shader, 'LINES', \ + { "pos":verts, "color":colours }) + lines.draw( cropper_view_shader ) + +# Blender +# ------------------------------------------------------------------------------ + +def cropper_render_item(obj,context): + cam = context.scene.camera + original_pos_x = cam.location[0] + original_pos_y = cam.location[1] + original_res_x = context.scene.render.resolution_x + original_res_y = context.scene.render.resolution_y + original_file = context.scene.render.filepath + original_scale = cam.data.ortho_scale + + x = obj.cropper_data.resolution[0] + y = obj.cropper_data.resolution[1] + fmt = context.scene.render.image_settings.file_format.lower() + fn = F"{obj.cropper_data.filename}.{fmt}" + + p0 = obj.matrix_world @ Vector((0,0,0)) + p1 = obj.matrix_world @ Vector((x,0,0)) + p2 = obj.matrix_world @ Vector((x,y,0)) + p3 = obj.matrix_world @ Vector((0,y,0)) + c = obj.matrix_world @ Vector((x*0.5,y*0.5,0)) + + if x > y: s = p2[0]-p0[0] + else: s = p2[1]-p0[1] + + cam.location[0] = c[0] + cam.location[1] = c[1] + + cam.data.ortho_scale = s + context.scene.render.resolution_x = x + context.scene.render.resolution_y = y + context.scene.render.filepath = original_file + fn + print( F"render to: {context.scene.render.filepath}" ) + bpy.ops.render.render(write_still=True) + + # Reset + context.scene.render.resolution_x = original_res_x + context.scene.render.resolution_y = original_res_y + context.scene.render.filepath = original_file + + cam.data.ortho_scale = original_scale + cam.location[0] = original_pos_x + cam.location[1] = original_pos_y + +class CROPPER_RENDER_ALL(bpy.types.Operator): + bl_idname="cropper.render_all" + bl_label="Render all" + def execute(_,context): + for obj in context.scene.objects: + if obj.cropper_data.enabled: + cropper_render_item(obj,context) + + return {'FINISHED'} + +class CROPPER_RENDER(bpy.types.Operator): + bl_idname="cropper.render" + bl_label="Render" + def execute(_,context): + obj = context.active_object + if obj != None and obj.cropper_data.enabled: + cropper_render_item(obj,context) + + return {'FINISHED'} + +class CROPPER_OBJ_SETTINGS(bpy.types.PropertyGroup): + enabled: bpy.props.BoolProperty( name="enabled" ) + filename: bpy.props.StringProperty( name="filename" ) + resolution: bpy.props.IntVectorProperty( name="resolution",size=2 ) + +class CROPPER_OBJ_PANEL(bpy.types.Panel): + bl_label="Cropper Settings" + bl_idname="SCENE_PT_cropper" + bl_space_type='PROPERTIES' + bl_region_type='WINDOW' + bl_context="object" + + def draw(_,context): + active_object = context.active_object + if active_object == None: return + _.layout.prop( active_object.cropper_data, "enabled" ) + + box = _.layout.box() + if not active_object.cropper_data.enabled: + box.enabled = False + + box.prop( active_object.cropper_data, "filename" ) + box.prop( active_object.cropper_data, "resolution" ) + box.operator( "cropper.render" ) + _.layout.operator( "cropper.render_all" ) + +classes = [ CROPPER_OBJ_SETTINGS, CROPPER_OBJ_PANEL, \ + CROPPER_RENDER, CROPPER_RENDER_ALL ] + +def register(): + global cropper_view_draw_handler, cropper_ui_draw_handler + + for c in classes: + bpy.utils.register_class(c) + + bpy.types.Object.cropper_data = \ + bpy.props.PointerProperty(type=CROPPER_OBJ_SETTINGS) + + cropper_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\ + cropper_draw,(),'WINDOW','POST_VIEW') + cropper_ui_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\ + cropper_draw_ui,(),'WINDOW','POST_PIXEL') + +def unregister(): + global cropper_view_draw_handler, cropper_ui_draw_handler + + for c in classes: + bpy.utils.unregister_class(c) + + bpy.types.SpaceView3D.draw_handler_remove(cropper_view_draw_handler,'WINDOW') + bpy.types.SpaceView3D.draw_handler_remove(cropper_ui_draw_handler,'WINDOW') -- 2.25.1