diff options
-rwxr-xr-x | release/scripts/mesh_boneweight_copy.py | 123 |
1 files changed, 104 insertions, 19 deletions
diff --git a/release/scripts/mesh_boneweight_copy.py b/release/scripts/mesh_boneweight_copy.py index e82769a3e04..c08f2b9c892 100755 --- a/release/scripts/mesh_boneweight_copy.py +++ b/release/scripts/mesh_boneweight_copy.py @@ -5,6 +5,10 @@ Blender: 241 Group: 'Object' Tooltip: 'Copy Bone Weights from 1 weighted mesh, to other unweighted meshes.' """ +# 37.314122 sec +# 8.9 sec sec + + import Blender from Blender import Armature, Object, Mathutils, Window, Mesh Vector= Mathutils.Vector @@ -14,26 +18,88 @@ def copy_bone_influences(_from, _to): ob_to, me_to, world_verts_to, dummy= _to del dummy - def getSnapIdx(vec, vecs): + def getSnapIdx(seek_vec, vecs): ''' Returns the closest vec to snap_points ''' - close_dist= 1<<30 - close_idx= None - x,y,z= tuple(vec) - for i, v in enumerate(vecs): - # quick length cmp before a full length comparison. - if\ - abs(x-v[0]) < close_dist and\ - abs(y-v[1]) < close_dist and\ - abs(z-v[2]) < close_dist: - l= (v-vec).length - if l<close_dist: - close_dist= l - close_idx= i + # First seek the closest Z axis vert idx/v + seek_vec_x,seek_vec_y,seek_vec_z= tuple(seek_vec) + + from_vec_idx= 0 + + len_vecs= len(vecs) + + upidx= len_vecs-1 + loidx= 0 + + _range=upidx-loidx + # Guess the right index, keep re-adjusting the high and the low. + while _range > 3: + half= _range/2 + z= vecs[upidx-half][1].z + if z > seek_vec_z: + upidx= upidx-half + elif z < seek_vec_z: + loidx= loidx+half + + _range=upidx-loidx + + from_vec_idx= loidx + + # Seek the rest of the way. should only need to seek 2 or 3 items at the most. + while from_vec_idx < len_vecs and vecs[from_vec_idx][1].z < seek_vec_z: + from_vec_idx+=1 + + # Clamp if we overstepped. + if from_vec_idx >= len_vecs: + from_vec_idx-=1 + + close_dist= (vecs[from_vec_idx][1]-seek_vec).length + close_idx= vecs[from_vec_idx][0] + + upidx= from_vec_idx+1 + loidx= from_vec_idx-1 + + uselo=useup= True # This means we can keep seeking up/down. + + # Seek up/down to find the closest v to seek vec. + while uselo or useup: + if useup: + + if upidx >= len_vecs: + useup= False + else: + i,v= vecs[upidx] + if v.z-seek_vec_z > close_dist: + # the verticle distance is greater then the best distance sofar. we can stop looking up. + useup= False + elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: + # This is in the limit measure it. + l= (seek_vec-v).length + if l<close_dist: + close_dist= l + close_idx= i + upidx+=1 + + if uselo: + if loidx == 0: + uselo= False + else: + i,v= vecs[loidx] + if seek_vec_z-v.z > close_dist: + # the verticle distance is greater then the best distance sofar. we can stop looking up. + uselo= False + elif abs(seek_vec_y-v.y) < close_dist and abs(seek_vec_x-v.x) < close_dist: + # This is in the limit measure it. + l= (seek_vec-v).length + if l<close_dist: + close_dist= l + close_idx= i + loidx-=1 + return close_idx - + from_groups= me_from.getVertGroupNames() for group in from_groups: me_to.addVertGroup(group) @@ -50,6 +116,21 @@ def copy_bone_influences(_from, _to): me_to.update() +# ZSORT return (i/co) tuples, used for fast seeking of the snapvert. +def worldspace_verts_idx(me, ob): + mat= ob.matrixWorld + def worldvert(v): + vec= Vector(v) + vec.resize4D() + vec= vec*mat + vec.resize3D() + return vec + verts_zsort= [ (i, worldvert(v.co)) for i, v in enumerate(me.verts) ] + + # Sorts along the Z Axis so we can optimize the getsnap. + verts_zsort.sort(lambda a,b: cmp(a[1].z, b[1].z,)) + return verts_zsort + def worldspace_verts(me, ob): mat= ob.matrixWorld @@ -59,35 +140,39 @@ def worldspace_verts(me, ob): vec= vec*mat vec.resize3D() return vec - return [ worldvert(v.co) for v in me.verts ] + def main(): + print '\nStarting BoneWeight Copy...' sel=[] from_data= None for ob in Object.GetSelected(): if ob.getType()=='Mesh': me= ob.getData(mesh=1) groups= me.getVertGroupNames() - - data= (ob, me, worldspace_verts(me, ob), groups) if groups: if from_data: Blender.Draw.PupMenu('More then 1 mesh has vertex weights, only select 1 mesh with weights. aborting.') return else: + # This uses worldspace_verts_idx which gets (idx,co) pairs, then zsorts. + data= (ob, me, worldspace_verts_idx(me, ob), groups) from_data= data else: + data= (ob, me, worldspace_verts(me, ob), groups) sel.append(data) if not sel or from_data==None: Blender.Draw.PupMenu('Select 2 or more mesh objects, aborting.') return - + t= Blender.sys.time() Window.WaitCursor(1) # Now do the copy. + print '\tCopying from "%s" to %i other meshe(s).' % (from_data[0].name, len(sel)) for data in sel: copy_bone_influences(from_data, data) + print 'Copy Compleate in %.6f sec' % (Blender.sys.time()-t) Window.WaitCursor(0) if __name__ == '__main__': |