Пример #1
0
def copy_act_vgroup(me, PREF_NAME, PREF_SEL_ONLY):
    Window.WaitCursor(1)
    groupNames, vWeightDict = BPyMesh.meshWeight2Dict(me)
    act_group = me.activeGroup

    if not PREF_SEL_ONLY:
        for wd in vWeightDict:
            try:
                wd[PREF_NAME] = wd[act_group]
            except:
                pass
    else:
        # Selected faces only
        verts = {}  # should use set
        for f in me.faces:
            if f.sel:
                for v in f:
                    verts[v.index] = None

        for i in verts.iterkeys():
            wd = vWeightDict[i]
            try:
                wd[PREF_NAME] = wd[act_group]
            except:
                pass

    groupNames.append(PREF_NAME)
    # Copy weights back to the mesh.
    BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
    Window.WaitCursor(0)
Пример #2
0
def copy_act_vgroup(me, PREF_NAME, PREF_SEL_ONLY):
	Window.WaitCursor(1)
	groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
	act_group= me.activeGroup
	
	if not PREF_SEL_ONLY:
		for wd in vWeightDict:
			try:		wd[PREF_NAME] = wd[act_group]
			except:		pass
	else:
		# Selected faces only
		verts = {} # should use set
		for f in me.faces:
			if f.sel:
				for v in f:
					verts[v.index] = None
		
		for i in verts.iterkeys():
			wd = vWeightDict[i]
			try:		wd[PREF_NAME] = wd[act_group]
			except:		pass
		
		
	
	groupNames.append(PREF_NAME)
	# Copy weights back to the mesh.
	BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
	Window.WaitCursor(0)
Пример #3
0
def actWeightNormalize(me, PREF_MODE, PREF_MAX_DIST, PREF_STRENGTH, PREF_ITERATIONS):
	Window.WaitCursor(1)
	groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
	act_group= me.activeGroup
	
	# Start with assumed zero weights
	orig_vert_weights= [0.0] * len(vWeightDict) # Will be directly assigned to orig_vert_weights
	
	
	# fill in the zeros with real weights.
	for i, wd in enumerate(vWeightDict):
		try:
			orig_vert_weights[i]= wd[act_group]
		except:
			pass
	
	new_vert_weights= list(orig_vert_weights)
	
	for dummy in xrange(PREF_ITERATIONS):
		# Minimize or maximize the weights. connection based.
		
		if PREF_MODE==0: # Grow
			op= max
		else: # Shrink
			op= min
		
		for ed in me.edges:
			if not PREF_MAX_DIST or ed.length < PREF_MAX_DIST:
			
				i1= ed.v1.index
				i2= ed.v2.index
				new_weight= op(orig_vert_weights[i1], orig_vert_weights[i2])
				
				if PREF_STRENGTH==1.0: # do a full copy
					new_vert_weights[i1]= op(new_weight, new_vert_weights[i1])
					new_vert_weights[i2]= op(new_weight, new_vert_weights[i2])
					
				else: # Do a faded copy
					new_vert_weights[i1]= op(new_weight, new_vert_weights[i1])
					new_vert_weights[i2]= op(new_weight, new_vert_weights[i2])
					
					# Face the copy with the original (orig is updated per iteration)
					new_vert_weights[i1]= (new_vert_weights[i1]*PREF_STRENGTH) + (orig_vert_weights[i1]*(1-PREF_STRENGTH))
					new_vert_weights[i2]= (new_vert_weights[i2]*PREF_STRENGTH) + (orig_vert_weights[i2]*(1-PREF_STRENGTH))
		
		
		for i, wd in enumerate(vWeightDict):
			new_weight= new_vert_weights[i]
			if new_weight != orig_vert_weights[i]:
				wd[act_group]= new_weight
		
		if dummy+1 != PREF_ITERATIONS: # dont copy the list on the last round.
			orig_vert_weights= list(new_vert_weights)
		
		
	# Copy weights back to the mesh.
	BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
	Window.WaitCursor(0)
Пример #4
0
def actWeightNormalize(me, PREF_MODE, PREF_MAX_DIST, PREF_STRENGTH, PREF_ITERATIONS):
	Window.WaitCursor(1)
	groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
	act_group= me.activeGroup
	
	# Start with assumed zero weights
	orig_vert_weights= [0.0] * len(vWeightDict) # Will be directly assigned to orig_vert_weights
	
	
	# fill in the zeros with real weights.
	for i, wd in enumerate(vWeightDict):
		try:
			orig_vert_weights[i]= wd[act_group]
		except:
			pass
	
	new_vert_weights= list(orig_vert_weights)
	
	for dummy in xrange(PREF_ITERATIONS):
		# Minimize or maximize the weights. connection based.
		
		if PREF_MODE==0: # Grow
			op= max
		else: # Shrink
			op= min
		
		for ed in me.edges:
			if not PREF_MAX_DIST or ed.length < PREF_MAX_DIST:
			
				i1= ed.v1.index
				i2= ed.v2.index
				new_weight= op(orig_vert_weights[i1], orig_vert_weights[i2])
				
				if PREF_STRENGTH==1.0: # do a full copy
					new_vert_weights[i1]= op(new_weight, new_vert_weights[i1])
					new_vert_weights[i2]= op(new_weight, new_vert_weights[i2])
					
				else: # Do a faded copy
					new_vert_weights[i1]= op(new_weight, new_vert_weights[i1])
					new_vert_weights[i2]= op(new_weight, new_vert_weights[i2])
					
					# Face the copy with the original (orig is updated per iteration)
					new_vert_weights[i1]= (new_vert_weights[i1]*PREF_STRENGTH) + (orig_vert_weights[i1]*(1-PREF_STRENGTH))
					new_vert_weights[i2]= (new_vert_weights[i2]*PREF_STRENGTH) + (orig_vert_weights[i2]*(1-PREF_STRENGTH))
		
		
		for i, wd in enumerate(vWeightDict):
			new_weight= new_vert_weights[i]
			if new_weight != orig_vert_weights[i]:
				wd[act_group]= new_weight
		
		if dummy+1 != PREF_ITERATIONS: # dont copy the list on the last round.
			orig_vert_weights= list(new_vert_weights)
		
		
	# Copy weights back to the mesh.
	BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
	Window.WaitCursor(0)
