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)
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)
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)
def selSameWeights(me, PREF_TOLERENCE): # Check for missing data if not me.faceUV: return act_group= me.activeGroup if not act_group: return act_face = me.faces[me.activeFace] if act_face == None: return groupNames, vWeightDict= BPyMesh.meshWeight2Dict(me) def get_face_weight(f): ''' Return the faces median weight and weight range. ''' wmin = 1.0 wmax = 0.0 w = 0.0 for v in f: try: new_weight = vWeightDict[v.index][act_group] if wmin > new_weight: wmin = new_weight if wmax < new_weight: wmax = new_weight w += new_weight except: pass return w, wmax-wmin # weight, range weight_from, weight_range_from = get_face_weight(act_face) for f in me.faces: if (not f.sel) and f != act_face: weight, weight_range = get_face_weight(f) # Compare the 2 faces weight difference and difference in their contrast. if\ abs(weight - weight_from) <= PREF_TOLERENCE and\ abs(weight_range - weight_range_from) <= PREF_TOLERENCE: f.sel = True
def selSameWeights(me, PREF_TOLERENCE): # Check for missing data if not me.faceUV: return act_group = me.activeGroup if not act_group: return act_face = me.faces[me.activeFace] if act_face == None: return groupNames, vWeightDict = BPyMesh.meshWeight2Dict(me) def get_face_weight(f): ''' Return the faces median weight and weight range. ''' wmin = 1.0 wmax = 0.0 w = 0.0 for v in f: try: new_weight = vWeightDict[v.index][act_group] if wmin > new_weight: wmin = new_weight if wmax < new_weight: wmax = new_weight w += new_weight except: pass return w, wmax - wmin # weight, range weight_from, weight_range_from = get_face_weight(act_face) for f in me.faces: if (not f.sel) and f != act_face: weight, weight_range = get_face_weight(f) # Compare the 2 faces weight difference and difference in their contrast. if\ abs(weight - weight_from) <= PREF_TOLERENCE and\ abs(weight_range - weight_range_from) <= PREF_TOLERENCE: f.sel = True
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
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
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, '')
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()
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()
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, '')
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)
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)