Sped up quite a bit using zsorting and fast index guessing. so verts can find the closest vert in the other mesh.

from 37.3sec to 8.65 sec on the test I used (human with 24 bones) - 24k verts on the source mesh.
This commit is contained in:
Campbell Barton 2006-04-02 20:59:02 +00:00
parent 15a78cb9c8
commit 756bad72c4

@ -5,6 +5,10 @@ Blender: 241
Group: 'Object' Group: 'Object'
Tooltip: 'Copy Bone Weights from 1 weighted mesh, to other unweighted meshes.' Tooltip: 'Copy Bone Weights from 1 weighted mesh, to other unweighted meshes.'
""" """
# 37.314122 sec
# 8.9 sec sec
import Blender import Blender
from Blender import Armature, Object, Mathutils, Window, Mesh from Blender import Armature, Object, Mathutils, Window, Mesh
Vector= Mathutils.Vector Vector= Mathutils.Vector
@ -14,26 +18,88 @@ def copy_bone_influences(_from, _to):
ob_to, me_to, world_verts_to, dummy= _to ob_to, me_to, world_verts_to, dummy= _to
del dummy del dummy
def getSnapIdx(vec, vecs): def getSnapIdx(seek_vec, vecs):
''' '''
Returns the closest vec to snap_points Returns the closest vec to snap_points
''' '''
close_dist= 1<<30
close_idx= None
x,y,z= tuple(vec) # First seek the closest Z axis vert idx/v
for i, v in enumerate(vecs): seek_vec_x,seek_vec_y,seek_vec_z= tuple(seek_vec)
# quick length cmp before a full length comparison.
if\ from_vec_idx= 0
abs(x-v[0]) < close_dist and\
abs(y-v[1]) < close_dist and\ len_vecs= len(vecs)
abs(z-v[2]) < close_dist:
l= (v-vec).length upidx= len_vecs-1
if l<close_dist: loidx= 0
close_dist= l
close_idx= i _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 return close_idx
from_groups= me_from.getVertGroupNames() from_groups= me_from.getVertGroupNames()
for group in from_groups: for group in from_groups:
me_to.addVertGroup(group) me_to.addVertGroup(group)
@ -50,6 +116,21 @@ def copy_bone_influences(_from, _to):
me_to.update() 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): def worldspace_verts(me, ob):
mat= ob.matrixWorld mat= ob.matrixWorld
@ -59,35 +140,39 @@ def worldspace_verts(me, ob):
vec= vec*mat vec= vec*mat
vec.resize3D() vec.resize3D()
return vec return vec
return [ worldvert(v.co) for v in me.verts ] return [ worldvert(v.co) for v in me.verts ]
def main(): def main():
print '\nStarting BoneWeight Copy...'
sel=[] sel=[]
from_data= None from_data= None
for ob in Object.GetSelected(): for ob in Object.GetSelected():
if ob.getType()=='Mesh': if ob.getType()=='Mesh':
me= ob.getData(mesh=1) me= ob.getData(mesh=1)
groups= me.getVertGroupNames() groups= me.getVertGroupNames()
data= (ob, me, worldspace_verts(me, ob), groups)
if groups: if groups:
if from_data: if from_data:
Blender.Draw.PupMenu('More then 1 mesh has vertex weights, only select 1 mesh with weights. aborting.') Blender.Draw.PupMenu('More then 1 mesh has vertex weights, only select 1 mesh with weights. aborting.')
return return
else: 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 from_data= data
else: else:
data= (ob, me, worldspace_verts(me, ob), groups)
sel.append(data) sel.append(data)
if not sel or from_data==None: if not sel or from_data==None:
Blender.Draw.PupMenu('Select 2 or more mesh objects, aborting.') Blender.Draw.PupMenu('Select 2 or more mesh objects, aborting.')
return return
t= Blender.sys.time()
Window.WaitCursor(1) Window.WaitCursor(1)
# Now do the copy. # Now do the copy.
print '\tCopying from "%s" to %i other meshe(s).' % (from_data[0].name, len(sel))
for data in sel: for data in sel:
copy_bone_influences(from_data, data) copy_bone_influences(from_data, data)
print 'Copy Compleate in %.6f sec' % (Blender.sys.time()-t)
Window.WaitCursor(0) Window.WaitCursor(0)
if __name__ == '__main__': if __name__ == '__main__':