#!BPY """ Name: 'Weight Gradient...' Blender: 241 Group: 'VertPaint' Tooltip: 'Grad.' """ __author__ = ["Campbell Barton"] __url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") __version__ = "0.1" import Blender import BPyMesh import BPyWindow reload(BPyWindow) reload(BPyMesh) mouseViewRay= BPyWindow.mouseViewRay from Blender import Mathutils, Window, Scene, Draw, sys from Blender.Mathutils import CrossVecs, Vector, Intersect, LineIntersect, AngleBetweenVecs LMB= Window.MButs['L'] def mouseup(): # Loop until click mouse_buttons = Window.GetMouseButtons() while not mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() while mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() def mousedown_wait(): # If the menu has just been pressed dont use its mousedown, mouse_buttons = Window.GetMouseButtons() while mouse_buttons & LMB: mouse_buttons = Window.GetMouseButtons() eps= 0.0001 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= CrossVecs(DirectionA, DirectionB) ORTHO= False else: # Ortho - Same direction, different origin cross_grad= CrossVecs(DirectionA, OriginA-OriginB) ORTHO= True cross_grad= cross_grad.normalize() * 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 FSEL= Blender.Mesh.FaceFlags.SELECT VSEL= [False] * (len(me.verts)) # Get the selected faces and apply the selection to the verts. for f in me.faces: if f.flag & FSEL: 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.flag & FSEL: 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, '')