Пример #5
0
def weightClean(me, PREF_THRESH, PREF_KEEP_SINGLE, PREF_OTHER_GROUPS):
	
	groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
	act_group= me.activeGroup
	
	rem_count = 0
	
	if PREF_OTHER_GROUPS:
		for wd in vWeightDict:
			l = len(wd)
			if not PREF_KEEP_SINGLE or l > 1:
				# cant use iteritems because the dict is having items removed
				for group in wd.keys():
					w= wd[group]
					if w <= PREF_THRESH:
						# small weight, remove.
						del wd[group]
						rem_count +=1
						l-=1
					
					if PREF_KEEP_SINGLE and l == 1:
						break
	
	else:
		for wd in vWeightDict:
			if not PREF_KEEP_SINGLE or len(wd) > 1:
				try:
					w= wd[act_group]
					if w <= PREF_THRESH:
						# small weight, remove.
						del wd[act_group]
						rem_count +=1
				except:
					pass
	
	# Copy weights back to the mesh.
	BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
	return rem_count
Пример #6
0
def weightClean(me, PREF_THRESH, PREF_KEEP_SINGLE, PREF_OTHER_GROUPS):

    groupNames, vWeightDict = BPyMesh.meshWeight2Dict(me)
    act_group = me.activeGroup

    rem_count = 0

    if PREF_OTHER_GROUPS:
        for wd in vWeightDict:
            l = len(wd)
            if not PREF_KEEP_SINGLE or l > 1:
                # cant use iteritems because the dict is having items removed
                for group in wd.keys():
                    w = wd[group]
                    if w <= PREF_THRESH:
                        # small weight, remove.
                        del wd[group]
                        rem_count += 1
                        l -= 1

                    if PREF_KEEP_SINGLE and l == 1:
                        break

    else:
        for wd in vWeightDict:
            if not PREF_KEEP_SINGLE or len(wd) > 1:
                try:
                    w = wd[act_group]
                    if w <= PREF_THRESH:
                        # small weight, remove.
                        del wd[act_group]
                        rem_count += 1
                except:
                    pass

    # Copy weights back to the mesh.
    BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
    return rem_count
