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-24 15:26:04 +0400
committerCampbell Barton <ideasman42@gmail.com>2006-04-24 15:26:04 +0400
commit11586835daff6adfe634855f332994930ed1c8b1 (patch)
tree5356b932ff262b2cff9d3014044e2979cc54a7af /release/scripts
parent94ebee891ca8b8c6003f000128d0e3633ee4576f (diff)
Added utility functions to BPyMesh.py
- dictWeightFlipGroups, return a vert weight with flipped group names. - dictWeightMerge, takes a list of dictWeights and merges them mesh_mirror_tool.py Added vertex weight support for the mirror tool, its able to mirror arbitary meshes weights with optional name flipping and creation of name flipped groups. This also uses the mode for l<>r, l>r, r>l so you can copy from left to right only for eg.
Diffstat (limited to 'release/scripts')
-rw-r--r--release/scripts/bpymodules/BPyMesh.py147
-rw-r--r--release/scripts/mesh_mirror_tool.py211
2 files changed, 295 insertions, 63 deletions
diff --git a/release/scripts/bpymodules/BPyMesh.py b/release/scripts/bpymodules/BPyMesh.py
index 140613ad873..b1a5765bf22 100644
--- a/release/scripts/bpymodules/BPyMesh.py
+++ b/release/scripts/bpymodules/BPyMesh.py
@@ -10,7 +10,7 @@ def meshWeight2Dict(me):
# Clear the vert group.
groupNames= me.getVertGroupNames()
-
+
for group in groupNames:
for index, weight in me.getVertsFromGroup(group, 1): # (i,w) tuples.
vWeightDict[index][group]= weight
@@ -56,7 +56,83 @@ def dict2MeshWeight(me, groupNames, vWeightDict):
me.update()
+def dictWeightMerge(dict_weights):
+ '''
+ Takes dict weight list and merges into 1 weight dict item and returns it
+ '''
+
+ if not dict_weights:
+ return {}
+
+ keys= []
+ for weight in dict_weights:
+ keys.extend([ (k, 0.0) for k in weight.iterkeys() ])
+
+ new_wdict = dict(keys)
+
+ len_dict_weights= len(dict_weights)
+
+ for weight in dict_weights:
+ for group, value in weight.iteritems():
+ new_wdict[group] += value/len_dict_weights
+
+ return new_wdict
+
+
+FLIPNAMES=[\
+('Left','Right'),\
+('_L','_R'),\
+('-L','-R'),\
+('.L','.R'),\
+]
+def dictWeightFlipGroups(dict_weight, groupNames, createNewGroups):
+ '''
+ Returns a weight with flip names
+ dict_weight - 1 vert weight.
+ groupNames - because we may need to add new group names.
+ dict_weight - Weather to make new groups where needed.
+ '''
+
+ def flipName(name):
+ for n1,n2 in FLIPNAMES:
+ for nA, nB in ( (n1,n2), (n1.lower(),n2.lower()), (n1.upper(),n2.upper()) ):
+ if createNewGroups:
+ newName= name.replace(nA,nB)
+ if newName!=name:
+ if newName not in groupNames:
+ groupNames.append(newName)
+ return newName
+
+ newName= name.replace(nB,nA)
+ if newName!=name:
+ if newName not in groupNames:
+ groupNames.append(newName)
+ return newName
+
+ else:
+ newName= name.replace(nA,nB)
+ if newName!=name and newName in groupNames:
+ return newName
+
+ newName= name.replace(nB,nA)
+ if newName!=name and newName in groupNames:
+ return newName
+
+ return name
+
+ if not dict_weight:
+ return dict_weight, groupNames
+
+
+ new_wdict = {}
+ for group, weight in dict_weight.iteritems():
+ flipname= flipName(group)
+ print flipname, group
+ new_wdict[flipname]= weight
+
+ return new_wdict, groupNames
+
def getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None):
'''
@@ -239,6 +315,75 @@ me.faces.extend([[me.verts[ii] for ii in i] for i in indices])
+from Blender import *
+
+def pointInsideMesh(ob, pt):
+ Intersect = Mathutils.Intersect # 2 less dict lookups.
+ Vector = Mathutils.Vector
+
+ def ptInFaceXYBounds(f, pt):
+
+ co= f.v[0].co
+ xmax= xmin= co.x
+ ymax= ymin= co.y
+
+ co= f.v[1].co
+ xmax= max(xmax, co.x)
+ xmin= min(xmin, co.x)
+ ymax= max(ymax, co.y)
+ ymin= min(ymin, co.y)
+
+ co= f.v[2].co
+ xmax= max(xmax, co.x)
+ xmin= min(xmin, co.x)
+ ymax= max(ymax, co.y)
+ ymin= min(ymin, co.y)
+
+ if len(f.v)==4:
+ co= f.v[3].co
+ xmax= max(xmax, co.x)
+ xmin= min(xmin, co.x)
+ ymax= max(ymax, co.y)
+ ymin= min(ymin, co.y)
+
+ # Now we have the bounds, see if the point is in it.
+ if\
+ pt.x < xmin or\
+ pt.y < ymin or\
+ pt.x > xmax or\
+ pt.y > ymax:
+ return False # point is outside face bounds
+ else:
+ return True # point inside.
+ #return xmax, ymax, xmin, ymin
+
+ def faceIntersect(f):
+ isect = Intersect(f.v[0].co, f.v[1].co, f.v[2].co, ray, obSpacePt, 1) # Clipped.
+ if not isect and len(f.v) == 4:
+ isect = Intersect(f.v[0].co, f.v[2].co, f.v[3].co, ray, obSpacePt, 1) # Clipped.
+
+ if isect and isect.z > obSpacePt.z: # This is so the ray only counts if its above the point.
+ return True
+ else:
+ return False
+
+
+ obImvMat = Mathutils.Matrix(ob.matrixWorld)
+ obImvMat.invert()
+ pt.resize4D()
+ obSpacePt = pt* obImvMat
+ pt.resize3D()
+ obSpacePt.resize3D()
+ ray = Vector(0,0,-1)
+ me= ob.getData(mesh=1)
+
+ # Here we find the number on intersecting faces, return true if an odd number (inside), false (outside) if its true.
+ return len([None for f in me.faces if ptInFaceXYBounds(f, obSpacePt) if faceIntersect(f)]) % 2
+
+
+
+
+
diff --git a/release/scripts/mesh_mirror_tool.py b/release/scripts/mesh_mirror_tool.py
index b86e429f10c..23c30324041 100644
--- a/release/scripts/mesh_mirror_tool.py
+++ b/release/scripts/mesh_mirror_tool.py
@@ -1,22 +1,23 @@
#!BPY
"""
-Name: 'Mirror Snap Verts'
+Name: 'Mirror Verts Loc & Weight'
Blender: 241
-Group: 'Object'
+Group: 'Mesh'
Tooltip: 'Move verts so they snap to their mirrored locations.'
"""
from Blender import Draw, Window, Scene, Mesh, Mathutils, sys
import BPyMesh
+reload(BPyMesh)
-
-def mesh_mirror(me, PREF_MAX_DIST, PREF_MODE, PREF_NOR_WEIGHT, PREF_SEL_ONLY, PREF_EDGE_USERS):
+def mesh_mirror(me, PREF_MIRROR_LOCATION, PREF_MAX_DIST, PREF_MODE, PREF_NOR_WEIGHT, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES):
'''
PREF_MAX_DIST, Maximum distance to test snapping verts.
PREF_MODE, 0:middle, 1: Left. 2:Right.
PREF_NOR_WEIGHT, use normal angle difference to weight distances.
PREF_SEL_ONLY, only snap the selection
PREF_EDGE_USERS, match only verts with the same number of edge users.
+ PREF_MIRROR_LOCATION,
'''
is_editmode = Window.EditMode() # Exit Editmode.
@@ -29,6 +30,7 @@ def mesh_mirror(me, PREF_MAX_DIST, PREF_MODE, PREF_NOR_WEIGHT, PREF_SEL_ONLY, PR
for v in me.verts:
v.sel=1
+
if PREF_EDGE_USERS:
edge_users= [0]*len(me.verts)
for ed in me.edges:
@@ -39,68 +41,135 @@ def mesh_mirror(me, PREF_MAX_DIST, PREF_MODE, PREF_NOR_WEIGHT, PREF_SEL_ONLY, PR
neg_vts = [v for v in me.verts if v.sel and v.co.x > 0.000001]
pos_vts = [v for v in me.verts if v.sel and v.co.x < -0.000001]
- mirror_pos= True
- mirror_weights=True
-
-
- groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
-
- mirror_pairs= []
- # allign the negative with the positive.
- flipvec= Mathutils.Vector()
- len_neg_vts= float(len(neg_vts))
- for i1, nv in enumerate(neg_vts):
- nv_co= nv.co
- for i2, pv in enumerate(pos_vts):
- # Enforce edge users.
- if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]:
- flipvec[:]= pv.co
- flipvec.x= -flipvec.x
- l= (nv_co-flipvec).length
-
- # Record a match.
- if l<=PREF_MAX_DIST:
+
+ #*Mirror Location*********************************************************#
+ if PREF_MIRROR_LOCATION:
+ mirror_pairs= []
+ # allign the negative with the positive.
+ flipvec= Mathutils.Vector()
+ len_neg_vts= float(len(neg_vts))
+ for i1, nv in enumerate(neg_vts):
+ nv_co= nv.co
+ for i2, pv in enumerate(pos_vts):
+ # Enforce edge users.
+ if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]:
+ flipvec[:]= pv.co
+ flipvec.x= -flipvec.x
+ l= (nv_co-flipvec).length
- # We can adjust the length by the normal, now we know the length is under the limit.
- if PREF_NOR_WEIGHT>0:
- # Get the normal and flipm reuse flipvec
- flipvec[:]= pv.no
- flipvec.x= -flipvec.x
- try:
- ang= Mathutils.AngleBetweenVecs(nv.no, flipvec)/180.0
- except: # on rare occasions angle between vecs will fail.- zero length vec.
- ang= 0
+ # Record a match.
+ if l<=PREF_MAX_DIST:
- l=l*(1+(ang*PREF_NOR_WEIGHT))
-
- mirror_pairs.append((l, nv, pv))
+ # We can adjust the length by the normal, now we know the length is under the limit.
+ if PREF_NOR_WEIGHT>0:
+ # Get the normal and flipm reuse flipvec
+ flipvec[:]= pv.no
+ flipvec.x= -flipvec.x
+ try:
+ ang= Mathutils.AngleBetweenVecs(nv.no, flipvec)/180.0
+ except: # on rare occasions angle between vecs will fail.- zero length vec.
+ ang= 0
+
+ l=l*(1+(ang*PREF_NOR_WEIGHT))
+
+ mirror_pairs.append((l, nv, pv))
+
+ # Update every 20 loops
+ if i1 % 10 == 0:
+ Window.DrawProgressBar(0.8 * (i1/len_neg_vts), 'Mirror verts %i of %i' % (i1, len_neg_vts))
- # Update every 20 loops
- if i1 % 10 == 0:
- Window.DrawProgressBar(0.8 * (i1/len_neg_vts), 'Mirror verts %i of %i' % (i1, len_neg_vts))
+ Window.DrawProgressBar(0.9, 'Mirror verts: Updating locations')
+ # Now we have a list of the pairs we might use, lets find the best and do them first.
+ # de-selecting as we go. so we can makke sure not to mess it up.
+ mirror_pairs.sort(lambda a,b: cmp(a[0], b[0]))
+ for dist, v1,v2 in mirror_pairs: # dist, neg, pos
+ if v1.sel and v2.sel:
+ if PREF_MODE==0: # Middle
+ flipvec[:]= v2.co # positive
+ flipvec.x= -flipvec.x # negatve
+ v2.co[:]= v1.co[:]= (flipvec+v1.co)*0.5 # midway
+ v2.co.x= -v2.co.x
+ elif PREF_MODE==2: # Left
+ v2.co[:]= v1.co
+ v2.co.x= -v2.co.x
+ elif PREF_MODE==1: # Right
+ v1.co[:]= v2.co
+ v1.co.x= -v1.co.x
+ v1.sel= 0
+ v2.sel= 0
- Window.DrawProgressBar(0.9, 'Mirror verts: Updating locations')
- # Now we have a list of the pairs we might use, lets find the best and do them first.
- # de-selecting as we go. so we can makke sure not to mess it up.
- mirror_pairs.sort(lambda a,b: cmp(a[0], b[0]))
-
- for dist, v1,v2 in mirror_pairs: # dist, neg, pos
- if v1.sel and v2.sel:
- if PREF_MODE==0: # Middle
- flipvec[:]= v2.co # positive
- flipvec.x= -flipvec.x # negatve
- v2.co[:]= v1.co[:]= (flipvec+v1.co)*0.5 # midway
- v2.co.x= -v2.co.x
- elif PREF_MODE==2: # Left
- v2.co[:]= v1.co
- v2.co.x= -v2.co.x
- elif PREF_MODE==1: # Right
- v1.co[:]= v2.co
- v1.co.x= -v1.co.x
- v1.sel= 0
- v2.sel= 0
+ #*Mirror Weights**********************************************************#
+ if PREF_MIRROR_WEIGHTS:
+
+ groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
+ mirror_pairs_l2r= [] # Stor a list of matches for these verts.
+ mirror_pairs_r2l= [] # Stor a list of matches for these verts.
+
+ # allign the negative with the positive.
+ flipvec= Mathutils.Vector()
+ len_neg_vts= float(len(neg_vts))
+
+ if PREF_MODE==0: # Middle
+ find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), (pos_vts, neg_vts, mirror_pairs_r2l))
+ elif PREF_MODE==1: # Left
+ find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), )
+ elif PREF_MODE==2: # Right
+ find_set= ((pos_vts, neg_vts, mirror_pairs_r2l), )
+ for vtls_A, vtls_B, pair_ls in ((neg_vts, pos_vts, mirror_pairs_l2r), (pos_vts, neg_vts, mirror_pairs_r2l)):
+ for i1, vA in enumerate(vtls_A):
+ best_len=1<<30
+ best_idx=-1
+
+ # Find the BEST match.
+ vA_co= vA.co
+ for i2, vB in enumerate(vtls_B):
+ # Enforce edge users.
+ if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]:
+ flipvec[:]= vB.co
+ flipvec.x= -flipvec.x
+ l= (vA_co-flipvec).length
+
+ if l<best_len:
+ best_len=l
+ best_idx=i2
+
+ if best_idx != -1:
+ pair_ls.append((vtls_A[i1].index, vtls_B[best_idx].index)) # neg, pos.
+
+ # Now we can merge the weights
+ if PREF_MODE==0: # Middle
+ newVWeightDict= [{} for i in xrange(len(me.verts))] # Have empty dicts just incase
+ for pair_ls in (mirror_pairs_l2r, mirror_pairs_r2l):
+ if PREF_FLIP_NAMES:
+ for i1, i2 in pair_ls:
+ flipWeight, groupNames= BPyMesh.dictWeightFlipGroups( vWeightDict[i2], groupNames, PREF_CREATE_FLIP_NAMES )
+ newVWeightDict[i1]= BPyMesh.dictWeightMerge([vWeightDict[i1], flipWeight] )
+ else:
+ for i1, i2 in pair_ls:
+ newVWeightDict[i1]= BPyMesh.dictWeightMerge([vWeightDict[i1], vWeightDict[i2]])
+
+ vWeightDict= newVWeightDict
+
+ elif PREF_MODE==1: # Left
+ if PREF_FLIP_NAMES:
+ for i1, i2 in mirror_pairs_l2r:
+ vWeightDict[i2], groupNames= BPyMesh.dictWeightFlipGroups(vWeightDict[i1], groupNames, PREF_CREATE_FLIP_NAMES)
+ else:
+ for i1, i2 in mirror_pairs_l2r:
+ vWeightDict[i2]= vWeightDict[i1] # Warning Multiple instances of the same data
+
+ elif PREF_MODE==2: # Right
+ if PREF_FLIP_NAMES:
+ for i1, i2 in mirror_pairs_r2l:
+ vWeightDict[i2], groupNames= BPyMesh.dictWeightFlipGroups(vWeightDict[i1], groupNames, PREF_CREATE_FLIP_NAMES)
+ else:
+ for i1, i2 in mirror_pairs_r2l:
+ vWeightDict[i2]= vWeightDict[i1]
+
+ BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
+
me.update()
if is_editmode: Window.EditMode(1)
@@ -116,30 +185,48 @@ def main():
except:
Draw.PupMenu('Error, select a mesh as your active object')
+ # Defaults
+ PREF_MIRROR_LOCATION= Draw.Create(1)
PREF_MAX_DIST= Draw.Create(0.2)
PREF_MODE= Draw.Create(0)
PREF_NOR_WEIGHT= Draw.Create(0.0)
PREF_SEL_ONLY= Draw.Create(1)
PREF_EDGE_USERS= Draw.Create(0)
+ # Weights
+ PREF_MIRROR_WEIGHTS= Draw.Create(0)
+ PREF_FLIP_NAMES= Draw.Create(1)
+ PREF_CREATE_FLIP_NAMES= Draw.Create(1)
pup_block = [\
('MaxDist:', PREF_MAX_DIST, 0.0, 1.0, 'Generate interpolated verts so closer vert weights can be copied.'),\
- ('Mode:', PREF_MODE, 0, 2, 'New Location (0:AverageL/R, 1:Left>Right 2:Right>Left)'),\
+ ('Mode:', PREF_MODE, 0, 2, 'New Location/Weight (0:AverageL/R, 1:Left>Right 2:Right>Left)'),\
('NorWeight:', PREF_NOR_WEIGHT, 0.0, 1.0, 'Generate interpolated verts so closer vert weights can be copied.'),\
('Sel Only', PREF_SEL_ONLY, 'Only mirror selected verts. Else try and mirror all'),\
('Edge Users', PREF_EDGE_USERS, 'Only match up verts that have the same number of edge users.'),\
+ 'Locations',\
+ ('Mirror Location', PREF_MIRROR_LOCATION, 'Mirror vertex locations.'),\
+ 'Weights',\
+ ('Mirror Weights', PREF_MIRROR_WEIGHTS, 'Mirror vertex locations.'),\
+ ('Flip Groups', PREF_FLIP_NAMES, 'Mirror flip names.'),\
+ ('New Flip Groups', PREF_CREATE_FLIP_NAMES, 'Make new groups for flipped names.'),\
]
if not Draw.PupBlock("Mirror mesh tool", pup_block):
return
+ PREF_MIRROR_LOCATION= PREF_MIRROR_LOCATION.val
PREF_MAX_DIST= PREF_MAX_DIST.val
PREF_MODE= PREF_MODE.val
PREF_NOR_WEIGHT= PREF_NOR_WEIGHT.val
PREF_SEL_ONLY= PREF_SEL_ONLY.val
PREF_EDGE_USERS= PREF_EDGE_USERS.val
+ # weights
+ PREF_MIRROR_WEIGHTS= PREF_MIRROR_WEIGHTS.val
+ PREF_FLIP_NAMES= PREF_FLIP_NAMES.val
+ PREF_CREATE_FLIP_NAMES= PREF_CREATE_FLIP_NAMES.val
+
t= sys.time()
- mesh_mirror(me, PREF_MAX_DIST, PREF_MODE, PREF_NOR_WEIGHT, PREF_SEL_ONLY, PREF_EDGE_USERS)
+ mesh_mirror(me, PREF_MIRROR_LOCATION, PREF_MAX_DIST, PREF_MODE, PREF_NOR_WEIGHT, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES)
print 'Mirror done in %.6f sec.' % (sys.time()-t)
if __name__ == '__main__':