2006-04-01 15:32:58 +00:00
|
|
|
#!BPY
|
|
|
|
"""
|
|
|
|
Name: 'Bone Weight Copy'
|
|
|
|
Blender: 241
|
|
|
|
Group: 'Object'
|
|
|
|
Tooltip: 'Copy Bone Weights from 1 weighted mesh, to other unweighted meshes.'
|
|
|
|
"""
|
2006-04-02 20:59:02 +00:00
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
import Blender
|
|
|
|
from Blender import Armature, Object, Mathutils, Window, Mesh
|
|
|
|
Vector= Mathutils.Vector
|
2006-04-21 09:41:58 +00:00
|
|
|
SMALL_NUM= 0.000001
|
2006-04-13 04:00:32 +00:00
|
|
|
def copy_bone_influences(_from, _to, PREF_SEL_ONLY, PREF_NO_XCROSS):
|
2006-04-01 15:32:58 +00:00
|
|
|
ob_from, me_from, world_verts_from, from_groups= _from
|
|
|
|
ob_to, me_to, world_verts_to, dummy= _to
|
|
|
|
del dummy
|
|
|
|
|
2006-04-02 20:59:02 +00:00
|
|
|
def getSnapIdx(seek_vec, vecs):
|
2006-04-01 15:32:58 +00:00
|
|
|
'''
|
|
|
|
Returns the closest vec to snap_points
|
|
|
|
'''
|
|
|
|
|
2006-04-02 20:59:02 +00:00
|
|
|
# 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
|
2006-04-03 20:15:24 +00:00
|
|
|
if z >= seek_vec_z:
|
2006-04-02 20:59:02 +00:00
|
|
|
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
|
|
|
|
|
2006-04-03 21:48:18 +00:00
|
|
|
# Set uselo/useup. This means we can keep seeking up/down.
|
|
|
|
if upidx >= len_vecs: useup= False
|
|
|
|
else: useup= True
|
|
|
|
|
|
|
|
if loidx < 0: uselo= False
|
|
|
|
else: uselo= True
|
2006-04-02 20:59:02 +00:00
|
|
|
|
|
|
|
# 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]
|
2006-04-21 09:41:58 +00:00
|
|
|
if (not PREF_NO_XCROSS) or ((v.x >= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing
|
2006-04-13 04:00:32 +00:00
|
|
|
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
|
2006-04-02 20:59:02 +00:00
|
|
|
upidx+=1
|
|
|
|
|
|
|
|
if uselo:
|
2006-04-13 04:00:32 +00:00
|
|
|
|
2006-04-02 20:59:02 +00:00
|
|
|
if loidx == 0:
|
|
|
|
uselo= False
|
|
|
|
else:
|
|
|
|
i,v= vecs[loidx]
|
2006-04-21 09:41:58 +00:00
|
|
|
if (not PREF_NO_XCROSS) or ((v.x >= -SMALL_NUM and seek_vec_x >= -SMALL_NUM) or (v.x <= SMALL_NUM and seek_vec_x <= SMALL_NUM)): # enfoce xcrossing
|
2006-04-13 04:00:32 +00:00
|
|
|
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
|
2006-04-02 20:59:02 +00:00
|
|
|
loidx-=1
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
return close_idx
|
2006-04-05 07:10:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
to_groups= me_to.getVertGroupNames() # if not PREF_SEL_ONLY will always be []
|
2006-04-01 15:32:58 +00:00
|
|
|
from_groups= me_from.getVertGroupNames()
|
2006-04-05 07:10:30 +00:00
|
|
|
|
|
|
|
if PREF_SEL_ONLY: # remove selected verts from all groups.
|
|
|
|
vsel= [v.index for v in me_to.verts if v.sel]
|
|
|
|
for group in to_groups:
|
|
|
|
me_to.removeVertsFromGroup(group, vsel)
|
|
|
|
else: # Add all groups.
|
|
|
|
for group in from_groups:
|
|
|
|
me_to.addVertGroup(group)
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
|
|
|
|
add_ = Mesh.AssignModes.ADD
|
|
|
|
|
|
|
|
for i, co in enumerate(world_verts_to):
|
2006-04-05 07:10:30 +00:00
|
|
|
if (not PREF_SEL_ONLY) or (PREF_SEL_ONLY and me_to.verts[i].sel):
|
2006-04-13 04:00:32 +00:00
|
|
|
|
|
|
|
Window.DrawProgressBar(0.99 * (i/float(len(world_verts_to))), 'Copy "%s" -> "%s" ' % (ob_from.name, ob_to.name))
|
|
|
|
|
2006-04-05 07:10:30 +00:00
|
|
|
from_idx= getSnapIdx(co, world_verts_from)
|
|
|
|
from_infs= me_from.getVertexInfluences(from_idx)
|
|
|
|
|
|
|
|
for group, weight in from_infs:
|
|
|
|
|
|
|
|
# Add where needed.
|
|
|
|
if PREF_SEL_ONLY and group not in to_groups:
|
|
|
|
me_to.addVertGroup(group)
|
|
|
|
to_groups.append(group)
|
|
|
|
|
|
|
|
me_to.assignVertsToGroup(group, [i], weight, add_)
|
2006-04-01 15:32:58 +00:00
|
|
|
|
|
|
|
me_to.update()
|
|
|
|
|
2006-04-02 20:59:02 +00:00
|
|
|
# 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
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
|
|
|
|
def worldspace_verts(me, ob):
|
|
|
|
mat= ob.matrixWorld
|
|
|
|
def worldvert(v):
|
|
|
|
vec= Vector(v)
|
|
|
|
vec.resize4D()
|
|
|
|
vec= vec*mat
|
|
|
|
vec.resize3D()
|
|
|
|
return vec
|
|
|
|
return [ worldvert(v.co) for v in me.verts ]
|
2006-04-02 20:59:02 +00:00
|
|
|
|
2006-04-05 07:10:30 +00:00
|
|
|
def subdivMesh(me, subdivs):
|
|
|
|
oldmode = Mesh.Mode()
|
|
|
|
Mesh.Mode(Mesh.SelectModes['FACE'])
|
|
|
|
for f in me.faces: f.sel = 1
|
|
|
|
|
|
|
|
for i in xrange(subdivs):
|
|
|
|
me.subdivide(0)
|
|
|
|
Mesh.Mode(oldmode)
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
|
|
|
|
def main():
|
2006-04-02 20:59:02 +00:00
|
|
|
print '\nStarting BoneWeight Copy...'
|
2006-04-05 07:10:30 +00:00
|
|
|
scn= Blender.Scene.GetCurrent()
|
|
|
|
contextSel= Object.GetSelected()
|
|
|
|
|
|
|
|
|
|
|
|
PREF_QUALITY= Blender.Draw.Create(3)
|
2006-04-13 04:00:32 +00:00
|
|
|
PREF_NO_XCROSS= Blender.Draw.Create(0)
|
2006-04-05 07:10:30 +00:00
|
|
|
PREF_SEL_ONLY= Blender.Draw.Create(0)
|
2006-04-13 04:00:32 +00:00
|
|
|
|
2006-04-05 07:10:30 +00:00
|
|
|
pup_block = [\
|
|
|
|
('Quality:', PREF_QUALITY, 0, 4, 'Generate interpolated verts so closer vert weights can be copied.'),\
|
2006-04-13 04:00:32 +00:00
|
|
|
('No X Crossing', PREF_NO_XCROSS, 'Do not snap accross the zero X axis'),\
|
2006-04-05 07:10:30 +00:00
|
|
|
('Copy to Selected', PREF_SEL_ONLY, 'Over wright vertex weights to selected verts on the target mesh. (use active ob as source)'),\
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
if not Blender.Draw.PupBlock("Copy Weights for %i Meshs" % len(contextSel), pup_block):
|
|
|
|
return
|
|
|
|
|
|
|
|
PREF_SEL_ONLY= PREF_SEL_ONLY.val
|
2006-04-13 04:00:32 +00:00
|
|
|
PREF_NO_XCROSS= PREF_NO_XCROSS.val
|
2006-04-05 07:10:30 +00:00
|
|
|
quality= PREF_QUALITY.val
|
|
|
|
|
|
|
|
act_ob= scn.getActiveObject()
|
|
|
|
if PREF_SEL_ONLY and act_ob==None:
|
|
|
|
Blender.Draw.PupMenu('Error%t|When dealing with 2 or more meshes with vgroups|There must be an active object|to be used as a source|aborting.')
|
|
|
|
return
|
|
|
|
|
|
|
|
'''
|
|
|
|
quality= Blender.Draw.PupIntInput('Quality: ', 2, 0, 4)
|
|
|
|
if quality==None:
|
|
|
|
return
|
|
|
|
'''
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
sel=[]
|
|
|
|
from_data= None
|
2006-04-05 07:10:30 +00:00
|
|
|
act_ob= scn.getActiveObject()
|
|
|
|
for ob in contextSel:
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
if ob.getType()=='Mesh':
|
|
|
|
me= ob.getData(mesh=1)
|
|
|
|
groups= me.getVertGroupNames()
|
2006-04-05 07:10:30 +00:00
|
|
|
|
|
|
|
# If this is the only mesh with a group OR if its one of many, but its active.
|
|
|
|
if groups and ((ob==act_ob and PREF_SEL_ONLY) or (not PREF_SEL_ONLY)):
|
2006-04-01 15:32:58 +00:00
|
|
|
if from_data:
|
|
|
|
Blender.Draw.PupMenu('More then 1 mesh has vertex weights, only select 1 mesh with weights. aborting.')
|
|
|
|
return
|
|
|
|
else:
|
2006-04-02 20:59:02 +00:00
|
|
|
# This uses worldspace_verts_idx which gets (idx,co) pairs, then zsorts.
|
2006-04-05 07:10:30 +00:00
|
|
|
if quality:
|
|
|
|
for _ob in contextSel:
|
|
|
|
_ob.sel=0
|
|
|
|
ob.sel=1
|
|
|
|
Object.Duplicate(mesh=1)
|
|
|
|
ob= scn.getActiveObject()
|
|
|
|
me= ob.getData(mesh=1)
|
|
|
|
# groups will be the same
|
|
|
|
print '\tGenerating higher %ix quality weights.' % quality
|
|
|
|
subdivMesh(me, quality)
|
|
|
|
scn.unlink(ob)
|
|
|
|
from_data= (ob, me, worldspace_verts_idx(me, ob), groups)
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
else:
|
2006-04-02 20:59:02 +00:00
|
|
|
data= (ob, me, worldspace_verts(me, ob), groups)
|
2006-04-01 15:32:58 +00:00
|
|
|
sel.append(data)
|
2006-04-05 07:10:30 +00:00
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
if not sel or from_data==None:
|
|
|
|
Blender.Draw.PupMenu('Select 2 or more mesh objects, aborting.')
|
2006-04-05 07:10:30 +00:00
|
|
|
if not sel and quality:
|
|
|
|
from_data[1].verts= None
|
2006-04-01 15:32:58 +00:00
|
|
|
return
|
2006-04-02 20:59:02 +00:00
|
|
|
t= Blender.sys.time()
|
2006-04-01 15:32:58 +00:00
|
|
|
Window.WaitCursor(1)
|
2006-04-05 07:10:30 +00:00
|
|
|
|
|
|
|
|
2006-04-01 15:32:58 +00:00
|
|
|
# Now do the copy.
|
2006-04-02 20:59:02 +00:00
|
|
|
print '\tCopying from "%s" to %i other meshe(s).' % (from_data[0].name, len(sel))
|
2006-04-01 15:32:58 +00:00
|
|
|
for data in sel:
|
2006-04-13 04:00:32 +00:00
|
|
|
copy_bone_influences(from_data, data, PREF_SEL_ONLY, PREF_NO_XCROSS)
|
2006-04-05 07:10:30 +00:00
|
|
|
|
|
|
|
# We cant unlink the mesh, but at least remove its data.
|
|
|
|
if quality:
|
|
|
|
from_data[1].verts= None
|
|
|
|
|
2006-04-02 20:59:02 +00:00
|
|
|
print 'Copy Compleate in %.6f sec' % (Blender.sys.time()-t)
|
2006-04-13 04:00:32 +00:00
|
|
|
Window.DrawProgressBar(1.0, '')
|
2006-04-01 15:32:58 +00:00
|
|
|
Window.WaitCursor(0)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|