Пример #7
0
def vertexGradientPick(ob, MODE):
    #MODE 0 == VWEIGHT,  1 == VCOL

    me = ob.getData(mesh=1)
    if not me.faceUV: me.faceUV = True

    Window.DrawProgressBar(0.0, '')

    mousedown_wait()

    if MODE == 0:
        act_group = me.activeGroup
        if act_group == None:
            mousedown_wait()
            Draw.PupMenu('Error, mesh has no active group.')
            return

    # Loop until click
    Window.DrawProgressBar(0.25, 'Click to set gradient start')
    mouseup()

    obmat = ob.matrixWorld
    screen_x, screen_y = Window.GetMouseCoords()
    mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat)
    if not mouseInView or not OriginA:
        return

    # get the mouse weight

    if MODE == 0:
        pickValA = BPyMesh.pickMeshGroupWeight(me, act_group, OriginA,
                                               DirectionA)
    if MODE == 1:
        pickValA = BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA)

    Window.DrawProgressBar(0.75, 'Click to set gradient end')
    mouseup()

    TOALPHA = Window.GetKeyQualifiers() & Window.Qual.SHIFT

    screen_x, screen_y = Window.GetMouseCoords()
    mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat)
    if not mouseInView or not OriginB:
        return

    if not TOALPHA:  # Only get a second opaque value if we are not blending to alpha
        if MODE == 0:
            pickValB = BPyMesh.pickMeshGroupWeight(me, act_group, OriginB,
                                                   DirectionB)
        else:
            pickValB = BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB)
    else:
        if MODE == 0: pickValB = 0.0
        else: pickValB = [0.0, 0.0, 0.0]  # Dummy value

    # Neither points touched a face
    if pickValA == pickValB == None:
        return

    # clicking on 1 non face is fine. just set the weight to 0.0
    if pickValA == None:
        pickValA = 0.0

        # swap A/B
        OriginA, OriginB = OriginB, OriginA
        DirectionA, DirectionB = DirectionB, DirectionA
        pickValA, pickValB = pickValA, pickValB

        TOALPHA = True

    if pickValB == None:
        pickValB = 0.0
        TOALPHA = True

    # set up 2 lines so we can measure their distances and calc the gradient

    # make a line 90d to the grad in screenspace.
    if (OriginA - OriginB
        ).length <= eps:  # Persp view. same origin different direction
        cross_grad = DirectionA.cross(DirectionB)
        ORTHO = False

    else:  # Ortho - Same direction, different origin
        cross_grad = DirectionA.cross(OriginA - OriginB)
        ORTHO = True

    cross_grad.normalize()
    cross_grad = cross_grad * 100

    lineA = (OriginA, OriginA + (DirectionA * 100))
    lineB = (OriginB, OriginB + (DirectionB * 100))

    if not ORTHO:
        line_angle = AngleBetweenVecs(lineA[1], lineB[1]) / 2
        line_mid = (lineA[1] + lineB[1]) * 0.5

    VSEL = [False] * (len(me.verts))

    # Get the selected faces and apply the selection to the verts.
    for f in me.faces:
        if f.sel:
            for v in f.v:
                VSEL[v.index] = True
    groupNames, vWeightDict = BPyMesh.meshWeight2Dict(me)

    def grad_weight_from_co(v):
        '''
		Takes a vert and retuens its gradient radio between A and B
		'''

        if not VSEL[v.index]:  # Not bart of a selected face?
            return None, None

        v_co = v.co
        # make a line 90d to the 2 lines the user clicked.
        vert_line = (v_co - cross_grad, v_co + cross_grad)

        xA = LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1])
        xB = LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1])

        if not xA or not xB:  # Should never happen but support it anyhow
            return None, None

        wA = (xA[0] - xA[1]).length
        wB = (xB[0] - xB[1]).length

        wTot = wA + wB
        if not wTot:  # lines are on the same point.
            return None, None
        '''
		Get the length of the line between both intersections on the 
		2x view lines.
		if the dist between  lineA+VertLine and lineB+VertLine is 
		greater then the lenth between lineA and lineB intersection points, it means
		that the verts are not inbetween the 2 lines.
		'''
        lineAB_length = (xA[1] - xB[1]).length

        # normalzie
        wA = wA / wTot
        wB = wB / wTot

        if ORTHO:  # Con only use line length method with parelelle lines
            if wTot > lineAB_length + eps:
                # vert is outside the range on 1 side. see what side of the grad
                if wA > wB: wA, wB = 1.0, 0.0
                else: wA, wB = 0.0, 1.0
        else:
            # PERSP, lineA[0] is the same origin as lineB[0]

            # Either xA[0] or xB[0]  can be used instead of a possible x_mid between the 2
            # as long as the point is inbetween lineA and lineB it dosent matter.
            a = AngleBetweenVecs(lineA[0] - xA[0], line_mid)
            if a > line_angle:
                # vert is outside the range on 1 side. see what side of the grad
                if wA > wB: wA, wB = 1.0, 0.0
                else: wA, wB = 0.0, 1.0

        return wA, wB

    grad_weights = [grad_weight_from_co(v) for v in me.verts]

    if MODE == 0:
        for v in me.verts:
            i = v.index
            if VSEL[i]:
                wA, wB = grad_weights[i]
                if wA != None:  # and wB
                    if TOALPHA:
                        # Do alpha by using the exiting weight for
                        try:
                            pickValB = vWeightDict[i][act_group]
                        except:
                            pickValB = 0.0  # The weights not there? assume zero
                    # Mix2 2 opaque weights
                    vWeightDict[i][act_group] = pickValB * wA + pickValA * wB

    else:  # MODE==1 VCol
        for f in me.faces:
            if f.sel:
                f_v = f.v
                for i in xrange(len(f_v)):
                    v = f_v[i]
                    wA, wB = grad_weights[v.index]

                    c = f.col[i]

                    if TOALPHA:
                        pickValB = c.r, c.g, c.b

                    c.r = int(pickValB[0] * wA + pickValA[0] * wB)
                    c.g = int(pickValB[1] * wA + pickValA[1] * wB)
                    c.b = int(pickValB[2] * wA + pickValA[2] * wB)

    # Copy weights back to the mesh.
    BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
    Window.DrawProgressBar(1.0, '')
