Advertisement
Guest User

UV shotgun

a guest
Mar 5th, 2017
599
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.12 KB | None | 0 0
  1. import bpy
  2. from mathutils import geometry as gm
  3. import math
  4. import random
  5. import time
  6.  
  7. #from os.path import dirname
  8. #module_dir = "\\".join(dirname(__file__).split("\\")[:-1])
  9.  
  10. #import sys
  11. #if not module_dir in sys.path:
  12. #    sys.path.insert(0, module_dir)
  13.  
  14. rnd = random.random
  15.  
  16. class Island():
  17.     def __init__(self, polys, obj):
  18.         self.obj = obj
  19.         self.polys = polys
  20.         self.verts = []
  21.         self.uv_layer = obj.data.uv_layers.active
  22.         self.vertcount = 0
  23.        
  24.         # verts matching poly indices
  25.         for f in self.polys:      
  26.             lidcs = obj.data.polygons[f].loop_indices
  27.             self.verts.append([[*self.uv_layer.data[l].uv] for l in lidcs])  
  28.             self.vertcount += len(lidcs)
  29.         self._bb_calc()
  30.                
  31.     def _bb_calc(self):
  32.         self.minx, self.miny, self.maxx, self.maxy = (100.0,100.0, -100.0,-100.0)
  33.         self.avg_x, self.avg_y = 0.0, 0.0
  34.         for a in self.verts:
  35.             for t in a:
  36.                 if t[0] > self.maxx: self.maxx = t[0]  
  37.                 if t[0] < self.minx: self.minx = t[0]
  38.                 if t[1] > self.maxy: self.maxy = t[1]  
  39.                 if t[1] < self.miny: self.miny = t[1]    
  40.                
  41.                 self.avg_x += t[0]
  42.                 self.avg_y += t[1]
  43.        
  44.         self.avg_x //= self.vertcount
  45.         self.avg_y //= self.vertcount
  46.            
  47.         self.bb_x = self.maxx - self.minx
  48.         self.bb_y = self.maxy - self.miny
  49.        
  50.         self.bb_size = round(self.bb_x * self.bb_y, 4)  
  51.        
  52.         # uv edges
  53.         self.lines = []
  54.         for f in range(len(self.verts)):
  55.             for j in range(len(self.verts[f])):
  56.                 self.lines.append((
  57.                     tuple(self.verts[f][j]),
  58.                     tuple(self.verts[f][(j+1)%len(self.verts[f])])))
  59.                    
  60.         # sort uv edges by x location from 0->
  61.         #self.lines = [(i[0],i[1]) if i[0][0]<i[1][0] else (i[1],i[0]) for i in self.lines]
  62.         #self.lines.sort(key=lambda x: x[0][0])
  63.        
  64.     def check_collision(self, other):
  65.         # check bounding boxes
  66.         if self.minx > other.maxx or self.miny > other.maxy or self.maxx < other.minx or self.maxy < other.miny:
  67.             return False        
  68.        
  69.         # check for point inside polygon collision, random
  70.         a = self.verts[random.randint(0, len(self.verts)-1)]
  71.         for t in a:
  72.             for f in other.verts: # faces
  73.                 if len(f) == 4:
  74.                     if gm.intersect_point_quad_2d(t, f[0], f[1], f[2], f[3]):
  75.                         return True
  76.                 elif len(f) == 3:
  77.                     if gm.intersect_point_tri_2d(t, f[0], f[1], f[2]):
  78.                         return True
  79.                    
  80.         # check for line collisions
  81.         for l in self.lines:
  82.             for ol in other.lines:
  83.                 if gm.intersect_line_line_2d(l[0], l[1], ol[0], ol[1]):
  84.                     return True
  85.  
  86.         return False      
  87.                
  88.     def _updateloc(self, x, y):
  89.         self.maxx += x
  90.         self.minx += x
  91.         self.maxy += y
  92.         self.miny += y
  93.         self.lines = [((a[0]+x,a[1]+y), (b[0]+x,b[1]+y)) for (a,b) in self.lines]        
  94.        
  95.     def rotate90(self):
  96.         for i in range(len(self.verts)):
  97.             for j in range(len(self.verts[i])):
  98.                 x = self.verts[i][j][0]
  99.                 y = self.verts[i][j][1]
  100.                 self.verts[i][j][0] = self.avg_y - y
  101.                 self.verts[i][j][1] = x - self.avg_x
  102.         self._bb_calc()
  103.        
  104.     def flipx(self):
  105.         for i in range(len(self.verts)):
  106.             for j in range(len(self.verts[i])):
  107.                 x = self.verts[i][j][0]
  108.                 self.verts[i][j][0] = self.avg_x - x
  109.         self._bb_calc()
  110.        
  111.     def move(self, x, y):
  112.         for i in range(len(self.verts)):
  113.             for j in range(len(self.verts[i])):
  114.                 self.verts[i][j][0] += x
  115.                 self.verts[i][j][1] += y
  116.         self._updateloc(x, y)
  117.        
  118.     def set_location(self, x, y):
  119.         dispx = x - self.minx
  120.         dispy = y - self.miny
  121.         for i in range(len(self.verts)):
  122.             for j in range(len(self.verts[i])):
  123.                 self.verts[i][j][0] += dispx
  124.                 self.verts[i][j][1] += dispy    
  125.         self._updateloc(dispx, dispy)        
  126.                
  127.     def write(self):
  128.         for fi, f in enumerate(self.polys):      
  129.             for i, loop_idx in enumerate(self.obj.data.polygons[f].loop_indices):
  130.                 self.obj.data.uv_layers.active.data[loop_idx].uv = \
  131.                     self.verts[fi][i]
  132.        
  133.     def __repr__(self):
  134.         return "verts: " + repr(self.verts) + "  polys: " + repr(self.polys)
  135.  
  136.  
  137. def approximate_islands(ob, uv_layer):
  138.     islands = []    
  139.  
  140.     # merge polygons sharing uvs
  141.     for poly in ob.data.polygons:
  142.         #poly_info = list(zip([i for i in poly.loop_indices], [i for i in poly.vertices]))
  143.         poly_info = [i for i in poly.loop_indices]
  144.         uvs = set((round(uv_layer[i].uv[0], 4), round(uv_layer[i].uv[1], 4)) for i in poly_info)
  145.         notfound = True
  146.         for i,island in enumerate(islands):
  147.             if island & uvs != set():
  148.                 islands[i] = islands[i].union(uvs)
  149.                 notfound = False
  150.                 break
  151.         if notfound:
  152.             islands.append(uvs)
  153.        
  154.     # merge sets sharing uvs
  155.     for isleidx in range(len(islands)):    
  156.         el = islands[isleidx]
  157.         notfound = True
  158.         for i, isle in enumerate(islands):
  159.             if i == isleidx:
  160.                 continue
  161.             if el & isle != set():
  162.                 islands[i] = islands[i].union(el)
  163.                 islands[isleidx] = set()
  164.                 notfound = False
  165.                 break
  166.            
  167.     # remove empty sets
  168.     islands = [i for i in islands if i != set()]
  169.     return islands
  170.  
  171. bpy.ops.object.mode_set(mode='OBJECT')
  172. ob = bpy.context.object
  173. uv_layer = ob.data.uv_layers.active.data
  174.  
  175. # get islands and their verts
  176. islands = approximate_islands(ob, uv_layer)  
  177. print(len(islands))
  178.  
  179. # connect polys to island data
  180. islefaces = [set()] * len(islands)
  181. for poly in ob.data.polygons:
  182.     uvs = set((round(uv_layer[i].uv[0], 4), round(uv_layer[i].uv[1], 4)) for i in poly.loop_indices)
  183.     for i, isle in enumerate(islands):
  184.         if uvs & isle != set():
  185.             islefaces[i] = islefaces[i].union(set([poly.index]))
  186.  
  187. isles = []
  188. for i in range(len(islands)):
  189.     isles.append(Island(islefaces[i], ob))
  190.  
  191. isles.sort(key=lambda x: 1-x.bb_size)
  192. print(isles[0].bb_size)
  193.  
  194. #for i in isles:
  195. #    i.move(-1.0, 0.0)
  196.    
  197. #isles[0].move(-isles[0].minx, -isles[0].miny)
  198.  
  199. # start monte carlo iteration
  200. iters = 2000
  201. iter_div = float(iters)/1.5
  202. start_time = time.time()
  203. total_checks = 0
  204.  
  205. for p in range(len(isles)):
  206.     icnt = 0
  207.     pcnt = 0
  208.     # find a free location
  209.     for i in range(iters):
  210.         i_div = float(i)/iter_div
  211.         #isles[p].set_location(rnd()*(1.0-isles[p].bb_x)*float(i)/iter_div, rnd()*(1.0-isles[p].bb_y)*float(i)/iter_div)
  212.         if rnd() > 0.75:
  213.             isles[p].rotate90()
  214.  
  215.         if rnd() > 0.75:
  216.             isles[p].flipx()
  217.            
  218.         if rnd() > 0.5: # x or y axis
  219.             isles[p].set_location(rnd()*i_div, 1.0*i_div)
  220.         else:
  221.             isles[p].set_location(1.0*i_div, rnd()*i_div)
  222.        
  223.         somecollision = False
  224.         for tf in range(0,p):
  225.             icnt += 1
  226.             if isles[p].check_collision(isles[tf]):
  227.                 somecollision = True    
  228.          
  229.         pcnt += 1
  230.         if not somecollision:      
  231.             break
  232.     # zigzag with y and x axis towards origin until collision
  233.    
  234.     print(repr(p)+"/"+repr(len(isles))+" i:"+repr(icnt)+" p:"+repr(pcnt))
  235.     total_checks += icnt
  236.        
  237. end_time = time.time()
  238. tot_time = end_time - start_time
  239. print(repr(total_checks) + " total collision checks in " + repr(round(tot_time,2))+" seconds. (" + repr(round(float(total_checks)/tot_time, 2)) + " checks per second)")
  240.  
  241. # write data out
  242. for i in isles:
  243.     i.write()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement