# gpl author: Pistiwique bl_info = { "name": "Mesh Check BGL edition", "description": "Display the triangles and ngons of the mesh", "author": "Pistiwique", "version": (1, 0, 1), "blender": (2, 75, 0), "location": "3D View(s) > Properties > Shading", "category": "3D View" } import bpy import bmesh from bgl import ( glBegin, glLineWidth, glColor4f, glVertex3f, glEnd, GL_LINES, glEnable, glDisable, GL_DEPTH_TEST, GL_BLEND, GL_POLYGON ) from mathutils.geometry import tessellate_polygon as tessellate from bpy.types import ( Operator, PropertyGroup, ) from bpy.props import ( BoolProperty, EnumProperty, FloatProperty, FloatVectorProperty, PointerProperty, ) # -- Globals -- # 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(Operator): bl_idname = "object.face_type_select" bl_label = "Face type select" bl_description = "Select Triangles and / or Ngons on the Active Object" bl_options = {'REGISTER', 'UNDO'} face_type = EnumProperty( name="Face Type", items=(('tris', "Tris", "Colorize Triangles in the Mesh"), ('ngons', "Ngons", "Colorize Ngons in the Mesh")), 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(PropertyGroup): mesh_check_use = BoolProperty( name="Mesh Check", description="Display Mesh Check options", default=False, update=updateBGLData ) display_faces = BoolProperty( name="Display Faces", description="Use BGL to display Ngons and Tris of the mesh", default=False, update=updateBGLData ) edge_width = FloatProperty( name="Width", description="Drawn Edges width in pixels", min=1.0, max=10.0, default=3.0, subtype='PIXEL', update=updateBGLData ) finer_lines_behind_use = BoolProperty( name="Finer Lines behind", description="Display partially hidden edges finer in non-occlude mode", default=True, update=updateBGLData ) custom_tri_color = 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 = 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 = 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 ) # Register classes = ( FaceTypeSelect, MeshCheckCollectionGroup, ) def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.WindowManager.mesh_check = 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()