Пример #8
0
def mesh_mirror(me, PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST, PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS, PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES):
	'''
	PREF_MIRROR_LOCATION, Will we mirror locations?
	PREF_XMID_SNAP, Should we snap verts to X-0?
	PREF_MAX_DIST, Maximum distance to test snapping verts.
	PREF_XZERO_THRESH, How close verts must be to the middle before they are considered X-Zero verts.
	PREF_MODE, 0:middle, 1: Left. 2:Right.
	PREF_SEL_ONLY, only snap the selection
	PREF_EDGE_USERS, match only verts with the same number of edge users.
	PREF_MIRROR_LOCATION, 
	'''
	
	
	# Operate on all verts
	if not PREF_SEL_ONLY:
		for v in me.verts:
			v.sel=1
	
	
	if PREF_EDGE_USERS:
		edge_users= [0]*len(me.verts)
		for ed in me.edges:
			edge_users[ed.v1.index]+=1
			edge_users[ed.v2.index]+=1
	
	
	
	if PREF_XMID_SNAP: # Do we snap locations at all?
		for v in me.verts:
			if v.sel:
				if abs(v.co.x) <= PREF_XZERO_THRESH:
					v.co.x= 0
					v.sel= 0
		
		# alredy de-selected verts
		neg_vts = [v for v in me.verts if v.sel and v.co.x < 0]
		pos_vts = [v for v in me.verts if v.sel and v.co.x > 0]
		
	else:
		# Use a small margin verts must be outside before we mirror them.
		neg_vts = [v for v in me.verts if v.sel if v.co.x <  -PREF_XZERO_THRESH]
		pos_vts = [v for v in me.verts if v.sel if v.co.x >   PREF_XZERO_THRESH]
	
	
	
	#*Mirror Location*********************************************************#
	if PREF_MIRROR_LOCATION:
		mirror_pairs= []
		# allign the negative with the positive.
		flipvec= Mathutils.Vector()
		len_neg_vts= float(len(neg_vts))
		for i1, nv in enumerate(neg_vts):
			if nv.sel: # we may alredy be mirrored, if so well be deselected
				nv_co= nv.co
				for i2, pv in enumerate(pos_vts):
					if pv.sel:
						# Enforce edge users.
						if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]:
							flipvec[:]= pv.co
							flipvec.x= -flipvec.x
							l= (nv_co-flipvec).length
							
							if l==0.0: # Both are alredy mirrored so we dont need to think about them.
								# De-Select so we dont use again/
								pv.sel= nv.sel= 0
							
							# Record a match.
							elif l<=PREF_MAX_DIST:
								
								# We can adjust the length by the normal, now we know the length is under the limit.
								# DISABLED, WASNT VERY USEFULL
								'''
								if PREF_NOR_WEIGHT>0:
									# Get the normal and flipm reuse flipvec
									flipvec[:]= pv.no
									flipvec.x= -flipvec.x
									try:
										ang= Mathutils.AngleBetweenVecs(nv.no, flipvec)/180.0
									except: # on rare occasions angle between vecs will fail.- zero length vec.
										ang= 0
									
									l=l*(1+(ang*PREF_NOR_WEIGHT))
								'''
								# Record the pairs for sorting to see who will get joined
								mirror_pairs.append((l, nv, pv))
				
				# Update every 20 loops
				if i1 % 10 == 0:
					Window.DrawProgressBar(0.8 * (i1/len_neg_vts), 'Mirror verts %i of %i' % (i1, len_neg_vts))
		
		Window.DrawProgressBar(0.9, 'Mirror verts: Updating locations')
		
		# Now we have a list of the pairs we might use, lets find the best and do them first.
		# de-selecting as we go. so we can makke sure not to mess it up.
		try:	mirror_pairs.sort(key = lambda a: a[0])
		except:	mirror_pairs.sort(lambda a,b: cmp(a[0], b[0]))
		
		for dist, v1,v2 in mirror_pairs: # dist, neg, pos
			if v1.sel and v2.sel:
				if PREF_MODE==0: # Middle
					flipvec[:]= v2.co # positive
					flipvec.x= -flipvec.x # negatve
					v2.co= v1.co= (flipvec+v1.co)*0.5 # midway
					v2.co.x= -v2.co.x
				elif PREF_MODE==2: # Left
					v2.co= v1.co
					v2.co.x= -v2.co.x
				elif PREF_MODE==1: # Right
					v1.co= v2.co
					v1.co.x= -v1.co.x
				v1.sel= v2.sel= 0
	
	
	#*Mirror Weights**********************************************************#
	if PREF_MIRROR_WEIGHTS:
		
		groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
		mirror_pairs_l2r= [] # Stor a list of matches for these verts.
		mirror_pairs_r2l= [] # Stor a list of matches for these verts.
		
		# allign the negative with the positive.
		flipvec= Mathutils.Vector()
		len_neg_vts= float(len(neg_vts))
		
		# Here we make a tuple to look through, if were middle well need to look through both.
		if PREF_MODE==0: # Middle
			find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), (pos_vts, neg_vts, mirror_pairs_r2l))
		elif PREF_MODE==1: # Left
			find_set= ((neg_vts, pos_vts, mirror_pairs_l2r), )
		elif PREF_MODE==2: # Right
			find_set= ((pos_vts, neg_vts, mirror_pairs_r2l), )
		
		
		# Do a locational lookup again :/ - This isnt that good form but if we havnt mirrored weights well need to do it anyway.
		# The Difference with this is that we dont need to have 1:1 match for each vert- just get each vert to find another mirrored vert
		# and use its weight.
		# Use  "find_set" so we can do a flipped search L>R and R>L without duplicate code.
		for vtls_A, vtls_B, pair_ls  in  find_set:
			for i1, vA in enumerate(vtls_A):
				best_len=1<<30 # BIGNUM
				best_idx=-1
				
				# Find the BEST match
				vA_co= vA.co
				for i2, vB in enumerate(vtls_B):
					# Enforce edge users.
					if not PREF_EDGE_USERS or edge_users[i1]==edge_users[i2]:
						flipvec[:]= vB.co
						flipvec.x= -flipvec.x
						l= (vA_co-flipvec).length
						
						if l<best_len:
							best_len=l
							best_idx=i2
				
				if best_idx != -1:
					pair_ls.append((vtls_A[i1].index, vtls_B[best_idx].index)) # neg, pos.
		
		# Now we can merge the weights
		if PREF_MODE==0: # Middle
			newVWeightDict= [vWeightDict[i] for i in xrange(len(me.verts))] # Have empty dicts just incase
			for pair_ls in (mirror_pairs_l2r, mirror_pairs_r2l):
				if PREF_FLIP_NAMES:
					for i1, i2 in pair_ls:
						flipWeight, groupNames= BPyMesh.dictWeightFlipGroups( vWeightDict[i2], groupNames, PREF_CREATE_FLIP_NAMES )
						newVWeightDict[i1]= BPyMesh.dictWeightMerge([vWeightDict[i1], flipWeight] )
				else:
					for i1, i2 in pair_ls:
						newVWeightDict[i1]= BPyMesh.dictWeightMerge([vWeightDict[i1], vWeightDict[i2]])
			
			vWeightDict= newVWeightDict
		
		elif PREF_MODE==1: # Left
			if PREF_FLIP_NAMES:
				for i1, i2 in mirror_pairs_l2r:
					vWeightDict[i2], groupNames= BPyMesh.dictWeightFlipGroups(vWeightDict[i1], groupNames, PREF_CREATE_FLIP_NAMES)
			else:
				for i1, i2 in mirror_pairs_l2r:
					vWeightDict[i2]= vWeightDict[i1] # Warning Multiple instances of the same data, its ok in this case but dont modify later.
			
		elif PREF_MODE==2: # Right
			if PREF_FLIP_NAMES:
				for i1, i2 in mirror_pairs_r2l:
					vWeightDict[i2], groupNames= BPyMesh.dictWeightFlipGroups(vWeightDict[i1], groupNames, PREF_CREATE_FLIP_NAMES)
			else:
				for i1, i2 in mirror_pairs_r2l:
					vWeightDict[i2]= vWeightDict[i1] # Warning, ditto above
		
		BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
	
	me.update()
