less copy protection, more size visualization
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

157 行
5.4 KiB

  1. import bpy
  2. from mathutils import Vector, Euler
  3. from math import pi
  4. import json
  5. import os
  6. import bpy_extras
  7. import bmesh
  8. import time
  9. class ModalTimerOperator(bpy.types.Operator):
  10. """Operator which runs its self from a timer"""
  11. bl_idname = "wm.modal_timer_operator"
  12. bl_label = "Modal Timer Operator"
  13. _timer = None
  14. index = 0
  15. def menu_func(self, context):
  16. self.layout.operator(ModalTimerOperator.bl_idname)
  17. def modal(self, context, event):
  18. scene = context.scene
  19. if self.index >= len(self.sides):
  20. self.cancel(context)
  21. return {'CANCELLED'}
  22. if event.type == 'TIMER':
  23. print("HOLY COW!!!")
  24. self.capture(self.sides[self.index])
  25. self.index += 1
  26. if self.index < len(self.sides):
  27. self.position_camera(self.sides[self.index])
  28. else:
  29. self.export_data()
  30. return {'PASS_THROUGH'}
  31. def execute(self, context):
  32. print("execute!")
  33. self.c = bpy.data.objects["cam"]
  34. self.scene = bpy.context.scene
  35. selected = bpy.context.selected_objects[0]
  36. bpy.ops.object.mode_set(mode="OBJECT")
  37. bpy.ops.object.transform_apply( rotation = True )
  38. self.data = {}
  39. self.b = selected
  40. FRONT = [0, 1, 2, "Front"]
  41. SIDE = [1, 1, 2, "Side"]
  42. TOP = [0, 0, 1, "Top"]
  43. ANGLED = [0.5, 1, 2, "Angled"]
  44. self.sides = [FRONT, SIDE, TOP, ANGLED]
  45. path = "/tmp/macrovision/"
  46. media_path = "/home/crux/furry/macrovision/media/"
  47. media_folder = "buildings/Houses/"
  48. os.makedirs(path, exist_ok=True)
  49. os.makedirs(os.path.join(media_path, media_folder), exist_ok=True)
  50. wm = context.window_manager
  51. self._timer = wm.event_timer_add(0.25, window=context.window)
  52. wm.modal_handler_add(self)
  53. self.position_camera(self.sides[self.index])
  54. return {'RUNNING_MODAL'}
  55. def cancel(self, context):
  56. wm = context.window_manager
  57. wm.event_timer_remove(self._timer)
  58. def getView3dAreaAndRegion(self, context):
  59. for area in context.screen.areas:
  60. if area.type == "VIEW_3D":
  61. for region in area.regions:
  62. if region.type == "WINDOW":
  63. print("Found WINDOW")
  64. return area, region
  65. def select_border(self, context, view3dAreaAndRegion=None, extend=True):
  66. if not view3dAreaAndRegion:
  67. view3dAreaAndRegion = self.getView3dAreaAndRegion(context)
  68. print(view3dAreaAndRegion)
  69. view3dArea, view3dRegion = view3dAreaAndRegion
  70. override = context.copy()
  71. override['area'] = view3dArea
  72. override['region'] = view3dRegion
  73. bpy.ops.view3d.select_box(override,xmin=0,xmax=view3dArea.width,ymin=0,ymax=view3dArea.height,mode='SET')
  74. def position_camera(self, angles):
  75. bpy.ops.object.mode_set(mode="OBJECT")
  76. local_bbox_center = 0.125 * sum((Vector(box) for box in self.b.bound_box), Vector())
  77. global_bbox_center = self.b.matrix_world @ local_bbox_center
  78. self.c.data.ortho_scale = max(self.b.dimensions) * 1.3
  79. self.c.location = global_bbox_center
  80. self.c.rotation_euler = Euler([angles[1] * pi / 2, 0, angles[0] * pi / 2])
  81. rot = self.c.rotation_euler.to_matrix()
  82. rot.invert()
  83. self.c.location = self.c.location + Vector([0, 0, 100]) @ rot
  84. self.data[angles[3]] = self.b.dimensions[angles[2]]
  85. def capture(self, angles):
  86. bpy.ops.object.mode_set(mode="EDIT")
  87. bpy.ops.mesh.select_all(action="SELECT")
  88. bpy.ops.mesh.sort_elements(type='VIEW_ZAXIS', elements={'FACE'}, reverse=False)
  89. bm = bmesh.from_edit_mesh(bpy.context.active_object.data)
  90. polygons = []
  91. edges = []
  92. self.select_border(bpy.context)
  93. bm.faces.ensure_lookup_table()
  94. bm.verts.ensure_lookup_table()
  95. bm.edges.ensure_lookup_table()
  96. for face in bm.faces:
  97. if not face.select:
  98. continue
  99. verts = []
  100. for vert in face.verts:
  101. co = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, vert.co)
  102. verts.append([co[0], co[1]])
  103. verts.append(verts[0])
  104. polygons.append({"verts": verts, "type": "bright" if face.material_index == 1 else "dark"})
  105. for edge in face.edges:
  106. if not edge.select:
  107. continue
  108. co1 = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, edge.verts[0].co)
  109. co2 = bpy_extras.object_utils.world_to_camera_view(self.scene, self.c, edge.verts[1].co)
  110. polygons.append({"type": "edge", "verts": [
  111. [co1[0], co1[1]],
  112. [co2[0], co2[1]]
  113. ]})
  114. bm.free()
  115. bpy.ops.object.mode_set(mode="OBJECT")
  116. with open(f"/tmp/polygons-{angles[3]}.json", "w", encoding="utf-8") as file:
  117. json.dump({"polygons": polygons}, file)
  118. def export_data(self):
  119. with open(f"/tmp/data-{self.b.name}.json", "w", encoding="utf-8") as file:
  120. json.dump({"name": self.b.name, "views": self.data}, file)
  121. def register():
  122. bpy.utils.register_class(ModalTimerOperator)
  123. bpy.types.VIEW3D_MT_object.append(ModalTimerOperator.menu_func)
  124. def unregister():
  125. bpy.utils.unregister_class(ModalTimerOperator)
  126. register()