2006-02-07 03:41:28 +00:00
|
|
|
#!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.
|
|
|
|
"""
|
|
|
|
|
|
|
|
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]
|
|
|
|
|
2006-02-07 03:58:57 +00:00
|
|
|
tempVertUVList = [Vector(0,0,0) for v in me.verts] # Z is an int for scaling the first 2 values.
|
2006-02-07 03:41:28 +00:00
|
|
|
|
|
|
|
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)
|
2006-02-07 03:58:57 +00:00
|
|
|
rv1= relaxVertList[v1.index]
|
|
|
|
rv2= relaxVertList[v2.index]
|
2006-02-07 03:41:28 +00:00
|
|
|
try: # Do nothing if we exist.
|
|
|
|
tmpEdge= relaxEdgeDict[key]
|
|
|
|
except:
|
2006-02-07 03:58:57 +00:00
|
|
|
tmpEdge= relaxEdgeDict[key]= relaxEdge(rv1,rv2)
|
2006-02-07 03:41:28 +00:00
|
|
|
|
|
|
|
# Add the edges to the face.
|
|
|
|
rv1.edges.append(tmpEdge)
|
|
|
|
rv2.edges.append(tmpEdge)
|
2006-02-07 03:58:57 +00:00
|
|
|
|
2006-02-07 03:41:28 +00:00
|
|
|
# Will get to all v1's no need to add both per edge.
|
|
|
|
rv1.bfaces.append( (f, i) )
|
2006-02-07 03:58:57 +00:00
|
|
|
tempVertUVList[v1.index].x += f.uv[i].x
|
|
|
|
tempVertUVList[v1.index].y += f.uv[i].y
|
|
|
|
tempVertUVList[v1.index].z+=1
|
2006-02-07 03:41:28 +00:00
|
|
|
if f.uvSel[i]:
|
|
|
|
rv1.sel= True
|
|
|
|
|
|
|
|
# Now average UV's into the relaxVerts
|
|
|
|
for i, rv in enumerate(relaxVertList):
|
2006-02-07 03:58:57 +00:00
|
|
|
if tempVertUVList[i].z > 0:
|
|
|
|
newUV= tempVertUVList[i] * (1/tempVertUVList[i].z)
|
|
|
|
rv.uv.x= newUV.x
|
|
|
|
rv.uv.y= newUV.y
|
2006-02-07 03:41:28 +00:00
|
|
|
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()
|