diff options
Diffstat (limited to 'release/scripts/mesh_cleanup.py')
-rw-r--r-- | release/scripts/mesh_cleanup.py | 212 |
1 files changed, 158 insertions, 54 deletions
diff --git a/release/scripts/mesh_cleanup.py b/release/scripts/mesh_cleanup.py index 09b1ef7376c..2f3b3c8abd3 100644 --- a/release/scripts/mesh_cleanup.py +++ b/release/scripts/mesh_cleanup.py @@ -8,8 +8,14 @@ Tooltip: 'Clean unused data from all selected mesh objects.' from Blender import * from Blender.Mathutils import TriangleArea +import Blender +import BPyMesh +reload(BPyMesh) +dict2MeshWeight= BPyMesh.dict2MeshWeight +meshWeight2Dict= BPyMesh.meshWeight2Dict + def rem_free_verts(me): - vert_users = [0] * len(me.verts) + vert_users= [0] * len(me.verts) for f in me.faces: for v in f.v: vert_users[v.index]+=1 @@ -18,7 +24,7 @@ def rem_free_verts(me): for v in e: # loop on edge verts vert_users[v.index]+=1 - verts_free = [] + verts_free= [] for i, users in enumerate(vert_users): if not users: verts_free.append(i) @@ -33,19 +39,19 @@ def rem_free_edges(me, limit=None): def sortPair(a,b): return min(a,b), max(a,b) - edgeDict = {} # will use a set when python 2.4 is standard. + edgeDict= {} # will use a set when python 2.4 is standard. for f in me.faces: for i in xrange(len(f.v)): - edgeDict[sortPair(f.v[i].index, f.v[i-1].index)] = None + edgeDict[sortPair(f.v[i].index, f.v[i-1].index)]= None - edges_free = [] + edges_free= [] for e in me.edges: if not edgeDict.has_key(sortPair(e.v1.index, e.v2.index)): edges_free.append(e) if limit != None: - edges_free = [e for e in edges_free if (e.v1.co-e.v2.co).length <= limit] + edges_free= [e for e in edges_free if (e.v1.co-e.v2.co).length <= limit] me.edges.delete(edges_free) return len(edges_free) @@ -59,7 +65,7 @@ def rem_area_faces(me, limit=0.001): return\ TriangleArea(f.v[0].co, f.v[1].co, f.v[2].co) +\ TriangleArea(f.v[0].co, f.v[2].co, f.v[3].co) - rem_faces = [f for f in me.faces if faceArea(f) <= limit] + rem_faces= [f for f in me.faces if faceArea(f) <= limit] if rem_faces: me.faces.delete( 0, rem_faces ) return len(rem_faces) @@ -78,69 +84,134 @@ def rem_perimeter_faces(me, limit=0.001): (f.v[1].co-f.v[2].co).length +\ (f.v[2].co-f.v[3].co).length +\ (f.v[3].co-f.v[0].co).length - rem_faces = [f for f in me.faces if faceEdLen(f) <= limit] + rem_faces= [f for f in me.faces if faceEdLen(f) <= limit] if rem_faces: me.faces.delete( 0, rem_faces ) return len(rem_faces) -def main(): +def rem_unused_materials(me): + materials= me.materials + len_materials= len(materials) + if len_materials < 2: + return 0 + + rem_materials= 0 + + material_users= dict( [(i,0) for i in xrange(len_materials)] ) - def getLimit(text): - return Draw.PupFloatInput(text, 0.001, 0.0, 1.0, 0.1, 4) + for f in me.faces: + # Make sure the face index isnt too big. this happens sometimes. + if f.mat >= len_materials: + f.mat=0 + material_users[f.mat] += 1 + + mat_idx_subtract= 0 + reindex_mapping= dict( [(i,0) for i in xrange(len_materials)] ) + i= len_materials + while i: + i-=1 + + if material_users[i] == 0: + mat_idx_subtract+=1 + reindex_mapping[i]= mat_idx_subtract + materials.pop(i) + rem_materials+=1 + for f in me.faces: + f.mat= f.mat - reindex_mapping[f.mat] + + me.materials= materials + return rem_materials + + +def rem_free_groups(me, groupNames, vWeightDict): + ''' cound how many vert users a group has and remove unsued groups ''' + rem_groups = 0 + groupUserDict= dict([(group,0) for group in groupNames]) + + for vertexWeight in vWeightDict: + for group, weight in vertexWeight.iteritems(): + groupUserDict[group] += 1 + + i=len(groupNames) + while i: + i-=1 + group= groupNames[i] + if groupUserDict[group] == 0: + del groupNames[i] + print '\tremoving, vgroup', group + rem_groups+=1 + return rem_groups + +def rem_zero_weights(me, limit, groupNames, vWeightDict): + ''' remove verts from a group when their weight is zero.''' + rem_vweight_count= 0 + for vertexWeight in vWeightDict: + items= vertexWeight.items() + for group, weight in items: + if weight < limit: + del vertexWeight[group] + rem_vweight_count+= 1 + + return rem_vweight_count + - scn = Scene.GetCurrent() - obsel = Object.GetSelected() - actob = scn.getActiveObject() +def normalize_vweight(me, groupNames, vWeightDict): + for vertexWeight in vWeightDict: + unit= 0.0 + for group, weight in vertexWeight.iteritems(): + unit+= weight + + if unit != 1.0 and unit != 0.0: + for group, weight in vertexWeight.iteritems(): + vertexWeight[group]= weight/unit + + + +def main(): + scn= Scene.GetCurrent() + obsel= Object.GetSelected() + actob= scn.getActiveObject() - is_editmode = Window.EditMode() + is_editmode= Window.EditMode() # Edit mode object is not active, add it to the list. if is_editmode and (not actob.sel): obsel.append(actob) - meshes = [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh'] + meshes= [ob.getData(mesh=1) for ob in obsel if ob.getType() == 'Mesh'] #====================================# # Popup menu to select the functions # #====================================# - ''' - if not meshes: - Draw.PupMenu('ERROR%t|no meshes in selection') - return - method = Draw.PupMenu(""" -Clean Mesh, Remove...%t| -Verts: free standing| -Edges: not in a face| -Edges: below a length| -Faces: below an area|%l| -All of the above|""") - if method == -1: - return - - if method >= 3: - limit = getLimit('threshold: ') - - print 'method', method - ''' - - - CLEAN_VERTS_FREE = Draw.Create(1) - CLEAN_EDGE_NOFACE = Draw.Create(0) - CLEAN_EDGE_SMALL = Draw.Create(0) - CLEAN_FACE_PERIMETER = Draw.Create(0) - CLEAN_FACE_SMALL = Draw.Create(0) - limit = Draw.Create(0.01) + CLEAN_VERTS_FREE= Draw.Create(1) + CLEAN_EDGE_NOFACE= Draw.Create(0) + CLEAN_EDGE_SMALL= Draw.Create(0) + CLEAN_FACE_PERIMETER= Draw.Create(0) + CLEAN_FACE_SMALL= Draw.Create(0) + + CLEAN_MATERIALS= Draw.Create(0) + CLEAN_GROUP= Draw.Create(0) + CLEAN_VWEIGHT= Draw.Create(0) + CLEAN_WEIGHT_NORMALIZE= Draw.Create(0) + limit= Draw.Create(0.01) # Get USER Options - pup_block = [\ + pup_block= [\ ('Verts: free', CLEAN_VERTS_FREE, 'Remove verts that are not used by an edge or a face.'),\ ('Edges: free', CLEAN_EDGE_NOFACE, 'Remove edges that are not in a face.'),\ ('Edges: short', CLEAN_EDGE_SMALL, 'Remove edges that are below the length limit.'),\ ('Faces: small perimeter', CLEAN_FACE_PERIMETER, 'Remove faces below the perimeter limit.'),\ ('Faces: small area', CLEAN_FACE_SMALL, 'Remove faces below the area limit (may remove faces stopping T-face artifacts).'),\ + 'Materials',\ + ('Material Clean', CLEAN_MATERIALS, 'Remove unused materials.'),\ + 'VGroups',\ + ('Group Clean', CLEAN_GROUP, 'Remove vertex groups that have no verts using them.'),\ + ('Weight Clean', CLEAN_VWEIGHT, 'Remove zero weighted verts from groups (limit is zero threshold).'),\ + ('Weight Normalize', CLEAN_WEIGHT_NORMALIZE, 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.'),\ + '',\ ('limit: ', limit, 0.001, 1.0, 'Limit used for the area and length tests above (a higher limit will remove more data).'),\ ] @@ -149,16 +220,20 @@ All of the above|""") return - CLEAN_VERTS_FREE = CLEAN_VERTS_FREE.val - CLEAN_EDGE_NOFACE = CLEAN_EDGE_NOFACE.val - CLEAN_EDGE_SMALL = CLEAN_EDGE_SMALL.val - CLEAN_FACE_PERIMETER = CLEAN_FACE_PERIMETER.val - CLEAN_FACE_SMALL = CLEAN_FACE_SMALL.val - limit = limit.val + CLEAN_VERTS_FREE= CLEAN_VERTS_FREE.val + CLEAN_EDGE_NOFACE= CLEAN_EDGE_NOFACE.val + CLEAN_EDGE_SMALL= CLEAN_EDGE_SMALL.val + CLEAN_FACE_PERIMETER= CLEAN_FACE_PERIMETER.val + CLEAN_FACE_SMALL= CLEAN_FACE_SMALL.val + CLEAN_MATERIALS= CLEAN_MATERIALS.val + CLEAN_GROUP= CLEAN_GROUP.val + CLEAN_VWEIGHT= CLEAN_VWEIGHT.val + CLEAN_WEIGHT_NORMALIZE= CLEAN_WEIGHT_NORMALIZE.val + limit= limit.val if is_editmode: Window.EditMode(0) - rem_face_count = rem_edge_count = rem_vert_count = 0 + rem_face_count= rem_edge_count= rem_vert_count= rem_material_count= rem_group_count= rem_vweight_count= 0 for me in meshes: if CLEAN_FACE_SMALL: @@ -175,10 +250,39 @@ All of the above|""") if CLEAN_VERTS_FREE: rem_vert_count += rem_free_verts(me) - + + if CLEAN_MATERIALS: + rem_material_count += rem_unused_materials(me) + + if CLEAN_VWEIGHT or CLEAN_GROUP or CLEAN_WEIGHT_NORMALIZE: + groupNames, vWeightDict= meshWeight2Dict(me) + + if CLEAN_VWEIGHT: + rem_vweight_count += rem_zero_weights(me, limit, groupNames, vWeightDict) + + if CLEAN_GROUP: + rem_group_count += rem_free_groups(me, groupNames, vWeightDict) + pass + + if CLEAN_WEIGHT_NORMALIZE: + normalize_vweight(me, groupNames, vWeightDict) + + # Copy back to mesh vertex groups. + dict2MeshWeight(me, groupNames, vWeightDict) + + if is_editmode: Window.EditMode(0) - Draw.PupMenu('Removed from ' + str(len(meshes)) +' Mesh(es)%t|' + 'Verts:' + str(rem_vert_count) + ' Edges:' + str(rem_edge_count) + ' Faces:' + str(rem_face_count)) + stat_string= 'Removed from ' + str(len(meshes)) + ' Mesh(es)%t|' + + if CLEAN_VERTS_FREE: stat_string+= 'Verts: %i|' % rem_edge_count + if CLEAN_EDGE_SMALL or CLEAN_EDGE_NOFACE: stat_string+= 'Edges: %i|' % rem_edge_count + if CLEAN_FACE_SMALL or CLEAN_FACE_PERIMETER: stat_string+= 'Faces: %i|' % rem_face_count + if CLEAN_MATERIALS: stat_string+= 'Materials: %i|' % rem_material_count + if CLEAN_VWEIGHT: stat_string+= 'VWeights: %i|' % rem_vweight_count + if CLEAN_GROUP: stat_string+= 'VGroups: %i|' % rem_group_count + + Draw.PupMenu(stat_string) + if __name__ == '__main__': main() - |