the tip isnt used for a label anyway. added comments explaining whats going on. only effects clever numbuts internaly. type fixes for weightpaint_envelope_assign.py
		
			
				
	
	
		
			241 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!BPY
 | |
| 
 | |
| """
 | |
| Name: 'Envelope via Group Objects'
 | |
| Blender: 242
 | |
| Group: 'WeightPaint'
 | |
| Tooltip: 'Assigns weights to vertices via object envelopes'
 | |
| """
 | |
| 
 | |
| __author__ = ["Campbell Barton"]
 | |
| __url__ = ("blender", "blenderartist.org")
 | |
| __version__ = "0.1"
 | |
| 
 | |
| # ***** BEGIN GPL LICENSE BLOCK *****
 | |
| #
 | |
| # This program is free software; you can redistribute it and/or
 | |
| # modify it under the terms of the GNU General Public License
 | |
| # as published by the Free Software Foundation; either version 2
 | |
| # of the License, or (at your option) any later version.
 | |
| #
 | |
| # This program is distributed in the hope that it will be useful,
 | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| # GNU General Public License for more details.
 | |
| #
 | |
| # You should have received a copy of the GNU General Public License
 | |
| # along with this program; if not, write to the Free Software Foundation,
 | |
| # Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 | |
| #
 | |
| # ***** END GPL LICENCE BLOCK *****
 | |
| # --------------------------------------------------------------------------
 | |
| 
 | |
| def intersection_data(ob):
 | |
| 	'''
 | |
| 	Takes an object and returns raw triangles and tri bounds.
 | |
| 	returns a list of (v1,v2,v3, xmin, ymin, xmax, ymax)
 | |
| 	... to be used for ray intersection
 | |
| 	'''
 | |
| 	global tot_ymin, tot_xmin, tot_ymax, tot_xmax, tot_zmin, tot_zmax
 | |
| 	tot_zmin = tot_ymin = tot_xmin =  100000000.0
 | |
| 	tot_zmax = tot_ymax = tot_xmax = -100000000.0
 | |
| 	
 | |
| 	def tribounds_xy(v1,v2,v3):
 | |
| 		'''
 | |
| 		return the 3 vecs with bounds, also update tot_*min/max
 | |
| 		'''
 | |
| 		global tot_ymin, tot_xmin, tot_ymax, tot_xmax, tot_zmin, tot_zmax
 | |
| 		xmin = xmax = v1.x
 | |
| 		ymin = ymax = v1.y
 | |
| 		
 | |
| 		x = v2.x
 | |
| 		y = v2.y
 | |
| 		if x>xmax: xmax = x
 | |
| 		if y>ymax: ymax = y
 | |
| 		if x<xmin: xmin = x
 | |
| 		if y<ymin: ymin = y
 | |
| 		
 | |
| 			
 | |
| 		x = v3.x
 | |
| 		y = v3.y
 | |
| 		if x>xmax: xmax = x
 | |
| 		if y>ymax: ymax = y
 | |
| 		if x<xmin: xmin = x
 | |
| 		if y<ymin: ymin = y
 | |
| 		
 | |
| 		# totbounds
 | |
| 		for z in v1.z, v2.z, v3.z:
 | |
| 			if z>tot_zmax: tot_zmax = z
 | |
| 			if z<tot_zmin: tot_zmin = z
 | |
| 		
 | |
| 		# maintain global min/max for x and y
 | |
| 		if xmax>tot_xmax: tot_xmax = xmax
 | |
| 		if xmin<tot_xmin: tot_xmin = xmin
 | |
| 		
 | |
| 		if ymax>tot_ymax: tot_ymax = ymax
 | |
| 		if ymin<tot_ymin: tot_ymin = ymin
 | |
| 		
 | |
| 		return v1,v2,v3, xmin, ymin, xmax, ymax
 | |
| 	
 | |