Пример #9
0
def mesh_mirror(me, PREF_MIRROR_LOCATION, PREF_XMID_SNAP, PREF_MAX_DIST,
                PREF_XZERO_THRESH, PREF_MODE, PREF_SEL_ONLY, PREF_EDGE_USERS,
                PREF_MIRROR_WEIGHTS, PREF_FLIP_NAMES, PREF_CREATE_FLIP_NAMES):
    '''
	PREF_MIRROR_LOCATION, Will we mirror locations?
	PREF_XMID_SNAP, Should we snap verts to X-0?
	PREF_MAX_DIST, Maximum distance to test snapping verts.
	PREF_XZERO_THRESH, How close verts must be to the middle before they are considered X-Zero verts.
	PREF_MODE, 0:middle, 1: Left. 2:Right.
	PREF_SEL_ONLY, only snap the selection
	PREF_EDGE_USERS, match only verts with the same number of edge users.
	PREF_MIRROR_LOCATION, 
	'''

    # Operate on all verts
    if not PREF_SEL_ONLY:
        for v in me.verts:
            v.sel = 1

    if PREF_EDGE_USERS:
        edge_users = [0] * len(me.verts)
        for ed in me.edges:
            edge_users[ed.v1.index] += 1
            edge_users[ed.v2.index] += 1

    if PREF_XMID_SNAP:  # Do we snap locations at all?
        for v in me.verts:
            if v.sel:
                if abs(v.co.x) <= PREF_XZERO_THRESH:
                    v.co.x = 0
                    v.sel = 0

        # alredy de-selected verts
        neg_vts = [v for v in me.verts if v.sel and v.co.x < 0]
        pos_vts = [v for v in me.verts if v.sel and v.co.x > 0]

    else:
        # Use a small margin verts must be outside before we mirror them.
        neg_vts = [v for v in me.verts if v.sel if v.co.x < -PREF_XZERO_THRESH]
        pos_vts = [v for v in me.verts if v.sel if v.co.x > PREF_XZERO_THRESH]

    #*Mirror Location*********************************************************#
    if PREF_MIRROR_LOCATION:
        mirror_pairs = []
        # allign the negative with the positive.
        flipvec = Mathutils.Vector()
        len_neg_vts = float(len(neg_vts))
        for i1, nv in enumerate(neg_vts):
            if nv.sel:  # we may alredy be mirrored, if so well be deselected
                nv_co = nv.co
                for i2, pv in enumerate(pos_vts):
                    if pv.sel:
                        # Enforce edge users.
                        if not PREF_EDGE_USERS or edge_users[i1] == edge_users[
                                i2]:
                            flipvec[:] = pv.co
                            flipvec.x = -flipvec.x
                            l = (nv_co - flipvec).length

                            if l == 0.0:  # Both are alredy mirrored so we dont need to think about them.
                                # De-Select so we dont use again/
                                pv.sel = nv.sel = 0

                            # Record a match.
                            elif l <= PREF_MAX_DIST:

                                # We can adjust the length by the normal, now we know the length is under the limit.
                                # DISABLED, WASNT VERY USEFULL
                                '''
								if PREF_NOR_WEIGHT>0:
									# Get the normal and flipm reuse flipvec
									flipvec[:]= pv.no
									flipvec.x= -flipvec.x
									try:
										ang= Mathutils.AngleBetweenVecs(nv.no, flipvec)/180.0
									except: # on rare occasions angle between vecs will fail.- zero length vec.
										ang= 0
									
									l=l*(1+(ang*PREF_NOR_WEIGHT))
								'''
                                # Record the pairs for sorting to see who will get joined
                                mirror_pairs.append((l, nv, pv))

                # Update every 20 loops
                if i1 % 10 == 0:
                    Window.DrawProgressBar(
                        0.8 * (i1 / len_neg_vts),
                        'Mirror verts %i of %i' % (i1, len_neg_vts))

        Window.DrawProgressBar(0.9, 'Mirror verts: Updating locations')

        # Now we have a list of the pairs we might use, lets find the best and do them first.
        # de-selecting as we go. so we can makke sure not to mess it up.
        try:
            mirror_pairs.sort(key=lambda a: a[0])
        except:
            mirror_pairs.sort(lambda a, b: cmp(a[0], b[0]))

        for dist, v1, v2 in mirror_pairs:  # dist, neg, pos
            if v1.sel and v2.sel:
                if PREF_MODE == 0:  # Middle
                    flipvec[:] = v2.co  # positive
                    flipvec.x = -flipvec.x  # negatve
                    v2.co = v1.co = (flipvec + v1.co) * 0.5  # midway
                    v2.co.x = -v2.co.x
                elif PREF_MODE == 2:  # Left
                    v2.co = v1.co
                    v2.co.x = -v2.co.x
                elif PREF_MODE == 1:  # Right
                    v1.co = v2.co
                    v1.co.x = -v1.co.x
                v1.sel = v2.sel = 0

    #*Mirror Weights**********************************************************#
    if PREF_MIRROR_WEIGHTS:

        groupNames, vWeightDict = BPyMesh.meshWeight2Dict(me)
        mirror_pairs_l2r = []  # Stor a list of matches for these verts.
        mirror_pairs_r2l = []  # Stor a list of matches for these verts.

        # allign the negative with the positive.
        flipvec = Mathutils.Vector()
        len_neg_vts = float(len(neg_vts))

        # Here we make a tuple to look through, if were middle well need to look through both.
        if PREF_MODE == 0:  # Middle
            find_set = ((neg_vts, pos_vts, mirror_pairs_l2r),
                        (pos_vts, neg_vts, mirror_pairs_r2l))
        elif PREF_MODE == 1:  # Left
            find_set = ((neg_vts, pos_vts, mirror_pairs_l2r), )
        elif PREF_MODE == 2:  # Right
            find_set = ((pos_vts, neg_vts, mirror_pairs_r2l), )

        # Do a locational lookup again :/ - This isnt that good form but if we havnt mirrored weights well need to do it anyway.
        # The Difference with this is that we dont need to have 1:1 match for each vert- just get each vert to find another mirrored vert
        # and use its weight.
        # Use  "find_set" so we can do a flipped search L>R and R>L without duplicate code.
        for vtls_A, vtls_B, pair_ls in find_set:
            for i1, vA in enumerate(vtls_A):
                best_len = 1 << 30  # BIGNUM
                best_idx = -1

                # Find the BEST match
                vA_co = vA.co
                for i2, vB in enumerate(vtls_B):
                    # Enforce edge users.
                    if not PREF_EDGE_USERS or edge_users[i1] == edge_users[i2]:
                        flipvec[:] = vB.co
                        flipvec.x = -flipvec.x
                        l = (vA_co - flipvec).length

                        if l < best_len:
                            best_len = l
                            best_idx = i2

                if best_idx != -1:
                    pair_ls.append((vtls_A[i1].index,
                                    vtls_B[best_idx].index))  # neg, pos.

        # Now we can merge the weights
        if PREF_MODE == 0:  # Middle
            newVWeightDict = [vWeightDict[i] for i in xrange(len(me.verts))
                              ]  # Have empty dicts just incase
            for pair_ls in (mirror_pairs_l2r, mirror_pairs_r2l):
                if PREF_FLIP_NAMES:
                    for i1, i2 in pair_ls:
                        flipWeight, groupNames = BPyMesh.dictWeightFlipGroups(
                            vWeightDict[i2], groupNames,
                            PREF_CREATE_FLIP_NAMES)
                        newVWeightDict[i1] = BPyMesh.dictWeightMerge(
                            [vWeightDict[i1], flipWeight])
                else:
                    for i1, i2 in pair_ls:
                        newVWeightDict[i1] = BPyMesh.dictWeightMerge(
                            [vWeightDict[i1], vWeightDict[i2]])

            vWeightDict = newVWeightDict

        elif PREF_MODE == 1:  # Left
            if PREF_FLIP_NAMES:
                for i1, i2 in mirror_pairs_l2r:
                    vWeightDict[i2], groupNames = BPyMesh.dictWeightFlipGroups(
                        vWeightDict[i1], groupNames, PREF_CREATE_FLIP_NAMES)
            else:
                for i1, i2 in mirror_pairs_l2r:
                    vWeightDict[i2] = vWeightDict[
                        i1]  # Warning Multiple instances of the same data, its ok in this case but dont modify later.

        elif PREF_MODE == 2:  # Right
            if PREF_FLIP_NAMES:
                for i1, i2 in mirror_pairs_r2l:
                    vWeightDict[i2], groupNames = BPyMesh.dictWeightFlipGroups(
                        vWeightDict[i1], groupNames, PREF_CREATE_FLIP_NAMES)
            else:
                for i1, i2 in mirror_pairs_r2l:
                    vWeightDict[i2] = vWeightDict[i1]  # Warning, ditto above

        BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)

    me.update()
