def save_md3(settings): from mathutils import Euler, Matrix, Vector from math import radians starttime = time.clock() # start timer fullpath = splitext(settings.savepath)[0] modelname = basename(fullpath) logname = modelname + ".log" logfpath = fullpath + ".log" if settings.name == "": settings.name = modelname dumpall = settings.dumpall if settings.logtype == "append": log = open(logfpath,"a") elif settings.logtype == "overwrite": log = open(logfpath,"w") elif settings.logtype == "blender": log = bpy.data.texts.new(logname) log.clear() else: log = None ref_frame = settings.refframe if settings.refframe == -1: ref_frame = bpy.context.scene.frame_current message(log, "###################### BEGIN ######################") model = BlenderModelManager(settings.gzdoom, ref_frame) # Set up fix transformation matrix model.fix_transform *= Matrix.Scale(settings.scale, 4) model.fix_transform *= Matrix.Translation(Vector(( settings.offsetx, settings.offsety, settings.offsetz))) rotation_fix = Euler() rotation_fix.z = radians(90) model.fix_transform *= rotation_fix.to_matrix().to_4x4() model.md3.name = settings.name # Add objects to model manager if len(bpy.context.selected_objects) == 0: message(log, "Select an object to export!") else: # If multiple objects are selected, they are joined together for bobject in bpy.context.selected_objects: if bobject.type == 'MESH': model.add_mesh(bobject) elif bobject.type == 'EMPTY': model.add_tag(bobject) model.setup_frames() model.md3.GetSize() print_md3(log, model.md3, dumpall) model.save(settings.savepath) endtime = time.clock() - starttime message(log, "Export took {:.3f} seconds".format(endtime))
def PerturbInsideCameraView(minCenterDistance, maxCenterDistance, camera, obj): relative_vector = Vector() relative_euler_orientation = Euler() relative_euler_orientation.x = random.uniform(-math.pi, math.pi) relative_euler_orientation.y = random.uniform(-math.pi, math.pi) relative_euler_orientation.z = random.uniform(-math.pi, math.pi) #Find a position that is fully inside the camera's frustum obj.rotation_mode = 'XYZ' for i in range(0, 10000): distance = random.uniform(minCenterDistance, maxCenterDistance) relative_vector = GetRandomUnitVector()*distance if not approx_object_in_camera_view(camera, camera.location + relative_vector, .15, distance, minCenterDistance, maxCenterDistance): continue bpy.context.scene.update() #print("Updating scene " + str((time.time() - start )*1000.0) + " milliseconds") #Temporarily disabling translation for debugging obj.location = camera.location + relative_vector obj.rotation_euler = relative_euler_orientation #Update world matrix of object to match bpy.context.scene.update() #if not object_center_in_camera_view(camera, obj): # continue break #start = time.time() #if mesh_object_vertices_in_camera_view(camera, obj): # print("Fine grain check " + str((time.time() - start )*1000.0) + " milliseconds") # break # print("Fine grain check " + str((time.time() - start )*1000.0) + " milliseconds") return relative_vector, relative_euler_orientation
def draw_callback_px(self, context): font_id = 0 region = context.region UIColor = (0.992, 0.5518, 0.0, 1.0) # Cut Type RECTANGLE = 0 LINE = 1 CIRCLE = 2 self.carver_prefs = context.preferences.addons[__package__].preferences # Color color1 = (1.0, 1.0, 1.0, 1.0) color2 = UIColor #The mouse is outside the active region if not self.in_view_3d: color1 = color2 = (1.0, 0.2, 0.1, 1.0) # Primitives type PrimitiveType = "Rectangle" if self.CutType == CIRCLE: PrimitiveType = "Circle" if self.CutType == LINE: PrimitiveType = "Line" # Width screen overlap = context.preferences.system.use_region_overlap t_panel_width = 0 if overlap: for region in context.area.regions: if region.type == 'TOOLS': t_panel_width = region.width # Initial position region_width = int(region.width / 2.0) y_txt = 10 # Draw the center command from bottom to top # Get the size of the text text_size = 18 if region.width >= 850 else 12 blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale, 0)), 72) # Help Display if (self.ObjectMode is False) and (self.ProfileMode is False): # Depth Cursor TypeStr = "Cursor Depth [" + self.carver_prefs.Key_Depth + "]" BoolStr = "(ON)" if self.snapCursor else "(OFF)" help_txt = [[TypeStr, BoolStr]] # Close poygonal shape if self.CreateMode and self.CutType == LINE: TypeStr = "Close [" + self.carver_prefs.Key_Close + "]" BoolStr = "(ON)" if self.Closed else "(OFF)" help_txt += [[TypeStr, BoolStr]] if self.CreateMode is False: # Apply Booleans TypeStr = "Apply Operations [" + self.carver_prefs.Key_Apply + "]" BoolStr = "(OFF)" if self.dont_apply_boolean else "(ON)" help_txt += [[TypeStr, BoolStr]] #Auto update for bevel TypeStr = "Bevel Update [" + self.carver_prefs.Key_Update + "]" BoolStr = "(ON)" if self.Auto_BevelUpdate else "(OFF)" help_txt += [[TypeStr, BoolStr]] # Circle subdivisions if self.CutType == CIRCLE: TypeStr = "Subdivisions [" + self.carver_prefs.Key_Subrem + "][" + self.carver_prefs.Key_Subadd + "]" BoolStr = str((int(360 / self.stepAngle[self.step]))) help_txt += [[TypeStr, BoolStr]] if self.CreateMode: help_txt += [["Type [Space]", PrimitiveType]] else: help_txt += [["Cut Type [Space]", PrimitiveType]] else: # Instantiate TypeStr = "Instantiate [" + self.carver_prefs.Key_Instant + "]" BoolStr = "(ON)" if self.Instantiate else "(OFF)" help_txt = [[TypeStr, BoolStr]] # Random rotation if self.alt: TypeStr = "Random Rotation [" + self.carver_prefs.Key_Randrot + "]" BoolStr = "(ON)" if self.RandomRotation else "(OFF)" help_txt += [[TypeStr, BoolStr]] # Thickness if self.BrushSolidify: TypeStr = "Thickness [" + self.carver_prefs.Key_Depth + "]" if self.ProfileMode: BoolStr = str( round(self.ProfileBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) if self.ObjectMode: BoolStr = str( round(self.ObjectBrush.modifiers["CT_SOLIDIFY"].thickness, 2)) help_txt += [[TypeStr, BoolStr]] # Brush depth if (self.ObjectMode): TypeStr = "Carve Depth [" + self.carver_prefs.Key_Depth + "]" BoolStr = str(round(self.ObjectBrush.data.vertices[0].co.z, 2)) help_txt += [[TypeStr, BoolStr]] TypeStr = "Brush Depth [" + self.carver_prefs.Key_BrushDepth + "]" BoolStr = str(round(self.BrushDepthOffset, 2)) help_txt += [[TypeStr, BoolStr]] help_txt, bloc_height, max_option, max_key, comma = get_text_info( self, context, help_txt) xCmd = region_width - (max_option + max_key + comma) / 2 draw_string(self, color1, color2, xCmd, y_txt, help_txt, max_option, divide=2) # Separator (Line) LineWidth = (max_option + max_key + comma) / 2 if region.width >= 850: LineWidth = 140 LineWidth = (max_option + max_key + comma) coords = [(int(region_width - LineWidth/2), y_txt + bloc_height + 8), \ (int(region_width + LineWidth/2), y_txt + bloc_height + 8)] draw_shader(self, UIColor, 1, 'LINES', coords, self.carver_prefs.LineWidth) # Command Display if self.CreateMode and ((self.ObjectMode is False) and (self.ProfileMode is False)): BooleanMode = "Create" else: if self.ObjectMode or self.ProfileMode: BooleanType = "Difference) [T]" if self.BoolOps == self.difference else "Union) [T]" BooleanMode = \ "Object Brush (" + BooleanType if self.ObjectMode else "Profil Brush (" + BooleanType else: BooleanMode = \ "Difference" if (self.shift is False) and (self.ForceRebool is False) else "Rebool" # Display boolean mode text_size = 40 if region.width >= 850 else 20 blf.size(0, int(round(text_size * bpy.context.preferences.view.ui_scale, 0)), 72) draw_string(self, color2, color2, region_width - (blf.dimensions(0, BooleanMode)[0]) / 2, \ y_txt + bloc_height + 16, BooleanMode, 0, divide = 2) if region.width >= 850: if self.AskHelp is False: # "H for Help" text blf.size(0, int(round(13 * bpy.context.preferences.view.ui_scale, 0)), 72) help_txt = "[" + self.carver_prefs.Key_Help + "] for help" txt_width = blf.dimensions(0, help_txt)[0] txt_height = (blf.dimensions(0, "gM")[1] * 1.45) # Draw a rectangle and put the text "H for Help" xrect = 40 yrect = 40 rect_vertices = [(xrect - 5, yrect - 5), (xrect + txt_width + 5, yrect - 5), \ (xrect + txt_width + 5, yrect + txt_height + 5), (xrect - 5, yrect + txt_height + 5)] draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', rect_vertices, self.carver_prefs.LineWidth) draw_string(self, color1, color2, xrect, yrect, help_txt, 0) else: #Draw the help text xHelp = 30 + t_panel_width yHelp = 10 if self.ObjectMode or self.ProfileMode: if self.ProfileMode: help_txt = [["Object Mode", self.carver_prefs.Key_Brush]] else: help_txt = [["Cut Mode", self.carver_prefs.Key_Brush]] else: help_txt =[ ["Profil Brush", self.carver_prefs.Key_Brush],\ ["Move Cursor", "Ctrl + LMB"] ] if (self.ObjectMode is False) and (self.ProfileMode is False): if self.CreateMode is False: help_txt +=[ ["Create geometry", self.carver_prefs.Key_Create],\ ] else: help_txt +=[ ["Cut", self.carver_prefs.Key_Create],\ ] if self.CutMode == RECTANGLE: help_txt +=[ ["Dimension", "MouseMove"],\ ["Move all", "Alt"],\ ["Validate", "LMB"],\ ["Rebool", "Shift"] ] elif self.CutMode == CIRCLE: help_txt +=[ ["Rotation and Radius", "MouseMove"],\ ["Move all", "Alt"],\ ["Subdivision", self.carver_prefs.Key_Subrem + " " + self.carver_prefs.Key_Subadd],\ ["Incremental rotation", "Ctrl"],\ ["Rebool", "Shift"] ] elif self.CutMode == LINE: help_txt +=[ ["Dimension", "MouseMove"],\ ["Move all", "Alt"],\ ["Validate", "Space"],\ ["Rebool", "Shift"],\ ["Snap", "Ctrl"],\ ["Scale Snap", "WheelMouse"],\ ] else: # ObjectMode help_txt +=[ ["Difference", "Space"],\ ["Rebool", "Shift + Space"],\ ["Duplicate", "Alt + Space"],\ ["Scale", self.carver_prefs.Key_Scale],\ ["Rotation", "LMB + Move"],\ ["Step Angle", "CTRL + LMB + Move"],\ ] if self.ProfileMode: help_txt += [[ "Previous or Next Profile", self.carver_prefs.Key_Subadd + " " + self.carver_prefs.Key_Subrem ]] help_txt +=[ ["Create / Delete rows", chr(8597)],\ ["Create / Delete cols", chr(8596)],\ ["Gap for rows or columns", self.carver_prefs.Key_Gapy + " " + self.carver_prefs.Key_Gapx] ] blf.size(0, int(round(15 * bpy.context.preferences.view.ui_scale, 0)), 72) help_txt, bloc_height, max_option, max_key, comma = get_text_info( self, context, help_txt) draw_string(self, color1, color2, xHelp, yHelp, help_txt, max_option) if self.ProfileMode: xrect = region.width - t_panel_width - 80 yrect = 80 coords = [(xrect, yrect), (xrect + 60, yrect), (xrect + 60, yrect - 60), (xrect, yrect - 60)] # Draw rectangle background in the lower right draw_shader(self, (0.0, 0.0, 0.0), 0.3, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) # Use numpy to get the vertices and indices of the profile object to draw WidthProfil = 50 location = Vector((region.width - t_panel_width - WidthProfil, 50, 0)) ProfilScale = 20.0 coords = [] mesh = bpy.data.meshes[self.Profils[self.nProfil][0]] mesh.calc_loop_triangles() vertices = np.empty((len(mesh.vertices), 3), 'f') indices = np.empty((len(mesh.loop_triangles), 3), 'i') mesh.vertices.foreach_get("co", np.reshape(vertices, len(mesh.vertices) * 3)) mesh.loop_triangles.foreach_get( "vertices", np.reshape(indices, len(mesh.loop_triangles) * 3)) for idx, vals in enumerate(vertices): coords.append([ vals[0] * ProfilScale + location.x, vals[1] * ProfilScale + location.y, vals[2] * ProfilScale + location.z ]) #Draw the silhouette of the mesh draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) if self.CutMode: if len(self.mouse_path) > 1: x0 = self.mouse_path[0][0] y0 = self.mouse_path[0][1] x1 = self.mouse_path[1][0] y1 = self.mouse_path[1][1] # Cut rectangle if self.CutType == RECTANGLE: coords = [ (x0 + self.xpos, y0 + self.ypos), (x1 + self.xpos, y0 + self.ypos), \ (x1 + self.xpos, y1 + self.ypos), (x0 + self.xpos, y1 + self.ypos) ] indices = ((0, 1, 2), (2, 0, 3)) self.rectangle_coord = coords draw_shader(self, UIColor, 1, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) #Draw points draw_shader(self, UIColor, 1, 'POINTS', coords, size=3) if self.shift or self.CreateMode: draw_shader(self, UIColor, 0.5, 'TRIS', coords, size=self.carver_prefs.LineWidth, indices=indices) # Draw grid (based on the overlay options) to show the incremental snapping if self.ctrl: mini_grid(self, context, UIColor) # Cut Line elif self.CutType == LINE: coords = [] indices = [] top_grid = False for idx, vals in enumerate(self.mouse_path): coords.append([vals[0] + self.xpos, vals[1] + self.ypos]) indices.append([idx]) # Draw lines if self.Closed: draw_shader(self, UIColor, 1.0, 'LINE_LOOP', coords, size=self.carver_prefs.LineWidth) else: draw_shader(self, UIColor, 1.0, 'LINE_STRIP', coords, size=self.carver_prefs.LineWidth) # Draw points draw_shader(self, UIColor, 1.0, 'POINTS', coords, size=3) # Draw polygon if (self.shift) or (self.CreateMode and self.Closed): draw_shader(self, UIColor, 0.5, 'TRI_FAN', coords, size=self.carver_prefs.LineWidth) # Draw grid (based on the overlay options) to show the incremental snapping if self.ctrl: mini_grid(self, context, UIColor) # Circle Cut elif self.CutType == CIRCLE: # Create a circle using a tri fan tris_coords, indices = draw_circle(self, x0, y0) # Remove the vertex in the center to get the outer line of the circle line_coords = tris_coords[1:] draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=self.carver_prefs.LineWidth) if self.shift or self.CreateMode: draw_shader(self, UIColor, 0.5, 'TRIS', tris_coords, size=self.carver_prefs.LineWidth, indices=indices) if (self.ObjectMode or self.ProfileMode) and len(self.CurrentSelection) > 0: if self.ShowCursor: region = context.region rv3d = context.space_data.region_3d if self.ObjectMode: ob = self.ObjectBrush if self.ProfileMode: ob = self.ProfileBrush mat = ob.matrix_world # 50% alpha, 2 pixel width line bgl.glEnable(bgl.GL_BLEND) bbox = [mat @ Vector(b) for b in ob.bound_box] objBBDiagonal = objDiagonal(self.CurrentSelection[0]) if self.shift: gl_size = 4 UIColor = (0.5, 1.0, 0.0, 1.0) else: gl_size = 2 UIColor = (1.0, 0.8, 0.0, 1.0) line_coords = [] idx = 0 CRadius = ((bbox[7] - bbox[0]).length) / 2 for i in range(int(len(self.CLR_C) / 3)): vector3d = (self.CLR_C[idx * 3] * CRadius + self.CurLoc.x, \ self.CLR_C[idx * 3 + 1] * CRadius + self.CurLoc.y, \ self.CLR_C[idx * 3 + 2] * CRadius + self.CurLoc.z) vector2d = bpy_extras.view3d_utils.location_3d_to_region_2d( region, rv3d, vector3d) if vector2d is not None: line_coords.append((vector2d[0], vector2d[1])) idx += 1 if len(line_coords) > 0: draw_shader(self, UIColor, 1.0, 'LINE_LOOP', line_coords, size=gl_size) # Object display if self.quat_rot is not None: ob.location = self.CurLoc v = Vector() v.x = v.y = 0.0 v.z = self.BrushDepthOffset ob.location += self.quat_rot @ v e = Euler() e.x = 0.0 e.y = 0.0 e.z = self.aRotZ / 25.0 qe = e.to_quaternion() qRot = self.quat_rot @ qe ob.rotation_mode = 'QUATERNION' ob.rotation_quaternion = qRot ob.rotation_mode = 'XYZ' if self.ProfileMode: if self.ProfileBrush is not None: self.ProfileBrush.location = self.CurLoc self.ProfileBrush.rotation_mode = 'QUATERNION' self.ProfileBrush.rotation_quaternion = qRot self.ProfileBrush.rotation_mode = 'XYZ' # Opengl defaults bgl.glLineWidth(1) bgl.glDisable(bgl.GL_BLEND)
def duplicateObject(self): if self.Instantiate: bpy.ops.object.duplicate_move_linked( OBJECT_OT_duplicate={ "linked": True, "mode": 'TRANSLATION', }, TRANSFORM_OT_translate={ "value": (0, 0, 0), }, ) else: bpy.ops.object.duplicate_move( OBJECT_OT_duplicate={ "linked": False, "mode": 'TRANSLATION', }, TRANSFORM_OT_translate={ "value": (0, 0, 0), }, ) ob_new = bpy.context.active_object ob_new.location = self.CurLoc v = Vector() v.x = v.y = 0.0 v.z = self.BrushDepthOffset ob_new.location += self.qRot * v if self.ObjectMode: ob_new.scale = self.ObjectBrush.scale if self.ProfileMode: ob_new.scale = self.ProfileBrush.scale e = Euler() e.x = e.y = 0.0 e.z = self.aRotZ / 25.0 # If duplicate with a grid, no random rotation (each mesh in the grid is already rotated randomly) if (self.alt is True) and ((self.nbcol + self.nbrow) < 3): if self.RandomRotation: e.z += random.random() qe = e.to_quaternion() qRot = self.qRot * qe ob_new.rotation_mode = 'QUATERNION' ob_new.rotation_quaternion = qRot ob_new.rotation_mode = 'XYZ' if (ob_new.display_type == "WIRE") and (self.BrushSolidify is False): ob_new.hide_viewport = True if self.BrushSolidify: ob_new.display_type = "SOLID" ob_new.show_in_front = False for o in bpy.context.selected_objects: UndoAdd(self, "DUPLICATE", o) if len(bpy.context.selected_objects) > 0: bpy.ops.object.select_all(action='TOGGLE') for o in self.all_sel_obj_list: o.select_set(True) bpy.context.view_layer.objects.active = self.OpsObj
pos = Vector() nameOfTire = "Tire" rot = Euler((0, 0, 0)) mag = Vector((0, 0, 0)) vo = Vector((60.0, 60.0, 60.0)) targetName = "Target" bpy.data.objects[nameOfTire + "1"].location = Vector((0.3, -0.3, 0)) bpy.data.objects[nameOfTire + "2"].location = Vector((-0.3, 0.3, 0)) bpy.data.objects[nameOfTire + "3"].location = Vector((0.3, 0.3, 0)) bpy.data.objects[nameOfTire + "4"].location = Vector((-0.3, -0.3, 0)) tires = [] frame_num = 10 # frames in animation rot.x = 90 rot.z = 0 objTarget = bpy.data.objects[str(targetName)] car = bpy.data.objects["car"] def rotate(sce): speed = mag * vo for index in range(1, 5): name = str(nameOfTire) + str(index) obj = bpy.data.objects[str(name)] tires.insert(index, obj) rot.y += 1 vo.y = rot.y * math.pi / 180 mag.y = objTarget.location.z