Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2006-04-05 22:54:38 +0400
committerCampbell Barton <ideasman42@gmail.com>2006-04-05 22:54:38 +0400
commit086cb9d7934c492f2e08b0546ab8e3367fc10235 (patch)
treefb0e5e9c41bcc821a3d1660aa0979dfc4916ee4e
parentde44e6c29e632ac856b3e5f49285fba614a0b320 (diff)
Added BPyMesh for mesh python mesh functions.
at the moment it only has meshWeight2Dict and dict2MeshWeight These allow you to deal with vertex weights as a list of dicts which makes scrips short and easy to understand. (kh_python, perhaps dict access to the python verts could replace this ) Used the above util functions to update mesh_cleanup. Copied from the source 'Material Clean', 'Remove unused materials.' 'VGroups' 'Group Clean', 'Remove vertex groups that have no verts using them.' 'Weight Clean', 'Remove zero weighted verts from groups (limit is zero threshold).' 'Weight Normalize', 'Make the sum total of vertex weights accross vgroups 1.0 for each vertex.' Normalizing lets you see how much % of the vertex a bone owns just by looking at 1 of the bone weights. Would be nice to have this functionality in Blender but theres not much room for new buttons in teh vgroup and material area :/
-rw-r--r--release/scripts/bpymodules/BPyMesh.py146
-rw-r--r--release/scripts/mesh_cleanup.py212
2 files changed, 304 insertions, 54 deletions
diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py
new file mode 100644
index 00000000000..61a3d3056d2
--- /dev/null
+++ b/release/scripts/bpymodules/BPyMesh.py
@@ -0,0 +1,146 @@
+import Blender
+
+def meshWeight2Dict(me):
+ ''' Takes a mesh and return its group names and a list of dicts, one dict per vertex.
+ using the group as a key and a float value for the weight.
+ These 2 lists can be modified and then used with dict2MeshWeight to apply the changes.
+ '''
+
+ vWeightDicts= [dict() for i in xrange(len(me.verts))] # Sync with vertlist.
+
+ # Clear the vert group.
+ groupNames= me.getVertGroupNames()
+
+ for group in groupNames:
+ for index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples.
+ vWeightDicts[index][group]= weight
+
+ for group in groupNames:
+ me.removeVertGroup(group)
+
+ return groupNames, vWeightDicts
+
+
+def dict2MeshWeight(me, groupNames, vWeightDict):
+ ''' Takes a list of groups and a list of vertex Weight dicts as created by meshWeight2Dict
+ and applys it to the mesh.'''
+
+ if len(vWeightDict) != len(me.verts):
+ raise 'Error, Lists Differ in size, do not modify your mesh.verts before updating the weights'
+
+ # Clear the vert group.
+ currentGroupNames= me.getVertGroupNames()
+ for group in currentGroupNames:
+ me.removeVertGroup(group)
+
+ # Add clean unused vert groupNames back
+ for group in groupNames:
+ me.addVertGroup(group)
+
+ add_ = Blender.Mesh.AssignModes.ADD
+
+ vertList= [None]
+ for i, v in enumerate(me.verts):
+ vertList[0]= i
+ for group, weight in vWeightDict[i].iteritems():
+ try:
+ me.assignVertsToGroup(group, vertList, weight, add_)
+ except:
+ pass # vert group is not used anymore.
+
+ me.update()
+
+
+
+#~ # Test normalize.
+#~ if __name__ == '__main__':
+ #~ ob= Blender.Scene.GetCurrent().getActiveObject()
+ #~ me= ob.getData(mesh=1)
+
+ #~ wdct= meshWeight2Dict(me)
+ #~ wdct_new= [w.copy() for w in wdct] # Make a copy for the new data. so verts dont get blured unevenly.
+
+ #~ '''
+ #~ for wv in wdct: # Weight verts.
+ #~ for key,val in wv.iteritems():
+ #~ wv[key]= val*0.5
+ #~ '''
+ #~ # Normalize between bones.
+ #~ '''
+ #~ for wv in wdct: # Weight verts.
+ #~ no=0.0
+ #~ for val in wv.itervalues():
+ #~ no+=val
+
+ #~ if no>0:
+ #~ for key,val in wv.iteritems():
+ #~ wv[key]/=no
+ #~ '''
+
+ #~ # remove
+
+
+
+
+ #~ '''
+ #~ radius= 0.1
+ #~ strength=0.5
+ #~ # Distance based radial blur,
+ #~ vertEdgeUsers= [list() for i in xrange(len(me.verts))]
+
+ #~ # Build edge lengths and face users for this data.
+ #~ edgeLengths= [(ed.v1.co-ed.v2.co).length for ed in me.edges\
+ #~ if vertEdgeUsers[ed.v1.index].append(ed)== None and\
+ #~ vertEdgeUsers[ed.v2.index].append(ed) == None ]
+
+
+
+ #~ for i, vertShared, in enumerate(vertEdgeUsers):
+ #~ vert_hub= me.verts[i]
+ #~ dummy_weight= {}
+ #~ for cnctEd in vertShared:
+ #~ if cnctEd.v1==vert_hub:
+ #~ cnctVt= cnctEd.v2
+ #~ else:
+ #~ cnctVt= cnctEd.v1
+
+
+ #~ cnct_weight= wdct[cnctVt.index] # copy from, old var
+
+ #~ for group, weight in cnct_weight.iteritems():
+ #~ w= weight / len(vertShared) # Scale the weight...
+ #~ try:
+ #~ dummy_weight[group] += w
+ #~ except:
+ #~ dummy_weight[group] = w
+
+ #~ # New add the collected dumy weight to the vertex.
+
+
+ #~ length= edgeLengths[cnctEd.index]
+
+ #~ if length != 0 and length < radius:
+ #~ factor= strength #length/radius # < 1
+ #~ factor_inv= 1.0-factor
+
+ #~ # Add the cnctVt's weight to the vert_hub's.
+ #~ hub_weight= wdct_new[i] # copy to new var
+ #~ cnct_weight= wdct[cnctVt.index] # copy from, old var
+
+ #~ for group, weight in dummy_weight.iteritems():
+ #~ try:
+ #~ hub_weight[group]= ((hub_weight[group]*factor) + (weight*factor_inv)) * 0.9
+ #~ except:
+ #~ hub_weight[group]= (weight*factor_inv)* 0.9
+
+ #~ for group, weight in hub_weight.iteritems():
+ #~ try:
+ #~ dummy_weight[group]
+ #~ except:
+ #~ hub_weight[group]= weight*factor
+ #~ '''
+ #~ dict2MeshWeight(me, wdct_new)
+
+
+
+ \ No newline at end of file
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()
-