Пример #10
0
def vertexGradientPick(ob, MODE):
	#MODE 0 == VWEIGHT,  1 == VCOL 
	
	me= ob.getData(mesh=1)
	if not me.faceUV:	me.faceUV= True
	
	Window.DrawProgressBar (0.0, '')
	
	mousedown_wait()
	
	if MODE==0:
		act_group= me.activeGroup
		if act_group == None:
			mousedown_wait()
			Draw.PupMenu('Error, mesh has no active group.')
			return
	
	# Loop until click
	Window.DrawProgressBar (0.25, 'Click to set gradient start')
	mouseup()
	
	obmat= ob.matrixWorld
	screen_x, screen_y = Window.GetMouseCoords()
	mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat)
	if not mouseInView or not OriginA:
		return
	
	# get the mouse weight
	
	if MODE==0:
		pickValA= BPyMesh.pickMeshGroupWeight(me, act_group, OriginA, DirectionA)
	if MODE==1:
		pickValA= BPyMesh.pickMeshGroupVCol(me, OriginA, DirectionA)
	
	Window.DrawProgressBar (0.75, 'Click to set gradient end')
	mouseup()
	
	TOALPHA= Window.GetKeyQualifiers() & Window.Qual.SHIFT
	
	screen_x, screen_y = Window.GetMouseCoords()
	mouseInView, OriginB, DirectionB = mouseViewRay(screen_x, screen_y, obmat)
	if not mouseInView or not OriginB:
		return
	
	if not TOALPHA: # Only get a second opaque value if we are not blending to alpha
		if MODE==0:	pickValB= BPyMesh.pickMeshGroupWeight(me, act_group, OriginB, DirectionB)
		else:
			pickValB= BPyMesh.pickMeshGroupVCol(me, OriginB, DirectionB)
	else:
		if MODE==0: pickValB= 0.0
		else: pickValB= [0.0, 0.0, 0.0] # Dummy value
	
	# Neither points touched a face
	if pickValA == pickValB == None:
		return
	
	# clicking on 1 non face is fine. just set the weight to 0.0
	if pickValA==None:
		pickValA= 0.0
		
		# swap A/B
		OriginA, OriginB= OriginB, OriginA
		DirectionA, DirectionB= DirectionB, DirectionA
		pickValA, pickValB= pickValA, pickValB
		
		TOALPHA= True
		
	if pickValB==None:
		pickValB= 0.0
		TOALPHA= True
	
	# set up 2 lines so we can measure their distances and calc the gradient
	
	# make a line 90d to the grad in screenspace.
	if (OriginA-OriginB).length <= eps: # Persp view. same origin different direction
		cross_grad= DirectionA.cross(DirectionB)
		ORTHO= False
		
	else: # Ortho - Same direction, different origin
		cross_grad= DirectionA.cross(OriginA-OriginB)
		ORTHO= True
	
	cross_grad.normalize()
	cross_grad= cross_grad * 100
	
	lineA= (OriginA, OriginA+(DirectionA*100))
	lineB= (OriginB, OriginB+(DirectionB*100))
	
	if not ORTHO:
		line_angle= AngleBetweenVecs(lineA[1], lineB[1])/2
		line_mid= (lineA[1]+lineB[1])*0.5

	VSEL= [False] * (len(me.verts))
	
	# Get the selected faces and apply the selection to the verts.
	for f in me.faces:
		if f.sel:
			for v in f.v:
				VSEL[v.index]= True
	groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
	
	
	
	def grad_weight_from_co(v):
		'''
		Takes a vert and retuens its gradient radio between A and B
		'''
		
		if not VSEL[v.index]: # Not bart of a selected face?
			return None, None
		
		v_co= v.co
		# make a line 90d to the 2 lines the user clicked.
		vert_line= (v_co - cross_grad, v_co + cross_grad)
		
		xA= LineIntersect(vert_line[0], vert_line[1], lineA[0], lineA[1])
		xB= LineIntersect(vert_line[0], vert_line[1], lineB[0], lineB[1])
		
		if not xA or not xB: # Should never happen but support it anyhow
			return None, None
		
		wA= (xA[0]-xA[1]).length
		wB= (xB[0]-xB[1]).length
		
		wTot= wA+wB
		if not wTot: # lines are on the same point.
			return None, None
		
		'''
		Get the length of the line between both intersections on the 
		2x view lines.
		if the dist between  lineA+VertLine and lineB+VertLine is 
		greater then the lenth between lineA and lineB intersection points, it means
		that the verts are not inbetween the 2 lines.
		'''
		lineAB_length= (xA[1]-xB[1]).length
		
		# normalzie
		wA= wA/wTot
		wB= wB/wTot
		
		if ORTHO: # Con only use line length method with parelelle lines
			if wTot > lineAB_length+eps:
				# vert is outside the range on 1 side. see what side of the grad
				if wA>wB:		wA, wB= 1.0, 0.0
				else:			wA, wB= 0.0, 1.0
		else:
			# PERSP, lineA[0] is the same origin as lineB[0]
			
			# Either xA[0] or xB[0]  can be used instead of a possible x_mid between the 2
			# as long as the point is inbetween lineA and lineB it dosent matter.
			a= AngleBetweenVecs(lineA[0]-xA[0], line_mid)
			if a>line_angle:
				# vert is outside the range on 1 side. see what side of the grad
				if wA>wB:		wA, wB= 1.0, 0.0
				else:			wA, wB= 0.0, 1.0
		
		return wA, wB
		
	
	grad_weights= [grad_weight_from_co(v) for v in me.verts]
	
	
	if MODE==0:
		for v in me.verts:
			i= v.index
			if VSEL[i]:
				wA, wB = grad_weights[i]
				if wA != None: # and wB 
					if TOALPHA:
						# Do alpha by using the exiting weight for 
						try:		pickValB= vWeightDict[i][act_group]
						except:	pickValB= 0.0 # The weights not there? assume zero
					# Mix2 2 opaque weights
					vWeightDict[i][act_group]= pickValB*wA + pickValA*wB
	
	else: # MODE==1 VCol
		for f in me.faces:
			if f.sel:
				f_v= f.v
				for i in xrange(len(f_v)):
					v= f_v[i]
					wA, wB = grad_weights[v.index]
					
					c= f.col[i]
					
					if TOALPHA:
						pickValB= c.r, c.g, c.b
					
					c.r = int(pickValB[0]*wA + pickValA[0]*wB)
					c.g = int(pickValB[1]*wA + pickValA[1]*wB)
					c.b = int(pickValB[2]*wA + pickValA[2]*wB)
					
	
	
	
	# Copy weights back to the mesh.
	BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
	Window.DrawProgressBar (1.0, '')
