#!BPY """ Name: 'Relax selected UVs.' Blender: 237 Group: 'UV' Tooltip: 'Relaxes selected UVs ' """ __author__ = "Campbell Barton" __url__ = ("blender", "elysiun") __version__ = "1.0 2006/02/07" __bpydoc__ = """\ This script relaxes selected UV verts in relation to there surrounding geometry. Use this script in face select mode. Left Click to finish or wait until no more relaxing can be done. """ # ***** BEGIN GPL LICENSE BLOCK ***** # # Script copyright (C) Campbell J Barton # # 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 ***** # -------------------------------------------------------------------------- from Blender import Scene, Object, Mesh, Window from Blender.Mathutils import Vector class relaxVert(object): __slots__= 'bvert', 'edges', 'bfaces', 'uv', 'sel' def __init__(self, bvert): self.bvert= bvert self.edges= [] self.bfaces= [] # list pf tuples, bface and this verts index in the bface. self.uv= Vector(0,0) self.sel= False def setBFaceUV(self): x= self.uv.x y= self.uv.y for bface,i in self.bfaces: bface.uv[i].x= x bface.uv[i].y= y class relaxEdge(object): __slots__= 'v1', 'v2', 'length3d', 'lengthUv', 'lengthUvOrig' def __init__(self, v1,v2): self.v1= v1 self.v2= v2 self.length3d= (v1.bvert.co-v2.bvert.co).length self.lengthUv= None self.lengthUvOrig= None def otherVert(self, v): if v==self.v1 and v!=self.v2: return self.v2 elif v==self.v2 and v!=self.v1: return self.v1 else: raise 'Vert not in edge' def setUvLength(self): self.lengthUv= (self.v1.uv - self.v2.uv).length if self.lengthUvOrig==None: self.lengthUvOrig= self.lengthUv def main(): scn= Scene.GetCurrent() ob= scn.getActiveObject() if not ob or ob.getType() != 'Mesh': Draw.PupMenu('ERROR: No mesh object in face select mode.') return me= ob.getData(mesh=1) def sortPair(a,b): return min(a,b), max(a,b) # Build edge data from faces. relaxEdgeDict= {} relaxVertList= [relaxVert(v) for v in me.verts] tempVertUVList = [Vector(0,0,0) for v in me.verts] # Z is an int for scaling the first 2 values. for f in me.faces: for i in xrange(len(f.v)): v1,v2= f.v[i], f.v[i-1] key= sortPair(v1.index, v2.index) rv1= relaxVertList[v1.index] rv2= relaxVertList[v2.index] try: # Do nothing if we exist. tmpEdge= relaxEdgeDict[key] except: tmpEdge= relaxEdgeDict[key]= relaxEdge(rv1,rv2) # Add the edges to the face. rv1.edges.append(tmpEdge) rv2.edges.append(tmpEdge) # Will get to all v1's no need to add both per edge. rv1.bfaces.append( (f, i) ) tempVertUVList[v1.index].x += f.uv[i].x tempVertUVList[v1.index].y += f.uv[i].y tempVertUVList[v1.index].z+=1 if f.uvSel[i]: rv1.sel= True # Now average UV's into the relaxVerts for i, rv in enumerate(relaxVertList): if tempVertUVList[i].z > 0: newUV= tempVertUVList[i] * (1/tempVertUVList[i].z) rv.uv.x= newUV.x rv.uv.y= newUV.y del tempVertUVList # Loop while the button is held, so clicking on a menu wont immediatly exit. while Window.GetMouseButtons() & Window.MButs['L']: pass # NOW RELAX #ITERATIONS=1000 #for iter in range(ITERATIONS): Window.DrawProgressBar(0.0, '') iter=0 while not Window.GetMouseButtons() & Window.MButs['L']: tempUV= Vector(0,0) iter+=1 if not iter%10: Window.DrawProgressBar(0.1, 'Left Mouse to Exit %i' % iter) # Set the uv lengths each iteration. for re in relaxEdgeDict.itervalues(): re.setUvLength() changed=False for rv in relaxVertList: if rv.sel: backupUV= rv.uv totUvLen= tot3dLen= 0 for re in rv.edges: tot3dLen+= re.length3d totUvLen+= re.lengthUvOrig # So the UV edges dont keep growing. # the radio is the scaler between 3d space and UV space - so we can relax the UVs # so proportionaly the UV lengths match the 3d lengths. ratio = totUvLen/tot3dLen # Make a list of new UVs that match the 3d length of the edges. tempUV.y= tempUV.x= 0 for re in rv.edges: otherRelaxVert= re.otherVert(rv) targetDist= re.length3d*ratio newUV= rv.uv-otherRelaxVert.uv newUV.normalize() newUV= newUV*targetDist #tempUVs.append(newUV+otherRelaxVert.uv) tempUV= tempUV+ ( (newUV+otherRelaxVert.uv) * (1/float(len(rv.edges)))) if (rv.uv!=tempUV): changed= True rv.uv= (rv.uv+tempUV)* 0.5 if not changed: break # Connection data done. for rv in relaxVertList: if rv.sel: rv.setBFaceUV() me.update() Window.RedrawAll() Window.DrawProgressBar(1.0, '') if __name__=='__main__': main()