diff options
author | meta-androcto <meta.androcto1@gmail.com> | 2017-03-30 09:31:07 +0300 |
---|---|---|
committer | meta-androcto <meta.androcto1@gmail.com> | 2017-03-30 09:31:07 +0300 |
commit | ba89ec341ccea23d480d3c23c51ebaaf2bb88ee5 (patch) | |
tree | e32332cba3cb599b7c1e19126b9273a5d14964e1 /mesh_extra_tools | |
parent | f53017167bdd9854a65690c23cbc90cf1f9d37ea (diff) |
Update Mesh Edit Tools: T50680
Diffstat (limited to 'mesh_extra_tools')
-rw-r--r-- | mesh_extra_tools/__init__.py | 76 | ||||
-rw-r--r-- | mesh_extra_tools/icons/icons.py | 31 | ||||
-rw-r--r-- | mesh_extra_tools/icons/ngon.png | bin | 0 -> 6747 bytes | |||
-rw-r--r-- | mesh_extra_tools/icons/triangle.png | bin | 0 -> 4153 bytes | |||
-rw-r--r-- | mesh_extra_tools/mesh_check.py | 448 | ||||
-rw-r--r-- | mesh_extra_tools/mesh_mextrude_plus.py | 152 | ||||
-rw-r--r-- | mesh_extra_tools/pkhg_faces.py | 27 |
7 files changed, 667 insertions, 67 deletions
diff --git a/mesh_extra_tools/__init__.py b/mesh_extra_tools/__init__.py index 90f5c674..89b9a453 100644 --- a/mesh_extra_tools/__init__.py +++ b/mesh_extra_tools/__init__.py @@ -63,6 +63,7 @@ if "bpy" in locals(): importlib.reload(mesh_selection_topokit) importlib.reload(mesh_info_select) importlib.reload(mesh_extrude_and_reshape) + importlib.reload(mesh_check) else: from . import face_inset_fillet @@ -83,6 +84,7 @@ else: from . import vfe_specials from . import mesh_help from . import mesh_extrude_and_reshape + from . import mesh_check from .mesh_select_tools import mesh_select_by_direction from .mesh_select_tools import mesh_select_by_edge_length @@ -93,7 +95,11 @@ else: from .mesh_select_tools import mesh_selection_topokit from .mesh_select_tools import mesh_info_select + from . icons.icons import load_icons + import bpy +import bmesh +from bpy.props import EnumProperty from bpy.types import ( Menu, Panel, @@ -316,6 +322,11 @@ class EditToolsPanel(Panel): row.operator("mesh.extra_tools_help", icon="LAYER_USED").help_ids = "split_solidify" + row = layout.split(0.8, align=True) + row.operator("mesh.add_faces_to_object", "Shape Extrude") + row.operator("mesh.extra_tools_help", + icon="LAYER_USED").help_ids = "pkhg_faces" + # Utils options box1 = self.layout.box() col = box1.column(align=True) @@ -353,11 +364,64 @@ class EditToolsPanel(Panel): row = layout.row(align=True) row.operator("mesh.select_vert_edge_face_index", - icon="VERTEXSEL", text="Vert Index").select_type = 'VERT' - row.operator("mesh.select_vert_edge_face_index", - icon="EDGESEL", text="Edge Index").select_type = 'EDGE' - row.operator("mesh.select_vert_edge_face_index", - icon="FACESEL", text="Face Index").select_type = 'FACE' + icon="VERTEXSEL", text="Select By Index").select_type = 'VERT' + + layout = self.layout + icons = load_icons() + tris = icons.get("triangles") + ngons = icons.get("ngons") + + + mesh_check = context.window_manager.mesh_check + + layout.prop(mesh_check, "mesh_check_use") + + if mesh_check.mesh_check_use: + layout = self.layout + + row = layout.row() + row.operator("object.face_type_select", text="Tris", icon_value=tris.icon_id).face_type = 'tris' + row.operator("object.face_type_select", text="Ngons",icon_value=ngons.icon_id).face_type = 'ngons' + row = layout.row() + row.prop(mesh_check, "display_faces", text="Display Faces") + if mesh_check.display_faces: + row = layout.row() + row.prop(mesh_check, "edge_width") + row = layout.row() + row.prop(mesh_check, "custom_tri_color",text="Tris color" ) + row = layout.row() + row.prop(mesh_check, "custom_ngons_color") + row = layout.row() + row.prop(mesh_check, "face_opacity") + if bpy.context.object.mode == 'EDIT': + obj = bpy.context.object + me = obj.data + bm = bmesh.from_edit_mesh(me) + + info_str = "" + tris = ngons = 0 + + for f in bm.faces: + + v = len(f.verts) + if v == 3: + tris += 1 + elif v > 4: + ngons += 1 + + bmesh.update_edit_mesh(me) + info_str = " Ngons: %i Tris: %i" % (ngons, tris) + + split = layout.split(percentage=0.1) + split.separator() + split.label(info_str, icon='MESH_DATA') + + if context.mode == 'EDIT_MESH' and not context.space_data.use_occlude_geometry: + split = layout.split(percentage=0.1) + split.separator() + split2 = split.split() + row = split2.row() + row.prop(mesh_check, "finer_lines_behind_use") # ********** Edit Multiselect ********** @@ -719,6 +783,7 @@ def register(): mesh_pen_tool.register() vfe_specials.register() mesh_extrude_and_reshape.register() + mesh_check.register() bpy.utils.register_module(__name__) # Register Scene Properties @@ -742,6 +807,7 @@ def unregister(): mesh_pen_tool.unregister() vfe_specials.unregister() mesh_extrude_and_reshape.unregister() + mesh_check.unregister() del bpy.types.Scene.mesh_extra_tools del bpy.types.Object.tkkey diff --git a/mesh_extra_tools/icons/icons.py b/mesh_extra_tools/icons/icons.py new file mode 100644 index 00000000..92b7d0db --- /dev/null +++ b/mesh_extra_tools/icons/icons.py @@ -0,0 +1,31 @@ +import os +import bpy +import bpy.utils.previews + +mesh_check_icon_collections = {} +mesh_check_icons_loaded = False + +def load_icons(): + global mesh_check_icon_collections + global mesh_check_icons_loaded + + if mesh_check_icons_loaded: return mesh_check_icon_collections["main"] + + custom_icons = bpy.utils.previews.new() + + icons_dir = os.path.join(os.path.dirname(__file__)) + + custom_icons.load("ngons", os.path.join(icons_dir, "ngon.png"), 'IMAGE') + custom_icons.load("triangles", os.path.join(icons_dir, "triangle.png"), 'IMAGE') + + mesh_check_icon_collections["main"] = custom_icons + mesh_check_icons_loaded = True + + return mesh_check_icon_collections["main"] + +def clear_icons(): + global mesh_check_icons_loaded + for icon in mesh_check_icon_collections.values(): + bpy.utils.previews.remove(icon) + mesh_check_icon_collections.clear() + mesh_check_icons_loaded = False diff --git a/mesh_extra_tools/icons/ngon.png b/mesh_extra_tools/icons/ngon.png Binary files differnew file mode 100644 index 00000000..b1a79b98 --- /dev/null +++ b/mesh_extra_tools/icons/ngon.png diff --git a/mesh_extra_tools/icons/triangle.png b/mesh_extra_tools/icons/triangle.png Binary files differnew file mode 100644 index 00000000..05f3a8db --- /dev/null +++ b/mesh_extra_tools/icons/triangle.png diff --git a/mesh_extra_tools/mesh_check.py b/mesh_extra_tools/mesh_check.py new file mode 100644 index 00000000..a8f1ab6a --- /dev/null +++ b/mesh_extra_tools/mesh_check.py @@ -0,0 +1,448 @@ +bl_info = {"name": "Mesh Check BGL edition", + "description": "Display the triangles and ngons of the mesh", + "author": "Pistiwique", + "version": (1, 0, 0), + "blender": (2, 75, 0), + "location": "3D View(s) -> Properties -> Shading", + "category": "3D View" + } + + + +import bpy +from bgl import ( + glBegin, + glLineWidth, + glColor3f, + glColor4f, + glVertex3f, + glEnd, + GL_LINES, + glEnable, + glDisable, + GL_DEPTH_TEST, + GL_BLEND, + GL_POLYGON +) + +from mathutils.geometry import tessellate_polygon as tessellate +import bmesh +from mathutils import Vector + +from bpy.props import EnumProperty, PointerProperty + +mesh_check_handle = [] +draw_enabled = [False] +edge_width = [1.0] +face_opacity = [0.2] +edges_tri_color = [(1.0, 1.0, 0.0, 1)] +faces_tri_color = [(1.0, 1.0, 0.0, face_opacity[0])] +edges_ngons_color = [(1.0, 0.0, 0.0, 1.0)] +faces_ngons_color = [(1.0, 0.0, 0.0, face_opacity[0])] +bm_old = [None] +finer_lines = [False] + + +def draw_poly(points): + for i in range(len(points)): + glVertex3f(points[i][0], points[i][1], points[i][2]) + + +def mesh_check_draw_callback(): + obj = bpy.context.object + if obj and obj.type == 'MESH': + if draw_enabled[0]: + mesh = obj.data + matrix_world = obj.matrix_world + + glLineWidth(edge_width[0]) + + if bpy.context.mode == 'EDIT_MESH': + + use_occlude = True + + if bm_old[0] is None or not bm_old[0].is_valid: + bm = bm_old[0] = bmesh.from_edit_mesh(mesh) + + else: + bm = bm_old[0] + + no_depth = not bpy.context.space_data.use_occlude_geometry + + if no_depth: + glDisable(GL_DEPTH_TEST) + + use_occlude = False + + if finer_lines[0]: + glLineWidth(edge_width[0]/4.0) + use_occlude = True + + for face in bm.faces: + if len([verts for verts in face.verts]) == 3: + faces = [matrix_world*vert.co for vert in face.verts] + glColor4f(*faces_tri_color[0]) + glEnable(GL_BLEND) + glBegin(GL_POLYGON) + draw_poly(faces) + glEnd() + + for edge in face.edges: + if edge.is_valid: + edges = [matrix_world*vert.co for vert in edge.verts] + glColor4f(*edges_tri_color[0]) + glBegin(GL_LINES) + draw_poly(edges) + glEnd() + + elif len([verts for verts in face.verts]) > 4: + new_faces = [] + faces = [] + coords = [v.co for v in face.verts] + indices = [v.index for v in face.verts] + for pol in tessellate([coords]): + new_faces.append([indices[i] for i in pol]) + + for f in new_faces: + faces.append([((matrix_world*bm.verts[i].co)[0]+face.normal.x*0.001, + (matrix_world*bm.verts[i].co)[1]+face.normal.y*0.001, + (matrix_world*bm.verts[i].co)[2]+face.normal.z*0.001) + for i in f]) + + for f in faces: + glColor4f(*faces_ngons_color[0]) + glEnable(GL_BLEND) + glBegin(GL_POLYGON) + draw_poly(f) + glEnd() + + for edge in face.edges: + if edge.is_valid: + edges = [matrix_world*vert.co for vert in edge.verts] + glColor4f(*edges_ngons_color[0]) + glBegin(GL_LINES) + draw_poly(edges) + glEnd() + + glDisable(GL_BLEND) + glColor4f(0.0, 0.0, 0.0, 1.0) + glLineWidth(edge_width[0]) + glEnable(GL_DEPTH_TEST) + + if use_occlude: + + for face in bm.faces: + if len([verts for verts in face.verts]) == 3: + faces = [] + for vert in face.verts: + vert_face = matrix_world*vert.co + faces.append((vert_face[0]+face.normal.x*0.001, vert_face[1]+face.normal.y*0.001, vert_face[2]+face.normal.z*0.001)) + + glColor4f(*faces_tri_color[0]) + glEnable(GL_BLEND) + glBegin(GL_POLYGON) + draw_poly(faces) + glEnd() + + for edge in face.edges: + if edge.is_valid: + edges = [] + for vert in edge.verts: + vert_edge = matrix_world*vert.co + edges.append((vert_edge[0]+face.normal.x*0.001, vert_edge[1]+face.normal.y*0.001, vert_edge[2]+face.normal.z*0.001)) + glColor4f(*edges_tri_color[0]) + glBegin(GL_LINES) + draw_poly(edges) + glEnd() + + elif len([verts for verts in face.verts]) > 4: + new_faces = [] + faces = [] + coords = [v.co for v in face.verts] + indices = [v.index for v in face.verts] + for pol in tessellate([coords]): + new_faces.append([indices[i] for i in pol]) + + for f in new_faces: + faces.append([((matrix_world*bm.verts[i].co)[0]+face.normal.x*0.001, + (matrix_world*bm.verts[i].co)[1]+face.normal.y*0.001, + (matrix_world*bm.verts[i].co)[2]+face.normal.z*0.001) + for i in f]) + + for f in faces: + glColor4f(*faces_ngons_color[0]) + glEnable(GL_BLEND) + glBegin(GL_POLYGON) + draw_poly(f) + glEnd() + + for edge in face.edges: + if edge.is_valid: + edges = [] + for vert in edge.verts: + vert_edge = matrix_world*vert.co + edges.append((vert_edge[0]+face.normal.x*0.001, vert_edge[1]+face.normal.y*0.001, vert_edge[2]+face.normal.z*0.001)) + glColor4f(*edges_ngons_color[0]) + glBegin(GL_LINES) + draw_poly(edges) + glEnd() + + + glDisable(GL_BLEND) + glColor4f(0.0, 0.0, 0.0, 1.0) + + + +def updateBGLData(self, context): + if self.mesh_check_use and self.display_faces: + bpy.ops.object.mode_set(mode='EDIT') + draw_enabled[0] = True + edge_width[0] = self.edge_width + finer_lines[0] = self.finer_lines_behind_use + face_opacity[0] = self.face_opacity + edges_tri_color[0] = (self.custom_tri_color[0], + self.custom_tri_color[1], + self.custom_tri_color[2], + 1) + faces_tri_color[0] = (self.custom_tri_color[0], + self.custom_tri_color[1], + self.custom_tri_color[2], + self.face_opacity) + edges_ngons_color[0] = (self.custom_ngons_color[0], + self.custom_ngons_color[1], + self.custom_ngons_color[2], + 1) + + faces_ngons_color[0] = (self.custom_ngons_color[0], + self.custom_ngons_color[1], + self.custom_ngons_color[2], + self.face_opacity) + + return + + draw_enabled[0] = False + + +class FaceTypeSelect(bpy.types.Operator): + bl_idname = "object.face_type_select" + bl_label = "Face type select" + bl_options = {'REGISTER', 'UNDO'} + + face_type = bpy.props.EnumProperty( + items=(('tris', 'Tris', ""), + ('ngons', 'Ngons', "")), + default='ngons' + ) + + @classmethod + def poll(cls, context): + return context.active_object is not None and context.active_object.type == 'MESH' + + def execute(self, context): + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='DESELECT') + context.tool_settings.mesh_select_mode=(False, False, True) + + if self.face_type == "tris": + bpy.ops.mesh.select_face_by_sides(number=3, type='EQUAL') + else: + bpy.ops.mesh.select_face_by_sides(number=4, type='GREATER') + + return {'FINISHED'} + + +class MeshCheckCollectionGroup(bpy.types.PropertyGroup): + mesh_check_use = bpy.props.BoolProperty( + name="Mesh Check", + description="Display Mesh Check options", + default=False, + update=updateBGLData + ) + + + display_faces = bpy.props.BoolProperty( + name="Display Faces", + description="Use BGL to display ngons en tris of the mesh", + default=False, + update=updateBGLData + ) + + edge_width = bpy.props.FloatProperty( + name="Width", + description="Edges width in pixels", + min=1.0, + max=10.0, + default=3.0, + subtype='PIXEL', + update=updateBGLData) + + finer_lines_behind_use = bpy.props.BoolProperty( + name="Finer Lines behind", + description="Display partially hidden edges finer in non-occlude mode", + default=True, + update=updateBGLData) + + custom_tri_color = bpy.props.FloatVectorProperty( + name="Tri Color", + description="Custom color for the triangles", + min=0.0, + max=1.0, + default=(1.0, 1.0, 0.0), + size=3, + subtype='COLOR', + update=updateBGLData) + + custom_ngons_color = bpy.props.FloatVectorProperty( + name="Ngons Color", + description="custom color for the ngons", + min=0.0, + max=1.0, + default=(1.0, 0.0, 0.0), + size=3, + subtype='COLOR', + update=updateBGLData) + + face_opacity = bpy.props.FloatProperty( + name="Face Opacity", + description="Opacity of the color for the face", + min=0.0, + max=1.0, + default=0.2, + subtype='FACTOR', + update=updateBGLData) + +class DATA_OP_facetype_select(bpy.types.Operator): + """Select all faces of a certain type""" + bl_idname = "data.facetype_select" + bl_label = "Select by face type" + bl_options = {'REGISTER', 'UNDO'} + select_mode = bpy.props.StringProperty() + face_type = EnumProperty(name="Select faces:", + items=(("3", "Triangles", "Faces made up of 3 vertices"), + ("5", "Ngons", "Faces made up of 5 and more vertices")), + default="5") + + @classmethod + def poll(cls, context): + return context.object is not None and context.object.type == 'MESH' + + def execute(self, context): + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='DESELECT') + if tuple(bpy.context.tool_settings.mesh_select_mode) == (True, False, False): + self.select_mode = "VERT" + elif tuple(bpy.context.tool_settings.mesh_select_mode) == (False, True, False): + self.select_mode = "EDGE" + elif tuple(bpy.context.tool_settings.mesh_select_mode) == (False, False, True): + self.select_mode = "FACE" + context.tool_settings.mesh_select_mode = (False, False, True) + if self.face_type == "3": + bpy.ops.mesh.select_face_by_sides(number=3, type='EQUAL') + bpy.ops.mesh.select_mode(type=self.select_mode) + else: + bpy.ops.mesh.select_face_by_sides(number=4, type='GREATER') + bpy.ops.mesh.select_mode(type=self.select_mode) + return {'FINISHED'} + +def displayMeshCheckPanel(self, context): + layout = self.layout + icons = load_icons() + tris = icons.get("triangles") + ngons = icons.get("ngons") + + + mesh_check = context.window_manager.mesh_check + + layout.prop(mesh_check, "mesh_check_use") + + if mesh_check.mesh_check_use: + split = layout.split(percentage=0.1) + split.separator() + split2 = split.split() + row = split2.row(align=True) + row.operator("object.face_type_select", text="Tris", icon_value=tris.icon_id).face_type = 'tris' + row.operator("object.face_type_select", text="Ngons",icon_value=ngons.icon_id).face_type = 'ngons' + split = layout.split(percentage=0.1) + split.separator() + split.prop(mesh_check, "display_faces", text="Display Faces") + if mesh_check.display_faces: + split = layout.split(percentage=0.1) + split.separator() + split2 = split.split() + row = split2.row(align=True) + row.prop(mesh_check, "edge_width") + split = layout.split(percentage=0.1) + split.separator() + split2 = split.split() + row = split2.row() + row.prop(mesh_check, "custom_tri_color",text="Tris color" ) + split = layout.split(percentage=0.1) + split.separator() + split2 = split.split() + row = split2.row() + row.prop(mesh_check, "custom_ngons_color") + split = layout.split(percentage=0.1) + split.separator() + split2 = split.split() + row = split2.row() + row.prop(mesh_check, "face_opacity") + if bpy.context.object.mode == 'EDIT': + obj = bpy.context.object + me = obj.data + bm = bmesh.from_edit_mesh(me) + + info_str = "" + tris = ngons = 0 + + for f in bm.faces: + + v = len(f.verts) + if v == 3: + tris += 1 + elif v > 4: + ngons += 1 + + bmesh.update_edit_mesh(me) + info_str = " Ngons: %i Tris: %i" % (ngons, tris) + + split = layout.split(percentage=0.1) + split.separator() + split.label(info_str, icon='MESH_DATA') + + if context.mode == 'EDIT_MESH' and not context.space_data.use_occlude_geometry: + split = layout.split(percentage=0.1) + split.separator() + split2 = split.split() + row = split2.row() + row.prop(mesh_check, "finer_lines_behind_use") + + +classes = ( + FaceTypeSelect, + MeshCheckCollectionGroup, + DATA_OP_facetype_select + ) + +def register(): + + for cls in classes: + bpy.utils.register_class(cls) + bpy.types.WindowManager.mesh_check = bpy.props.PointerProperty( + type=MeshCheckCollectionGroup) + + if mesh_check_handle: + bpy.types.SpaceView3D.draw_handler_remove(mesh_check_handle[0], 'WINDOW') + mesh_check_handle[:] = [bpy.types.SpaceView3D.draw_handler_add(mesh_check_draw_callback, (), 'WINDOW', 'POST_VIEW')] + + +def unregister(): + + del bpy.types.WindowManager.mesh_check + if mesh_check_handle: + bpy.types.SpaceView3D.draw_handler_remove(mesh_check_handle[0], 'WINDOW') + mesh_check_handle[:] = [] + for cls in classes: + bpy.utils.unregister_class(cls) + +if __name__ == "__main__": + register() diff --git a/mesh_extra_tools/mesh_mextrude_plus.py b/mesh_extra_tools/mesh_mextrude_plus.py index 786db0f5..cb7c8b69 100644 --- a/mesh_extra_tools/mesh_mextrude_plus.py +++ b/mesh_extra_tools/mesh_mextrude_plus.py @@ -17,12 +17,15 @@ # ##### END GPL LICENSE BLOCK ##### # # Repeats extrusion + rotation + scale for one or more faces +# Original code by liero +# Update by Jimmy Hazevoet 03/2017 for Blender 2.79 +# normal rotation, probability, scaled offset, object origin, initial scale noise bl_info = { "name": "MExtrude Plus1", - "author": "liero", - "version": (1, 2, 9), + "author": "liero, Jimmy Hazevoet", + "version": (1, 3, 0), "blender": (2, 77, 0), "location": "View3D > Tool Shelf", "description": "Repeat extrusions from faces to create organic shapes", @@ -36,25 +39,27 @@ import bpy import bmesh import random from bpy.types import Operator -from random import gauss, choice +from random import gauss from math import radians -from mathutils import Euler +from mathutils import Euler, Vector from bpy.props import ( FloatProperty, IntProperty, + BoolProperty, + EnumProperty, ) - -# added normal rot -def nrot(self,n): - return Euler((radians(self.nrotx) * n[0], \ - radians(self.nroty) * n[1], \ - radians(self.nrotz) * n[2]), 'XYZ') +def gloc(self, r): + return Vector((self.offx, self.offy, self.offz)) def vloc(self, r): random.seed(self.ran + r) return self.off * (1 + gauss(0, self.var1 / 3)) +def nrot(self, n): + return Euler((radians(self.nrotx) * n[0], + radians(self.nroty) * n[1], + radians(self.nrotz) * n[2]), 'XYZ') def vrot(self, r): random.seed(self.ran + r) @@ -62,10 +67,9 @@ def vrot(self, r): radians(self.roty) + gauss(0, self.var2 / 3), radians(self.rotz) + gauss(0, self.var2 / 3)), 'XYZ') - def vsca(self, r): random.seed(self.ran + r) - return self.sca * (1 + random.gauss(0, self.var3 / 3)) + return self.sca * (1 + gauss(0, self.var3 / 3)) class MExtrude(Operator): @@ -73,15 +77,36 @@ class MExtrude(Operator): bl_label = "Multi Extrude" bl_description = ("Extrude selected Faces with Rotation,\n" "Scaling, Variation, Randomization") - bl_options = {"REGISTER", "UNDO"} + bl_options = {"REGISTER", "UNDO", "PRESET"} off = FloatProperty( name="Offset", soft_min=0.001, soft_max=2, min=-2, max=5, - default=.5, + default=1.0, description="Translation" ) + offx = FloatProperty( + name="Loc X", + soft_min=-2.0, soft_max=2.0, + min=-5.0, max=5.0, + default=0.0, + description="Global translation X" + ) + offy = FloatProperty( + name="Loc Y", + soft_min=-2.0, soft_max=2.0, + min=-5.0, max=5.0, + default=0.0, + description="Global translation Y" + ) + offz = FloatProperty( + name="Loc Z", + soft_min=-2.0, soft_max=2.0, + min=-5.0, max=5.0, + default=0.0, + description="Global translation Z" + ) rotx = FloatProperty( name="Rot X", min=-85, max=85, @@ -109,22 +134,21 @@ class MExtrude(Operator): min=-85, max=85, soft_min=-30, soft_max=30, default=0, - description="X Rotation" + description="Normal X Rotation" ) nroty = FloatProperty( name="N Rot Y", min=-85, max=85, - soft_min=-30, - soft_max=30, + soft_min=-30, soft_max=30, default=0, - description="Y Rotation" + description="Normal Y Rotation" ) nrotz = FloatProperty( name="N Rot Z", min=-85, max=85, soft_min=-30, soft_max=30, default=-0, - description="Z Rotation" + description="Normal Z Rotation" ) sca = FloatProperty( name="Scale", @@ -161,15 +185,38 @@ class MExtrude(Operator): ) num = IntProperty( name="Repeat", - min=1, max=50, + min=1, max=250, soft_max=100, default=5, - description="Repetitions") + description="Repetitions" + ) ran = IntProperty( name="Seed", min=-9999, max=9999, default=0, - description="Seed to feed random values") + description="Seed to feed random values" + ) + opt1 = BoolProperty( + name="Polygon coördinates", + default=True, + description="Polygon coördinates, Object coördinates" + ) + opt2 = BoolProperty( + name="Proportional offset", + default=False, + description="Scale * Offset" + ) + opt3 = BoolProperty( + name="Per step scale noise", + default=False, + description="Per step scale noise, Initial scale noise" + ) + opt4 = BoolProperty( + name="Per step rotation noise", + default=False, + description="Per step rotation noise, Initial rotation noise" + ) + @classmethod def poll(cls, context): @@ -178,16 +225,21 @@ class MExtrude(Operator): def draw(self, context): layout = self.layout - col = layout.column(align=True) col.label(text="Transformations:") col.prop(self, "off", slider=True) + col.prop(self, "offx", slider=True) + col.prop(self, "offy", slider=True) + col.prop(self, "offz", slider=True) + + col = layout.column(align=True) col.prop(self, "rotx", slider=True) col.prop(self, "roty", slider=True) col.prop(self, "rotz", slider=True) col.prop(self, 'nrotx', slider=True) col.prop(self, 'nroty', slider=True) col.prop(self, 'nrotz', slider=True) + col = layout.column(align=True) col.prop(self, "sca", slider=True) col = layout.column(align=True) @@ -200,13 +252,18 @@ class MExtrude(Operator): col = layout.column(align=False) col.prop(self, 'num') - - + col = layout.column(align=True) + col.label(text="Extra settings:") + col.prop(self, "opt1") + col.prop(self, "opt2") + col.prop(self, "opt3") + col.prop(self, "opt4") def execute(self, context): obj = bpy.context.object om = obj.mode bpy.context.tool_settings.mesh_select_mode = [False, False, True] + origin = Vector([0.0, 0.0, 0.0]) # bmesh operations bpy.ops.object.mode_set() @@ -218,28 +275,50 @@ class MExtrude(Operator): # faces loop for i, of in enumerate(sel): - rot = vrot(self, i) - off = vloc(self, i) nro = nrot(self, of.normal) + off = vloc(self, i) + loc = gloc(self, i) of.normal_update() + # initial scale noise + if self.opt3 is False: + s = vsca(self, i) + # initial rotation noise + if self.opt4 is False: + rot = vrot(self, i) + # extrusion loop - for r in range( self.num ): + for r in range(self.num): - ## random % skip some extrusions - if self.var4 >= int(random.random()*100): + ## random probability % for extrusions + if self.var4 > int(random.random()*100): nf = of.copy() nf.normal_update() no = nf.normal.copy() - ce = nf.calc_center_bounds() - s = vsca(self, i + r) + + # face/obj coördinates + if self.opt1 is True: + ce = nf.calc_center_bounds() + else: + ce = origin + + # per step scale noise + if self.opt3 is True: + s = vsca(self, i + r) + # per step rotation noise + if self.opt4 is True: + rot = vrot(self, i + r) + + # proportional, scale * offset + if self.opt2 is True: + off = s * off for v in nf.verts: v.co -= ce v.co.rotate(nro) v.co.rotate(rot) - v.co += ce + no * off + v.co += ce + loc + no * off v.co = v.co.lerp(ce, 1 - s) # extrude code from TrumanBlending @@ -247,9 +326,9 @@ class MExtrude(Operator): sf = bm.faces.new((a.vert, a.link_loop_next.vert, b.link_loop_next.vert, b.vert)) sf.normal_update() - bm.faces.remove(of) of = nf + after.append(of) for v in bm.verts: @@ -258,7 +337,10 @@ class MExtrude(Operator): e.select = False for f in after: - f.select = True + if f not in sel: + f.select = True + else: + f.select = False bm.to_mesh(obj.data) obj.data.update() diff --git a/mesh_extra_tools/pkhg_faces.py b/mesh_extra_tools/pkhg_faces.py index 10b0ca97..36992e65 100644 --- a/mesh_extra_tools/pkhg_faces.py +++ b/mesh_extra_tools/pkhg_faces.py @@ -461,33 +461,6 @@ class MESH_OT_add_faces_to_object(Operator): return {'FINISHED'} -class VIEW3D_Faces_Panel(Panel): - bl_label = "Face Extrude" - bl_space_type = "VIEW_3D" - bl_region_type = "TOOLS" - bl_category = "Tools" - bl_options = {"DEFAULT_CLOSED"} - - @classmethod - def poll(cls, context): - result = False - active_object = context.active_object - if active_object: - mesh_objects_name = [el.name for el in bpy.data.objects if el.type == "MESH"] - if active_object.name in mesh_objects_name: - if active_object.mode == "OBJECT": - result = True - return result - - def draw(self, context): - layout = self.layout - - row = layout.split(0.8, align=True) - row.operator("mesh.add_faces_to_object", "Selected Faces") - row.operator("mesh.extra_tools_help", - icon="LAYER_USED").help_ids = "pkhg_faces" - - def find_one_ring(sel_vertices): ring0 = sel_vertices.pop(0) to_delete = [] |