Пример #11
0
def actWeightNormalize(me, ob, PREF_PEAKWEIGHT, PREF_ACTIVE_ONLY,
                       PREF_ARMATURE_ONLY, PREF_KEEP_PROPORTION):

    groupNames, vWeightDict = BPyMesh.meshWeight2Dict(me)
    new_weight = max_weight = -1.0
    act_group = me.activeGroup

    if PREF_ACTIVE_ONLY:
        normalizeGroups = [act_group]
    else:
        normalizeGroups = groupNames[:]

    if PREF_ARMATURE_ONLY:

        armature_groups = getArmatureGroups(ob, me)

        i = len(normalizeGroups)
        while i:
            i -= 1
            if not normalizeGroups[i] in armature_groups:
                del normalizeGroups[i]

    for act_group in normalizeGroups:
        vWeightDictUsed = [False] * len(vWeightDict)

        for i, wd in enumerate(vWeightDict):
            try:
                new_weight = wd[act_group]
                if new_weight > max_weight:
                    max_weight = new_weight
                vWeightDictUsed[i] = wd
            except:
                pass

        # These can be skipped for now, they complicate things when using multiple vgroups,
        '''
		if max_weight < SMALL_NUM or new_weight == -1:
			Draw.PupMenu('No verts to normalize. exiting.')
			#return
		
		if abs(max_weight-PREF_PEAKWEIGHT) < SMALL_NUM:
			Draw.PupMenu('Vert Weights are alredy normalized.')
			#return
		'''
        max_weight = max_weight / PREF_PEAKWEIGHT

        if PREF_KEEP_PROPORTION:
            # TODO, PROPORTIONAL WEIGHT SCALING.
            for wd in vWeightDictUsed:
                if wd:  # not false.
                    if len(wd) == 1:
                        # Only 1 group for thsi vert. Simple
                        wd[act_group] /= max_weight
                    else:
                        # More then 1 group. will need to scale all users evenly.
                        if PREF_ARMATURE_ONLY:
                            local_maxweight = max([
                                v for k, v in wd.iteritems()
                                if k in armature_groups
                            ]) / PREF_PEAKWEIGHT
                            if local_maxweight > 0.0:
                                # So groups that are not used in any bones are ignored.
                                for weight in wd.iterkeys():
                                    if weight in armature_groups:
                                        wd[weight] /= local_maxweight
                        else:
                            local_maxweight = max(
                                wd.itervalues()) / PREF_PEAKWEIGHT
                            for weight in wd.iterkeys():
                                wd[weight] /= local_maxweight

        else:  # Simple, just scale the weights up. we alredy know this is in an armature group (if needed)
            for wd in vWeightDictUsed:
                if wd:  # not false.
                    wd[act_group] /= max_weight

    # Copy weights back to the mesh.
    BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)