| 	me = BPyMesh.getMeshFromObject(ob)
 | |
| 	
 | |
| 	if not me:
 | |
| 		return []
 | |
| 	
 | |
| 	me.transform(ob.matrixWorld)
 | |
| 	
 | |
| 	mesh_data = []
 | |
| 	
 | |
| 	# copy all the vectors so when the mesh is free'd we still have access.
 | |
| 	mesh_vert_cos= [v.co.copy() for v in me.verts]
 | |
| 	
 | |
| 	for f in me.faces:
 | |
| 		f_v = [mesh_vert_cos[v.index] for v in f]
 | |
| 		mesh_data.append( tribounds_xy(f_v[0], f_v[1], f_v[2]) )
 | |
| 		if len(f) == 4:
 | |
| 			mesh_data.append( tribounds_xy(f_v[0], f_v[2], f_v[3]) )
 | |
| 	
 | |
| 	me.verts = None # free some memory
 | |
| 	
 | |
| 	return ob.name, mesh_data, tot_xmin, tot_ymin, tot_zmin, tot_xmax, tot_ymax, tot_zmax
 | |
| 	
 | |
| from Blender import *
 | |
| ray = Mathutils.Vector(0,0,-1)
 | |
| def point_in_data(point, mesh_data_tuple):
 | |
| 	ob_name, mesh_data, tot_xmin, tot_ymin, tot_zmin, tot_xmax, tot_ymax, tot_zmax = mesh_data_tuple
 | |
| 	
 | |
| 	Intersect = Mathutils.Intersect
 | |
| 	x = point.x
 | |
| 	y = point.y
 | |
| 	z = point.z
 | |
| 	
 | |
| 	# Bouds check for all mesh data
 | |
| 	if not (\
 | |
| 	tot_zmin < z < tot_zmax and\
 | |
| 	tot_ymin < y < tot_ymax and\
 | |
| 	tot_xmin < x < tot_xmax\
 | |
| 	):
 | |
| 		return False
 | |
| 	
 | |
| 	def isect(tri_data):
 | |
| 		v1,v2,v3, xmin, ymin, xmax, ymax = tri_data
 | |
| 		if not (xmin < x < xmax and ymin < y < ymax):
 | |
| 			return False
 | |
| 		
 | |
| 		if v1.z < z and v2.z < z and v3.z < z:
 | |
| 			return False
 | |
| 		
 | |
| 		isect = Intersect(v1, v2,v3, ray, point, 1) # Clipped.
 | |
| 		if isect and isect.z > z: # This is so the ray only counts if its above the point. 
 | |
| 			return True
 | |
| 		else:
 | |
| 			return False
 | |
| 	
 | |
| 	# return len([None for tri_data in mesh_data if isect(tri_data)]) % 2
 | |
| 	return len( filter(isect, mesh_data) ) % 2
 | |
| 
 | |
| import BPyMesh
 | |
| def env_from_group(ob_act, grp, PREF_UPDATE_ACT=True):
 | |
| 	
 | |
| 	me = ob_act.getData(mesh=1)
 | |
| 	
 | |
| 	if PREF_UPDATE_ACT:
 | |
| 		act_group = me.activeGroup
 | |
| 		if act_group == None:
 | |
| 			Draw.PupMenu('Error%t|No active vertex group.')
 | |
| 			return
 | |
| 		
 | |
| 		try:
 | |
| 			ob = Object.Get(act_group)
 | |
| 		except:
 | |
| 			Draw.PupMenu('Error%t|No object named "'+ act_group +'".')
 | |
| 			return
 | |
| 		
 | |
| 		group_isect = intersection_data(ob)
 | |
| 		
 | |
| 	else:
 | |
| 		
 | |
| 		# get intersection data
 | |
| 		# group_isect_data = [intersection_data(ob) for ob in group.objects]
 | |
| 		group_isect_data = []
 | |
| 		for ob in grp.objects:
 | |
