import bpy from mathutils import Vector, Euler from math import pi import json import os import bpy_extras import bmesh import time class ModalTimerOperator(bpy.types.Operator): """Operator which runs its self from a timer""" bl_idname = "wm.modal_timer_operator" bl_label = "Modal Timer Operator" _timer = None index = 0 def menu_func(self, context): self.layout.operator(ModalTimerOperator.bl_idname) def modal(self, context, event): scene = context.scene if self.index >= len(self.sides): self.cancel(context) return {'CANCELLED'} if event.type == 'TIMER': print("HOLY COW!!!") self.capture(self.sides[self.index]) self.index += 1 if self.index < len(self.sides): self.position_camera(self.sides[self.index]) else: self.export_data() return {'PASS_THROUGH'} def execute(self, context): print("execute!") self.c = bpy.data.objects["cam"] self.scene = bpy.context.scene selected = bpy.context.selected_objects[0] bpy.ops.object.mode_set(mode="OBJECT") bpy.ops.object.transform_apply( rotation = True ) self.data = {} self.b = selected FRONT = [0, 1, 2, "Front"] SIDE = [1, 1, 2, "Side"] TOP = [0, 0, 1, "Top"] ANGLED = [0.5, 1, 2, "Angled"] self.sides = [FRONT, SIDE, TOP, ANGLED] path = "/tmp/macrovision/" media_path = "/home/crux/furry/macrovision/media/" media_folder = "buildings/Houses/" os.makedirs(path, exist_ok=True) os.makedirs(os.path.join(media_path, media_folder), exist_ok=True) wm = context.window_manager self._timer = wm.event_timer_add(0.25, window=context.window) wm.modal_handler_add(self) self.position_camera(self.sides[self.index]) return {'RUNNING_MODAL'} def cancel(self, context): wm = context.window_manager wm.event_timer_remove(self._timer) def getView3dAreaAndRegion(self, context): for area in context.screen.areas: if area.type == "VIEW_3D": for region in area.regions: if region.type == "WINDOW": print("Found WINDOW") return area, region def select_border(self, context, view3dAreaAndRegion=None, extend=True): if not view3dAreaAndRegion: view3dAreaAndRegion = self.getView3dAreaAndRegion(context) print(view3dAreaAndRegion) view3dArea, view3dRegion = view3dAreaAndRegion override = context.copy() override['area'] = view3dArea override['region'] = view3dRegion bpy.ops.view3d.select_box(override,xmin=0,xmax=view3dArea.width,ymin=0,ymax=view3dArea.height,mode='SET') def position_camera(self, angles): bpy.ops.object.mode_set(mode="OBJECT") local_bbox_center = 0.125 * sum((Vector(box) for box in self.b.bound_box), Vector()) global_bbox_center = self.b.matrix_world @ local_bbox_center self.c.data.ortho_scale = max(self.b.dimensions) * 1.3 self.c.location = global_bbox_center self.c.rotation_euler = Euler([angles[1] * pi / 2, 0, angles[0] * pi / 2]) rot = self.c.rotation_euler.to_matrix() rot.invert() self.c.location = self.c.location + Vector([0, 0, 100]) @ rot self.data[angles[3]] = self.b.dimensions[angles[2]] def capture(self, angles): bpy.ops.object.mode_set(mode="EDIT") bpy.ops.mesh.select_all(action="SELECT") bpy.ops.mesh.sort_elements(type='VIEW_ZAXIS', elements={'FACE'}, reverse=False) bm = bmesh.from_edit_mesh(bpy.context.active_object.data) polygons = [] edges = [] self.select_border(bpy.context) bm.faces.ensure_lookup_table() bm.verts.ensure_lookup_table() bm.edges.ensure_lookup_table() for face in bm.faces: if not face.select: continue verts = [] for vert in face.verts: co = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, vert.co) verts.append([co[0], co[1]]) verts.append(verts[0]) polygons.append({"verts": verts, "type": "bright" if face.material_index == 1 else "dark"}) for edge in face.edges: if not edge.select: continue co1 = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, edge.verts[0].co) co2 = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, edge.verts[1].co) polygons.append({"type": "edge", "verts": [ [co1[0], co1[1]], [co2[0], co2[1]] ]}) bm.free() bpy.ops.object.mode_set(mode="OBJECT") with open(f"/tmp/polygons-{angles[3]}.json", "w", encoding="utf-8") as file: json.dump({"polygons": polygons}, file) def export_data(self): with open(f"/tmp/data-{self.b.name}.json", "w", encoding="utf-8") as file: json.dump({"name": self.b.name, "views": self.data}, file) def register(): bpy.utils.register_class(ModalTimerOperator) bpy.types.VIEW3D_MT_object.append(ModalTimerOperator.menu_func) def unregister(): bpy.utils.unregister_class(ModalTimerOperator) register()