Пример #12
0
def actWeightNormalize(me, ob, PREF_PEAKWEIGHT, PREF_ACTIVE_ONLY, PREF_ARMATURE_ONLY, PREF_KEEP_PROPORTION):
	
	groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me)
	new_weight= max_weight= -1.0
	act_group= me.activeGroup
	
	if PREF_ACTIVE_ONLY:
		normalizeGroups = [act_group]
	else:
		normalizeGroups  = groupNames[:]
	
	if PREF_ARMATURE_ONLY:
		
		armature_groups = getArmatureGroups(ob, me)
		
		i = len(normalizeGroups)
		while i:
			i-=1
			if not normalizeGroups[i] in armature_groups:
				del normalizeGroups[i]
	
	
	for act_group in normalizeGroups:
		vWeightDictUsed=[False] * len(vWeightDict)
		
		for i, wd in enumerate(vWeightDict):
			try:
				new_weight= wd[act_group]
				if new_weight > max_weight:
					max_weight= new_weight
				vWeightDictUsed[i]=wd
			except:
				pass
				
		# These can be skipped for now, they complicate things when using multiple vgroups,
		'''
		if max_weight < SMALL_NUM or new_weight == -1:
			Draw.PupMenu('No verts to normalize. exiting.')
			#return
		
		if abs(max_weight-PREF_PEAKWEIGHT) < SMALL_NUM:
			Draw.PupMenu('Vert Weights are alredy normalized.')
			#return
		'''
		max_weight= max_weight/PREF_PEAKWEIGHT
		
		if PREF_KEEP_PROPORTION:
			# TODO, PROPORTIONAL WEIGHT SCALING.
			for wd in vWeightDictUsed:
				if wd: # not false.
					if len(wd) == 1:
						# Only 1 group for thsi vert. Simple
						wd[act_group] /= max_weight
					else:
						# More then 1 group. will need to scale all users evenly.
						if PREF_ARMATURE_ONLY:
							local_maxweight= max([v for k, v in wd.iteritems() if k in armature_groups]) / PREF_PEAKWEIGHT
							if local_maxweight > 0.0:
								# So groups that are not used in any bones are ignored.
								for weight in wd.iterkeys():
									if weight in armature_groups:
										wd[weight] /= local_maxweight
						else:
							local_maxweight= max(wd.itervalues()) / PREF_PEAKWEIGHT
							for weight in wd.iterkeys():
								wd[weight] /= local_maxweight
		
		else: # Simple, just scale the weights up. we alredy know this is in an armature group (if needed)
			for wd in vWeightDictUsed:
				if wd: # not false.
					wd[act_group] /= max_weight
		
	# Copy weights back to the mesh.
	BPyMesh.dict2MeshWeight(me, groupNames, vWeightDict)