| 			if ob != ob_act: # in case we're in the group.
 | |
| 				gid = intersection_data(ob)
 | |
| 				if gid[1]: # has some triangles?
 | |
| 					group_isect_data.append( gid )
 | |
| 					
 | |
| 					# we only need 1 for the active group
 | |
| 					if PREF_UPDATE_ACT:
 | |
| 						break
 | |
| 	
 | |
| 		# sort by name
 | |
| 		group_isect_data.sort()
 | |
| 	
 | |
| 	if PREF_UPDATE_ACT:
 | |
| 		group_names, vweight_list = BPyMesh.meshWeight2List(me)
 | |
| 		group_index = group_names.index(act_group)
 | |
| 	else:
 | |
| 		group_names = [gid[0] for gid in group_isect_data]
 | |
| 		vweight_list= [[0.0]* len(group_names) for i in xrange(len(me.verts))]
 | |
| 	
 | |
| 	
 | |
| 	
 | |
| 	ob_act_mat = ob_act.matrixWorld
 | |
| 	for vi, v in enumerate(me.verts):
 | |
| 		# Get all the groups for this vert
 | |
| 		co = v.co * ob_act_mat
 | |
| 		
 | |
| 		if PREF_UPDATE_ACT:
 | |
| 			# only update existing
 | |
| 			if point_in_data(co, group_isect):	w = 1.0
 | |
| 			else:								w = 0.0
 | |
| 			vweight_list[vi][group_index] = w
 | |
| 			
 | |
| 		else:
 | |
| 			# generate new vgroup weights.
 | |
| 			for group_index, group_isect in enumerate(group_isect_data):
 | |
| 				if point_in_data(co, group_isect):
 | |
| 					vweight_list[vi][group_index] = 1.0
 | |
| 	
 | |
| 	BPyMesh.list2MeshWeight(me, group_names, vweight_list)
 | |
| 
 | |
| import BPyMessages
 | |
| def main():
 | |
| 	
 | |
| 	scn= Scene.GetCurrent()
 | |
| 	ob_act = scn.objects.active
 | |
| 	if not ob_act or ob_act.type != 'Mesh':
 | |
| 		BPyMessages.Error_NoMeshActive()
 | |
| 		return
 | |
| 	
 | |
| 	PREF_ENV_GROUPNAME= Draw.Create('')	
 | |
| 	PREF_UPDATE_ACT= Draw.Create(True)
 | |
| 	pup_block= [\
 | |
| 	('Update Active', PREF_UPDATE_ACT, 'Only apply envelope weights to the active group.'),\
 | |
| 	'...or initialize from group',\
 | |
| 	('GR:', PREF_ENV_GROUPNAME, 0, 21, 'The name of an existing groups, each member will be used as a weight envelope'),\
 | |
| 	]
 | |
| 	
 | |
| 	if not Draw.PupBlock('Envelope From Group...', pup_block):
 | |
| 		return
 | |
| 	
 | |
| 	PREF_UPDATE_ACT= PREF_UPDATE_ACT.val
 | |
| 	
 | |
| 	if not PREF_UPDATE_ACT:
 | |
| 		try:
 | |
| 			grp = Group.Get(PREF_ENV_GROUPNAME.val)
 | |
| 		except:	
 | |
| 			Draw.PupMenu('Error%t|Group "' + PREF_ENV_GROUPNAME.val + '" does not exist.')
 | |
| 			return
 | |
| 	else:
 | |
| 		grp = None
 | |
| 	
 | |
| 	Window.WaitCursor(1)
 | |
| 	t = sys.time()
 | |
| 	env_from_group(ob_act, grp, PREF_UPDATE_ACT)
 | |
| 	print 'assigned envelopes in:', sys.time() - t
 | |
| 	Window.WaitCursor(0)
 | |
| 
 | |
| if __name__ == '__main__':
 | |
| 	main()
 |