visibility fix
[blender_graphics_cropper.git] / blender_graphics_cropper.py
1 import bpy, math, gpu, blf
2 from mathutils import *
3 from gpu_extras.batch import batch_for_shader
4
5 bl_info = {
6 "name":"Graphics Cropper",
7 "author": "Harry Godden (hgn)",
8 "version": (0,1),
9 "blender":(3,1,0),
10 "location":"",
11 "descriptin":"",
12 "warning":"",
13 "wiki_url":"",
14 "category":"",
15 }
16
17 # Clicky clicky GUI
18 # ------------------------------------------------------------------------------
19
20 cropper_view_draw_handler = None
21 cropper_ui_draw_handler = None
22 cropper_view_shader = gpu.shader.from_builtin('3D_SMOOTH_COLOR')
23
24 def cropper_draw_ui():
25 mtx = bpy.context.region_data.perspective_matrix
26 w = bpy.context.region.width
27 h = bpy.context.region.height
28
29 for obj in bpy.context.scene.objects:
30 if obj.cropper_data.enabled and obj.visible_get():
31 x = obj.cropper_data.resolution[0]
32 y = obj.cropper_data.resolution[1]
33 c = Vector((1,1,0,1)) if obj.select_get() else Vector((0.6,0.4,0,1))
34 p0 = obj.matrix_world @ Vector((0,0,0))
35 p1 = obj.matrix_world @ Vector((x,0,0))
36 p2 = obj.matrix_world @ Vector((x,y,0))
37 p3 = obj.matrix_world @ Vector((0,y,0))
38
39 co = mtx @ Vector((p3[0],p3[1],p3[2],1.0))
40
41 co[0] /= co[3]
42 co[1] /= co[3]
43 co[0] *= 0.5
44 co[1] *= 0.5
45 co[0] += 0.5
46 co[1] += 0.5
47 co[0] *= w
48 co[1] *= h
49
50 blf.position(0,co[0],co[1]+8,0)
51 blf.size(0,20,48)
52 blf.color(0,c[0],c[1],c[2],c[3])
53 blf.draw(0,obj.cropper_data.filename)
54
55 def cropper_draw():
56 global cropper_view_shader
57
58 verts = []
59 colours = []
60
61 for obj in bpy.context.scene.objects:
62 if obj.cropper_data.enabled and obj.visible_get():
63 x = obj.cropper_data.resolution[0]
64 y = obj.cropper_data.resolution[1]
65 c = Vector((1,1,0,1)) if obj.select_get() else Vector((0.6,0.4,0,1))
66 p0 = obj.matrix_world @ Vector((0,0,0))
67 p1 = obj.matrix_world @ Vector((x,0,0))
68 p2 = obj.matrix_world @ Vector((x,y,0))
69 p3 = obj.matrix_world @ Vector((0,y,0))
70
71 verts += [p0,p1,p1,p2,p2,p3,p3,p0]
72 colours += [c,c,c,c,c,c,c,c]
73
74 cropper_view_shader.bind()
75 gpu.state.depth_mask_set(False)
76 gpu.state.line_width_set(2.0)
77 gpu.state.face_culling_set('BACK')
78 gpu.state.depth_test_set('NONE')
79 gpu.state.blend_set('NONE')
80 lines = batch_for_shader( cropper_view_shader, 'LINES', \
81 { "pos":verts, "color":colours })
82 lines.draw( cropper_view_shader )
83
84 # Blender
85 # ------------------------------------------------------------------------------
86
87 def cropper_render_item(obj,context):
88 cam = context.scene.camera
89 original_pos_x = cam.location[0]
90 original_pos_y = cam.location[1]
91 original_res_x = context.scene.render.resolution_x
92 original_res_y = context.scene.render.resolution_y
93 original_file = context.scene.render.filepath
94 original_scale = cam.data.ortho_scale
95
96 x = obj.cropper_data.resolution[0]
97 y = obj.cropper_data.resolution[1]
98 fmt = context.scene.render.image_settings.file_format.lower()
99 fn = F"{obj.cropper_data.filename}.{fmt}"
100
101 p0 = obj.matrix_world @ Vector((0,0,0))
102 p1 = obj.matrix_world @ Vector((x,0,0))
103 p2 = obj.matrix_world @ Vector((x,y,0))
104 p3 = obj.matrix_world @ Vector((0,y,0))
105 c = obj.matrix_world @ Vector((x*0.5,y*0.5,0))
106
107 if x > y: s = p2[0]-p0[0]
108 else: s = p2[1]-p0[1]
109
110 cam.location[0] = c[0]
111 cam.location[1] = c[1]
112
113 cam.data.ortho_scale = s
114 context.scene.render.resolution_x = x
115 context.scene.render.resolution_y = y
116 context.scene.render.filepath = original_file + fn
117 print( F"render to: {context.scene.render.filepath}" )
118 bpy.ops.render.render(write_still=True)
119
120 # Reset
121 context.scene.render.resolution_x = original_res_x
122 context.scene.render.resolution_y = original_res_y
123 context.scene.render.filepath = original_file
124
125 cam.data.ortho_scale = original_scale
126 cam.location[0] = original_pos_x
127 cam.location[1] = original_pos_y
128
129 class CROPPER_RENDER_ALL(bpy.types.Operator):
130 bl_idname="cropper.render_all"
131 bl_label="Render all"
132 def execute(_,context):
133 for obj in context.scene.objects:
134 if obj.cropper_data.enabled and obj.visible_get():
135 cropper_render_item(obj,context)
136
137 return {'FINISHED'}
138
139 class CROPPER_RENDER(bpy.types.Operator):
140 bl_idname="cropper.render"
141 bl_label="Render"
142 def execute(_,context):
143 obj = context.active_object
144 if obj != None and obj.cropper_data.enabled:
145 cropper_render_item(obj,context)
146
147 return {'FINISHED'}
148
149 class CROPPER_OBJ_SETTINGS(bpy.types.PropertyGroup):
150 enabled: bpy.props.BoolProperty( name="enabled" )
151 filename: bpy.props.StringProperty( name="filename" )
152 resolution: bpy.props.IntVectorProperty( name="resolution",size=2 )
153
154 class CROPPER_OBJ_PANEL(bpy.types.Panel):
155 bl_label="Cropper Settings"
156 bl_idname="SCENE_PT_cropper"
157 bl_space_type='PROPERTIES'
158 bl_region_type='WINDOW'
159 bl_context="object"
160
161 def draw(_,context):
162 active_object = context.active_object
163 if active_object == None: return
164 _.layout.prop( active_object.cropper_data, "enabled" )
165
166 box = _.layout.box()
167 if not active_object.cropper_data.enabled:
168 box.enabled = False
169
170 box.prop( active_object.cropper_data, "filename" )
171 box.prop( active_object.cropper_data, "resolution" )
172 box.operator( "cropper.render" )
173 _.layout.operator( "cropper.render_all" )
174
175 classes = [ CROPPER_OBJ_SETTINGS, CROPPER_OBJ_PANEL, \
176 CROPPER_RENDER, CROPPER_RENDER_ALL ]
177
178 def register():
179 global cropper_view_draw_handler, cropper_ui_draw_handler
180
181 for c in classes:
182 bpy.utils.register_class(c)
183
184 bpy.types.Object.cropper_data = \
185 bpy.props.PointerProperty(type=CROPPER_OBJ_SETTINGS)
186
187 cropper_view_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\
188 cropper_draw,(),'WINDOW','POST_VIEW')
189 cropper_ui_draw_handler = bpy.types.SpaceView3D.draw_handler_add(\
190 cropper_draw_ui,(),'WINDOW','POST_PIXEL')
191
192 def unregister():
193 global cropper_view_draw_handler, cropper_ui_draw_handler
194
195 for c in classes:
196 bpy.utils.unregister_class(c)
197
198 bpy.types.SpaceView3D.draw_handler_remove(cropper_view_draw_handler,'WINDOW')
199 bpy.types.SpaceView3D.draw_handler_remove(cropper_ui_draw_handler,'WINDOW')