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

mesh_boneweight_copy.py « scripts « release - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c08f2b9c892287557d22265fd0e7ea7276f6dc7d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!BPY
"""
Name: 'Bone Weight Copy'
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

def copy_bone_influences(_from, _to):
	ob_from, me_from, world_verts_from, from_groups=  _from
	ob_to, me_to, world_verts_to, dummy=  _to	
	del dummy
	
	def getSnapIdx(seek_vec, vecs):
		'''
		Returns the closest vec to snap_points
		'''
		
		# 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)
	
	add_ = Mesh.AssignModes.ADD
	
	for i, co in enumerate(world_verts_to):
		
		from_idx= getSnapIdx(co, world_verts_from)
		from_infs= me_from.getVertexInfluences(from_idx)
		
		for group, weight in from_infs:
			me_to.assignVertsToGroup(group, [i], weight, add_)
	
	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
	def worldvert(v):
		vec= Vector(v)
		vec.resize4D()
		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()
			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__':
	main()