def blenderstructure(self, ): for i in range(len(self.xyz.atomtypes)): me = Mesh.Primitives.Icosphere(spheresubdivisions, atomicradii[self.xyz.atomtypes[i]]) me.materials = [materials[self.xyz.atomtypes[i]]] for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, 'Mesh') obj.setLocation(self.xyz.coord[i][0], self.xyz.coord[i][1], self.xyz.coord[i][2]) for i in range(len(self.xyz.atomtypes)): for j in range(i + 1, len(self.xyz.atomtypes)): vec1 = Mathutils.Vector(self.xyz.coord[i]) vec2 = Mathutils.Vector(self.xyz.coord[j]) vec = vec2 - vec1 distcovalent = covalentradii[self.xyz.atomtypes[ i]] + covalentradii[self.xyz.atomtypes[j]] if (vec.length - distcovalent) <= 0.10 * distcovalent: me = Mesh.Primitives.Tube(32, stickradius, vec.length) for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, 'Cylinder') axis = Mathutils.CrossVecs(Vector([0, 0, 1]), vec) angle = Mathutils.AngleBetweenVecs(Vector([0, 0, 1]), vec) rotmat = Mathutils.RotationMatrix(angle, 4, "R", axis) obj.setMatrix(obj.matrix * rotmat) obj.setLocation((vec1 + vec2) * 0.5)
def terrain_clamp(event, value): sce = bpy.data.scenes.active if GLOBALS['GROUND_SOURCE'][0].val: obs_terrain = [sce.objects.active] if not obs_terrain[0]: error_noact() return else: try: obs_terrain = bpy.data.groups[ GLOBALS['GROUND_GROUP_NAME'].val].objects except: error_nogroup() return obs_clamp = [ ob for ob in sce.objects.context if ob not in obs_terrain and not ob.lib ] if not obs_clamp: error_no_obs() return terrain_tris = collect_terrain_triangles(obs_terrain) if not terrain_tris: error_noground() return if GLOBALS['DROP_AXIS'][0].val: axis = Vector(0, 0, -1) else: axis = Vector(Window.GetViewVector()) do_orient = GLOBALS['DROP_ORIENT'].val do_orient_val = GLOBALS['DROP_ORIENT_VALUE'].val / 100.0 if not do_orient_val: do_orient = False for ob in obs_clamp: loc, no = calc_drop_loc(ob, terrain_tris, axis) if loc: if do_orient: try: ang = AngleBetweenVecs(no, axis) except: ang = 0.0 if ang > 90.0: no = -no ang = 180.0 - ang if ang > 0.0001: ob_matrix = ob.matrixWorld * RotationMatrix( ang * do_orient_val, 4, 'r', axis.cross(no)) ob.setMatrix(ob_matrix) ob.loc = loc # to make the while loop exist GLOBALS['EVENT'] = EVENT_EXIT
def terrain_clamp(event, value): sce = bpy.data.scenes.active if GLOBALS["GROUND_SOURCE"][0].val: obs_terrain = [sce.objects.active] if not obs_terrain[0]: error_noact() return else: try: obs_terrain = bpy.data.groups[GLOBALS["GROUND_GROUP_NAME"].val].objects except: error_nogroup() return obs_clamp = [ob for ob in sce.objects.context if ob not in obs_terrain and not ob.lib] if not obs_clamp: error_no_obs() return terrain_tris = collect_terrain_triangles(obs_terrain) if not terrain_tris: error_noground() return if GLOBALS["DROP_AXIS"][0].val: axis = Vector(0, 0, -1) else: axis = Vector(Window.GetViewVector()) do_orient = GLOBALS["DROP_ORIENT"].val do_orient_val = GLOBALS["DROP_ORIENT_VALUE"].val / 100.0 if not do_orient_val: do_orient = False for ob in obs_clamp: loc, no = calc_drop_loc(ob, terrain_tris, axis) if loc: if do_orient: try: ang = AngleBetweenVecs(no, axis) except: ang = 0.0 if ang > 90.0: no = -no ang = 180.0 - ang if ang > 0.0001: ob_matrix = ob.matrixWorld * RotationMatrix(ang * do_orient_val, 4, "r", axis.cross(no)) ob.setMatrix(ob_matrix) ob.loc = loc # to make the while loop exist GLOBALS["EVENT"] = EVENT_EXIT
def VectoMat(vec): a3 = vec.__copy__().normalize() up = Vector(0, 0, 1) if abs(a3.dot(up)) == 1.0: up = Vector(0, 1, 0) a1 = a3.cross(up).normalize() a2 = a3.cross(a1) return Matrix([a1[0], a1[1], a1[2]], [a2[0], a2[1], a2[2]], [a3[0], a3[1], a3[2]])
def selectedVertices(object): verts = [] mat = object.getMatrix("worldspace") for v in object.getData().verts: if not v.sel: continue vec = Vector([v[0], v[1], v[2]]) vec.resize4D() vec *= mat v[0], v[1], v[2] = vec[0], vec[1], vec[2] verts.append(v) return verts
def selectedVertices(object): verts = [] mat = object.getMatrix('worldspace') for v in object.getData().verts: if not v.sel: continue vec = Vector([v[0], v[1], v[2]]) vec.resize4D() vec *= mat v[0], v[1], v[2] = vec[0], vec[1], vec[2] verts.append(v) return verts
def test_point(x0, y0, i, j): x = x0 + 0.0625 * (i + 0.5) y = y0 + 0.0625 * (j + 0.5) ray, orig = Vector(0, 0, 1), Vector(x, y, 0) for face in mesh.faces: verts = [v.co + obj_loc for v in face.verts] if Intersect(verts[0], verts[1], verts[2], ray, orig, 1) or \ ( len(face.verts) == 4 and \ Intersect(verts[0], verts[2], verts[3], ray, orig, 1) ): return True return False
def delRegion(self, img): r = self.isRegion(img) if not r: return False (n, x1, y1, width, height) = r mesh = self.obj.getData(mesh=True) panelimage = mesh.faces[0].image try: (pwidth, pheight) = panelimage.size xoff = float(x1) / pwidth yoff = float(y1) / pheight xscale = float(width) / pwidth yscale = float(height) / pheight except: xoff = yoff = 0 xscale = yscale = 1 # Reassign UV mappings back to panel image for obj in Scene.GetCurrent().objects: if obj != self.obj and obj.getType() == "Mesh": mesh2 = obj.getData(mesh=True) if mesh2.faceUV: for face in mesh2.faces: if face.image == img: face.image = panelimage face.uv = [ Vector( [xoff + v.x * xscale, yoff + v.y * yscale]) for v in face.uv ] mesh2.update() mesh.faces[n].image = panelimage img.reload() # blank old region self.obj.removeProperty('x%d' % n) self.obj.removeProperty('y%d' % n) return True
def calc_drop_loc(ob, terrain_tris, axis): pt = Vector(ob.loc) isect = None isect_best = None isect_best_no = None isect_best_len = 0.0 for t1, t2, t3, no in terrain_tris: #if Geometry.PointInTriangle2D(pt, t1,t2,t3): isect = Mathutils.Intersect(t1, t2, t3, axis, pt, 1) # 1==clip if isect: if not GLOBALS['DROP_OVERLAP_CHECK'].val: # Find the first location return isect, no else: if isect_best: isect_len = (pt - isect).length if isect_len < isect_best_len: isect_best_len = isect_len isect_best = isect isect_best_no = no else: isect_best_len = (pt - isect).length isect_best = isect isect_best_no = no return isect_best, isect_best_no
def island2Edge(island): # Vert index edges edges = {} unique_points = {} for f in island: f_uvkey = map(tuple, f.uv) for vIdx, edkey in enumerate(f.edge_keys): unique_points[f_uvkey[vIdx]] = f.uv[vIdx] if f.v[vIdx].index > f.v[vIdx - 1].index: i1 = vIdx - 1 i2 = vIdx else: i1 = vIdx i2 = vIdx - 1 try: edges[f_uvkey[i1], f_uvkey[ i2]] *= 0 # sets eny edge with more then 1 user to 0 are not returned. except: edges[f_uvkey[i1], f_uvkey[i2]] = (f.uv[i1] - f.uv[i2]).length, # If 2 are the same then they will be together, but full [a,b] order is not correct. # Sort by length length_sorted_edges = [(Vector(key[0]), Vector(key[1]), value) for key, value in edges.iteritems() if value != 0] try: length_sorted_edges.sort(key=lambda A: -A[2]) # largest first except: length_sorted_edges.sort(lambda A, B: cmp(B[2], A[2])) # Its okay to leave the length in there. #for e in length_sorted_edges: # e.pop(2) # return edges and unique points return length_sorted_edges, [ v.__copy__().resize3D() for v in unique_points.itervalues() ]
def toVector(self, n): v = [self.x, self.y] if n == 3: v.append(self.z) elif n == 4: v.extend([self.z, 1.0]) else: raise AttributeError return Vector(v)
def addRegion(self, xoff, yoff, width, height): mesh = self.obj.getData(mesh=True) panelimage = mesh.faces[0].image name = 'PanelRegion' for img in Image.get(): # try to re-use existing deleted panel region if img.size == [ width, height ] and img.source == Image.Sources.GENERATED and img.filename == name and not self.isRegion( img): break else: img = Image.New(name, width, height, 24) for y in range(height): for x in range(width): rgba = panelimage.getPixelI(xoff + x, yoff + y) if not rgba[3]: img.setPixelI(x, y, (102, 102, 255, 255)) # hilite transparent else: img.setPixelI(x, y, rgba[:3] + [255]) img.pack() for n in range(1, PanelRegionHandler.REGIONCOUNT + 1): if mesh.faces[n].image == panelimage: mesh.faces[n].image = img self.obj.addProperty('x%d' % n, xoff) self.obj.addProperty('y%d' % n, yoff) (width, height) = img.size (pwidth, pheight) = panelimage.size xoff = float(xoff) / pwidth yoff = float(yoff) / pheight xscale = float(pwidth) / width yscale = float(pheight) / height # Assign UV mappings from panel image for obj in Scene.GetCurrent().objects: if obj != self.obj and obj.getType() == "Mesh": mesh2 = obj.getData(mesh=True) if mesh2.faceUV: for face in mesh2.faces: if face.image == panelimage: uv = [] for v in face.uv: x = (v.x - xoff) * xscale y = (v.y - yoff) * yscale if not -UV.LIMIT <= x <= 1 + UV.LIMIT or not -UV.LIMIT <= y <= 1 + UV.LIMIT: break uv.append( Vector(min(max(x, 0), 1), min(max(y, 0), 1))) else: face.uv = uv face.image = img mesh2.update() break return img
def pointInIsland(pt, island): vec1 = Vector(); vec2 = Vector(); vec3 = Vector() for f in island: vec1.x, vec1.y = f.uv[0] vec2.x, vec2.y = f.uv[1] vec3.x, vec3.y = f.uv[2] if pointInTri2D(pt, vec1, vec2, vec3): return True if len(f.v) == 4: vec1.x, vec1.y = f.uv[0] vec2.x, vec2.y = f.uv[2] vec3.x, vec3.y = f.uv[3] if pointInTri2D(pt, vec1, vec2, vec3): return True return False
def to_mesh(self, name, image): self.remove_degenerate_faces() self.duplicate_verts_with_multiple_normals() mesh = Blender.Mesh.New() mesh.properties['joename'] = name mesh.verts.extend([Vector(v.co()) for v in self.verts]) # set normals for f in self.faces: for i in range(3): mesh.verts[f.vertex_index[i]].no = Vector( self.normals[f.normal_index[i]].co()) # set faces mesh.faces.extend([f.vertex_index for f in self.faces], ignoreDups=True) # set texture coordinates for i in range(len(mesh.faces)): sf = self.faces[i] mf = mesh.faces[i] # fix face indices ordering i = (0, 1, 2) if mf.v[0].index == sf.vertex_index[1]: i = (1, 2, 0) elif mf.v[0].index == sf.vertex_index[2]: i = (2, 0, 1) # set coordinates ti = sf.texture_index[i[0]], sf.texture_index[ i[1]], sf.texture_index[i[2]] uv = [ Vector(self.texcoords[ti[0]].uv()), Vector(self.texcoords[ti[1]].uv()), Vector(self.texcoords[ti[2]].uv()) ] mf.uv = uv mf.smooth = 1 if image != None: mf.image = image # add to scene scn = Blender.Scene.GetCurrent() if name: return scn.objects.new(mesh, name) else: return scn.objects.new(mesh)
def blenderstructure(self, ): nat = len(self.xyz.atomtypes) # create atoms for i in range(0, nat): loc = Mathutils.Vector(self.xyz.coord[i]) me = Mesh.Primitives.Icosphere(spheresubdivisions, atomicradii[self.xyz.atomtypes[i]]) me.materials = [materials[self.xyz.atomtypes[i]]] for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, 'Atom') obj.setLocation(loc) # form bonds between atoms for i in range(0, nat): for j in range(i + 1, nat): vec1 = Mathutils.Vector(self.xyz.coord[i]) vec2 = Mathutils.Vector(self.xyz.coord[j]) vec = vec2 - vec1 distcovalent = covalentradii[self.xyz.atomtypes[ i]] + covalentradii[self.xyz.atomtypes[j]] print "vec.length = %s distcovalent = %s" % (vec.length, distcovalent) if (vec.length - distcovalent) <= 0.10 * distcovalent: me = Mesh.Primitives.Tube(32, stickradius, vec.length) for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, 'Bond') axis = Mathutils.CrossVecs(Vector([0, 0, 1]), vec) angle = Mathutils.AngleBetweenVecs(Vector([0, 0, 1]), vec) rotmat = Mathutils.RotationMatrix(angle, 4, "R", axis) obj.setMatrix(obj.matrix * rotmat) obj.setLocation((vec1 + vec2) * 0.5) # vectors scale = 1.0 #1000.0 #1.0 #1000.0 for i in range(0, nat): loc = Mathutils.Vector(self.xyz.coord[i]) vec = Mathutils.Vector(self.xyz.vectors[i]) * scale # arrow tail me = Mesh.Primitives.Tube(32, arrowradius, vec.length) me.materials = [materials["arrow"]] for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, "Arrow-Tail") axis = Mathutils.CrossVecs(Vector([0, 0, 1]), vec) angle = Mathutils.AngleBetweenVecs(Vector([0, 0, 1]), vec) rotmat = Mathutils.RotationMatrix(angle, 4, "R", axis) obj.setMatrix(obj.matrix * rotmat) obj.setLocation(loc + 0.5 * vec) # arrow head me = Mesh.Primitives.Cone(32, 2 * arrowradius, 0.5) me.materials = [materials["arrow"]] for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, "Arrow-Head") axis = Mathutils.CrossVecs(Vector([0, 0, 1]), vec) angle = Mathutils.AngleBetweenVecs(Vector([0, 0, 1]), vec) rotmat = Mathutils.RotationMatrix(angle + 180.0, 4, "R", axis) obj.setMatrix(obj.matrix * rotmat) obj.setLocation(loc + vec)
def pointBounds(points): ''' Takes a list of points and returns the area, center, bounds ''' ymax = xmax = -BIGNUM ymin = xmin = BIGNUM for p in points: x = p.x y = p.y if x > xmax: xmax = x if y > ymax: ymax = y if x < xmin: xmin = x if y < ymin: ymin = y # area and center return\ (xmax-xmin) * (ymax-ymin),\ Vector((xmin+xmax)/2, (ymin+ymax)/2),\ (xmin, ymin, xmax, ymax)
def makeVNormal(me, vert, origEdgeLen): vNormal = Vector([0,0,0]) eIdx = 0 while eIdx < origEdgeLen: e = me.edges[eIdx] if e.v1 == vert or e.v2 == vert: pass else: eIdx+=1 continue v1 = -1 if vert == e.v1: v1 = False if vert == e.v2: v1 = 1 if v1 == -1: eIdx+=1 continue # one of the verts in the face is the same as the vert that we are finding teyh normal for. # Make a vector from the edge v1 and v2 are the indivies for this edge v2 = (not v1) ev = [e.v1, e.v2] newVec = Vector([\ ev[v1].co[0]-ev[v2].co[0],\ ev[v1].co[1]-ev[v2].co[1],\ ev[v1].co[2]-ev[v2].co[2]] ) newVec.normalize() vNormal = vNormal + newVec eIdx+=1 vNormal.normalize() return vNormal
def mergeUvIslands(islandList): global USER_FILL_HOLES global USER_FILL_HOLES_QUALITY # Pack islands to bottom LHS # Sync with island #islandTotFaceArea = [] # A list of floats, each island area #islandArea = [] # a list of tuples ( area, w,h) decoratedIslandList = [] islandIdx = len(islandList) while islandIdx: islandIdx -= 1 minx, miny, maxx, maxy = boundsIsland(islandList[islandIdx]) w, h = maxx - minx, maxy - miny totFaceArea = 0 offset = Vector(minx, miny) for f in islandList[islandIdx]: for uv in f.uv: uv -= offset totFaceArea += f.area islandBoundsArea = w * h efficiency = abs(islandBoundsArea - totFaceArea) # UV Edge list used for intersections as well as unique points. edges, uniqueEdgePoints = island2Edge(islandList[islandIdx]) decoratedIslandList.append([ islandList[islandIdx], totFaceArea, efficiency, islandBoundsArea, w, h, edges, uniqueEdgePoints ]) # Sort by island bounding box area, smallest face area first. # no.. chance that to most simple edge loop first. decoratedIslandListAreaSort = decoratedIslandList[:] try: decoratedIslandListAreaSort.sort(key=lambda A: A[3]) except: decoratedIslandListAreaSort.sort(lambda A, B: cmp(A[3], B[3])) # sort by efficiency, Least Efficient first. decoratedIslandListEfficSort = decoratedIslandList[:] # decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2])) try: decoratedIslandListEfficSort.sort(key=lambda A: -A[2]) except: decoratedIslandListEfficSort.sort(lambda A, B: cmp(B[2], A[2])) # ================================================== THESE CAN BE TWEAKED. # This is a quality value for the number of tests. # from 1 to 4, generic quality value is from 1 to 100 USER_STEP_QUALITY = ((USER_FILL_HOLES_QUALITY - 1) / 25.0) + 1 # If 100 will test as long as there is enough free space. # this is rarely enough, and testing takes a while, so lower quality speeds this up. # 1 means they have the same quality USER_FREE_SPACE_TO_TEST_QUALITY = 1 + (( (100 - USER_FILL_HOLES_QUALITY) / 100.0) * 5) #print 'USER_STEP_QUALITY', USER_STEP_QUALITY #print 'USER_FREE_SPACE_TO_TEST_QUALITY', USER_FREE_SPACE_TO_TEST_QUALITY removedCount = 0 areaIslandIdx = 0 ctrl = Window.Qual.CTRL BREAK = False while areaIslandIdx < len(decoratedIslandListAreaSort) and not BREAK: sourceIsland = decoratedIslandListAreaSort[areaIslandIdx] # Alredy packed? if not sourceIsland[0]: areaIslandIdx += 1 else: efficIslandIdx = 0 while efficIslandIdx < len( decoratedIslandListEfficSort) and not BREAK: if Window.GetKeyQualifiers() & ctrl: BREAK = True break # Now we have 2 islands, is the efficience of the islands lowers theres an # increasing likely hood that we can fit merge into the bigger UV island. # this ensures a tight fit. # Just use figures we have about user/unused area to see if they might fit. targetIsland = decoratedIslandListEfficSort[efficIslandIdx] if sourceIsland[0] == targetIsland[0] or\ not targetIsland[0] or\ not sourceIsland[0]: pass else: # ([island, totFaceArea, efficiency, islandArea, w,h]) # Waisted space on target is greater then UV bounding island area. # if targetIsland[3] > (sourceIsland[2]) and\ # # print USER_FREE_SPACE_TO_TEST_QUALITY, 'ass' if targetIsland[2] > (sourceIsland[1] * USER_FREE_SPACE_TO_TEST_QUALITY) and\ targetIsland[4] > sourceIsland[4] and\ targetIsland[5] > sourceIsland[5]: # DEBUG # print '%.10f %.10f' % (targetIsland[3], sourceIsland[1]) # These enough spare space lets move the box until it fits # How many times does the source fit into the target x/y blockTestXUnit = targetIsland[4] / sourceIsland[4] blockTestYUnit = targetIsland[5] / sourceIsland[5] boxLeft = 0 # Distllllance we can move between whilst staying inside the targets bounds. testWidth = targetIsland[4] - sourceIsland[4] testHeight = targetIsland[5] - sourceIsland[5] # Increment we move each test. x/y xIncrement = (testWidth / (blockTestXUnit * ((USER_STEP_QUALITY / 50) + 0.1))) yIncrement = (testHeight / (blockTestYUnit * ((USER_STEP_QUALITY / 50) + 0.1))) # Make sure were not moving less then a 3rg of our width/height if xIncrement < sourceIsland[4] / 3: xIncrement = sourceIsland[4] if yIncrement < sourceIsland[5] / 3: yIncrement = sourceIsland[5] boxLeft = 0 # Start 1 back so we can jump into the loop. boxBottom = 0 #-yIncrement ##testcount= 0 while boxBottom <= testHeight: # Should we use this? - not needed for now. #if Window.GetKeyQualifiers() & ctrl: # BREAK= True # break ##testcount+=1 #print 'Testing intersect' Intersect = islandIntersectUvIsland( sourceIsland, targetIsland, Vector(boxLeft, boxBottom)) #print 'Done', Intersect if Intersect == 1: # Line intersect, dont bother with this any more pass if Intersect == 2: # Source inside target ''' We have an intersection, if we are inside the target then move us 1 whole width accross, Its possible this is a bad idea since 2 skinny Angular faces could join without 1 whole move, but its a lot more optimal to speed this up since we have alredy tested for it. It gives about 10% speedup with minimal errors. ''' #print 'ass' # Move the test allong its width + SMALL_NUM #boxLeft += sourceIsland[4] + SMALL_NUM boxLeft += sourceIsland[4] elif Intersect == 0: # No intersection?? Place it. # Progress removedCount += 1 Window.DrawProgressBar( 0.0, 'Merged: %i islands, Ctrl to finish early.' % removedCount) # Move faces into new island and offset targetIsland[0].extend(sourceIsland[0]) offset = Vector(boxLeft, boxBottom) for f in sourceIsland[0]: for uv in f.uv: uv += offset sourceIsland[0][:] = [] # Empty # Move edge loop into new and offset. # targetIsland[6].extend(sourceIsland[6]) #while sourceIsland[6]: targetIsland[6].extend( [ (\ (e[0]+offset, e[1]+offset, e[2])\ ) for e in sourceIsland[6] ] ) sourceIsland[6][:] = [] # Empty # Sort by edge length, reverse so biggest are first. try: targetIsland[6].sort(key=lambda A: A[2]) except: targetIsland[6].sort( lambda B, A: cmp(A[2], B[2])) targetIsland[7].extend(sourceIsland[7]) offset = Vector(boxLeft, boxBottom, 0) for p in sourceIsland[7]: p += offset sourceIsland[7][:] = [] # Decrement the efficiency targetIsland[1] += sourceIsland[ 1] # Increment totFaceArea targetIsland[2] -= sourceIsland[ 1] # Decrement efficiency # IF we ever used these again, should set to 0, eg sourceIsland[ 2] = 0 # No area if anyone wants to know break # INCREMENR NEXT LOCATION if boxLeft > testWidth: boxBottom += yIncrement boxLeft = 0.0 else: boxLeft += xIncrement ##print testcount efficIslandIdx += 1 areaIslandIdx += 1 # Remove empty islands i = len(islandList) while i: i -= 1 if not islandList[i]: del islandList[i] # Can increment islands removed here.
def build_hierarchy(self): blmatrix = AC_TO_BLEND_MATRIX olist = self.objlist[1:] olist.reverse() scene = self.scene newlist = [] for o in olist: kids = o.kids if kids: children = newlist[-kids:] newlist = newlist[:-kids] if o.type == AC_GROUP: parent = self.found_parent(o.name, children) if parent: children.remove(parent) o.bl_obj = parent.bl_obj else: # not found, use an empty empty = scene.objects.new('Empty', o.name) o.bl_obj = empty bl_children = [c.bl_obj for c in children if c.bl_obj != None] o.bl_obj.makeParent(bl_children, 0, 1) for child in children: blob = child.bl_obj if not blob: continue if child.rot: eul = euler_in_radians(child.rot.toEuler()) blob.setEuler(eul) if child.size: blob.size = child.size if not child.loc: child.loc = Vector(0.0, 0.0, 0.0) blob.setLocation(child.loc) newlist.append(o) for o in newlist: # newlist now only has objs w/o parents blob = o.bl_obj if not blob: continue if o.size: o.bl_obj.size = o.size if not o.rot: blob.setEuler([1.5707963267948966, 0, 0]) else: matrix = o.rot * blmatrix eul = euler_in_radians(matrix.toEuler()) blob.setEuler(eul) if o.loc: o.loc *= blmatrix else: o.loc = Vector(0.0, 0.0, 0.0) blob.setLocation(o.loc) # forces DAG update, so we do it even for 0, 0, 0 # XXX important: until we fix the BPy API so it doesn't increase user count # when wrapping a Blender object, this piece of code is needed for proper # object (+ obdata) deletion in Blender: for o in self.objlist: if o.bl_obj: o.bl_obj = None
def load_md2(md2_filename, texture_filename): #read the file in file = open(md2_filename, "rb") WaitCursor(1) DrawProgressBar(0.0, 'Loading MD2') md2 = md2_obj() md2.load(file) #md2.dump() file.close() ######### Creates a new mesh mesh = Mesh.New() uv_coord = [] #uv_list=[] verts_extend = [] #load the textures to use later #-1 if there is no texture to load mesh_image = load_textures(md2, texture_filename) if mesh_image == -1 and texture_filename: print 'MD2 Import, Warning, texture "%s" could not load' ######### Make the verts DrawProgressBar(0.25, "Loading Vertex Data") frame = md2.frames[0] scale = g_scale.val def tmp_get_vertex(i): #use the first frame for the mesh vertices x = (frame.scale[0] * frame.vertices[i].vertices[0] + frame.translate[0]) * scale y = (frame.scale[1] * frame.vertices[i].vertices[1] + frame.translate[1]) * scale z = (frame.scale[2] * frame.vertices[i].vertices[2] + frame.translate[2]) * scale return y, -x, z mesh.verts.extend([tmp_get_vertex(i) for i in xrange(0, md2.num_vertices)]) del tmp_get_vertex ######## Make the UV list DrawProgressBar(0.50, "Loading UV Data") w = float(md2.skin_width) h = float(md2.skin_height) if w <= 0.0: w = 1.0 if h <= 0.0: h = 1.0 #for some reason quake2 texture maps are upside down, flip that uv_list = [Vector(co.u / w, 1 - (co.v / h)) for co in md2.tex_coords] del w, h ######### Make the faces DrawProgressBar(0.75, "Loading Face Data") faces = [] face_uvs = [] for md2_face in md2.faces: f = md2_face.vertex_index[0], md2_face.vertex_index[ 2], md2_face.vertex_index[1] uv = uv_list[md2_face.texture_index[0]], uv_list[ md2_face.texture_index[2]], uv_list[md2_face.texture_index[1]] if f[2] == 0: # EEKADOODLE :/ f = f[1], f[2], f[0] uv = uv[1], uv[2], uv[0] #ditto in reverse order with the texture verts faces.append(f) face_uvs.append(uv) face_mapping = mesh.faces.extend(faces, indexList=True) print len(faces) print len(mesh.faces) mesh.faceUV = True #turn on face UV coordinates for this mesh mesh_faces = mesh.faces for i, uv in enumerate(face_uvs): if face_mapping[i] != None: f = mesh_faces[face_mapping[i]] f.uv = uv if (mesh_image != -1): f.image = mesh_image scn = Blender.Scene.GetCurrent() mesh_obj = scn.objects.new(mesh) animate_md2(md2, mesh) DrawProgressBar(0.98, "Loading Animation Data") #locate the Object containing the mesh at the cursor location cursor_pos = Blender.Window.GetCursorPos() mesh_obj.setLocation(float(cursor_pos[0]), float(cursor_pos[1]), float(cursor_pos[2])) DrawProgressBar(1.0, "") WaitCursor(0)
def pointInIsland(pt, island): vec1 = Vector() vec2 = Vector() vec3 = Vector() for f in island: vec1.x, vec1.y = f.uv[0] vec2.x, vec2.y = f.uv[1] vec3.x, vec3.y = f.uv[2] if pointInTri2D(pt, vec1, vec2, vec3): return True if len(f.v) == 4: vec1.x, vec1.y = f.uv[0] vec2.x, vec2.y = f.uv[2] vec3.x, vec3.y = f.uv[3] if pointInTri2D(pt, vec1, vec2, vec3): return True return False
for i in items: path=i[3].split('/')[:-1] extend_pop_for(pop_list,path) if len(path): append_to_inner(pop_list,(i[3].split('/')[-1],items.index(i))) else: pop_list.append((i[3].split('/')[-1],items.index(i))) r = Draw.PupTreeMenu(pop_list) if r >= 0: print items[r] set_pref_key('xplane.tools','annotate.last_item',items[r]) cur = Window.GetCursorPos() mm = TranslationMatrix(Vector([0,0,0])).resize4x4() #mm = TranslationMatrix(Vector(Window.GetCursorPos())).resize4x4() importer=OBJimport(items[r][1],mm) importer.verbose=1 try: sel = Blender.Scene.GetCurrent().objects.selected old_objs = set(Blender.Scene.GetCurrent().objects) obj_list = importer.doimport() new_objs = set(Blender.Scene.GetCurrent().objects) wrapper=Blender.Object.New('Empty','OBJ%s' % items[r][0].split('/')[-1]) Blender.Scene.GetCurrent().objects.link(wrapper) added = new_objs-old_objs wrapper.makeParent(list(added),1,0) if len(sel) == 1: sel[0].makeParent([wrapper],1,0) base = sel[0].getLocation('worldspace')
def readDSF(path): baddsf=(0, "Invalid DSF file", path) h=file(path, 'rb') h.seek(0, 2) hlen=h.tell() h.seek(0, 0) if h.read(8)!='XPLNEDSF' or unpack('<I',h.read(4))!=(1,) or h.read(4)!='DAEH': raise IOError, baddsf (l,)=unpack('<I', h.read(4)) headend=h.tell()+l-8 if h.read(4)!='PORP': raise IOError, baddsf (l,)=unpack('<I', h.read(4)) properties=[] c=h.read(l-9).split('\0') h.read(1) overlay=0 for i in range(0, len(c)-1, 2): if c[i]=='sim/overlay': overlay=int(c[i+1]) elif c[i]=='sim/south': lat=int(c[i+1]) elif c[i]=='sim/west': lon=int(c[i+1]) properties.append((c[i],c[i+1])) h.seek(headend) if overlay: # Overlay DSF - bail early h.close() raise IOError, (0, "This is an overlay DSF", path) # Definitions Atom if h.read(4)!='NFED': raise IOError, baddsf (l,)=unpack('<I', h.read(4)) defnend=h.tell()+l-8 terrain=objects=polygons=network=[] while h.tell()<defnend: c=h.read(4) (l,)=unpack('<I', h.read(4)) if l==8: pass # empty elif c=='TRET': terrain=h.read(l-9).replace('\\','/').replace(':','/').split('\0') h.read(1) elif c=='TJBO': objects=h.read(l-9).replace('\\','/').replace(':','/').split('\0') h.read(1) elif c=='YLOP': polygons=h.read(l-9).replace('\\','/').replace(':','/').split('\0') h.read(1) elif c=='WTEN': networks=h.read(l-9).replace('\\','/').replace(':','/').split('\0') h.read(1) else: h.seek(l-8, 1) # Geodata Atom if h.read(4)!='DOEG': raise IOError, baddsf (l,)=unpack('<I', h.read(4)) geodend=h.tell()+l-8 pool=[] scal=[] while h.tell()<geodend: c=h.read(4) (l,)=unpack('<I', h.read(4)) if c=='LOOP': thispool=[] (n,)=unpack('<I', h.read(4)) (p,)=unpack('<B', h.read(1)) for i in range(p): thisplane=[] (e,)=unpack('<B', h.read(1)) if e==0 or e==1: last=0 for j in range(n): (d,)=unpack('<H', h.read(2)) if e==1: d=(last+d)&65535 thisplane.append(d) last=d elif e==2 or e==3: last=0 while(len(thisplane))<n: (r,)=unpack('<B', h.read(1)) if (r&128): (d,)=unpack('<H', h.read(2)) for j in range(r&127): if e==3: thisplane.append((last+d)&65535) last=(last+d)&65535 else: thisplane.append(d) else: for j in range(r): (d,)=unpack('<H', h.read(2)) if e==3: d=(last+d)&65535 thisplane.append(d) last=d else: raise IOError, baddsf thispool.append(thisplane) pool.append(thispool) elif c=='LACS': thisscal=[] for i in range(0, l-8, 8): d=unpack('<2f', h.read(8)) thisscal.append(d) scal.append(thisscal) else: h.seek(l-8, 1) # Rescale pool and transform to one list per entry if len(scal)!=len(pool): raise(IOError) newpool=[] for i in range(len(pool)): curpool=pool[i] n=len(curpool[0]) newpool=[[] for j in range(n)] for plane in range(len(curpool)): (scale,offset)=scal[i][plane] scale=scale/65535 for j in range(n): newpool[j].append(curpool[plane][j]*scale+offset) pool[i]=newpool # Commands Atom if h.read(4)!='SDMC': raise IOError, baddsf (l,)=unpack('<I', h.read(4)) cmdsend=h.tell()+l-8 curpool=0 idx=0 near=0 far=-1 flags=0 # 0=physical, 1=overlay f=[[[],[]] for i in range(len(terrain))] v=[[[],[]] for i in range(len(terrain))] t=[[[],[]] for i in range(len(terrain))] pscale=99.0/(hlen-geodend) progress=0 while h.tell()<cmdsend: now=int((h.tell()-geodend)*pscale) if progress!=now: progress=now Window.DrawProgressBar(progress/100.0, "Importing %2d%%"%progress) (c,)=unpack('<B', h.read(1)) if c==1: # Coordinate Pool Select (curpool,)=unpack('<H', h.read(2)) elif c==2: # Junction Offset Select h.read(4) # not implemented elif c==3: # Set Definition (idx,)=unpack('<B', h.read(1)) elif c==4: # Set Definition (idx,)=unpack('<H', h.read(2)) elif c==5: # Set Definition (idx,)=unpack('<I', h.read(4)) elif c==6: # Set Road Subtype h.read(1) # not implemented elif c==7: # Object h.read(2) # not implemented elif c==8: # Object Range h.read(4) # not implemented elif c==9: # Network Chain (l,)=unpack('<B', h.read(1)) h.read(l*2) # not implemented elif c==10: # Network Chain Range h.read(4) # not implemented elif c==11: # Network Chain (l,)=unpack('<B', h.read(1)) h.read(l*4) # not implemented elif c==12: # Polygon (param,l)=unpack('<HB', h.read(3)) h.read(l*2) # not implemented elif c==13: # Polygon Range (DSF2Text uses this one) (param,first,last)=unpack('<HHH', h.read(6)) # not implemented elif c==14: # Nested Polygon (param,n)=unpack('<HB', h.read(3)) for i in range(n): (l,)=unpack('<B', h.read(1)) h.read(l*2) # not implemented elif c==15: # Nested Polygon Range (DSF2Text uses this one too) (param,n)=unpack('<HB', h.read(3)) h.read((n+1)*2) # not implemented elif c==16: # Terrain Patch pass elif c==17: # Terrain Patch w/ flags (flags,)=unpack('<B', h.read(1)) flags-=1 elif c==18: # Terrain Patch w/ flags & LOD (flags,near,far)=unpack('<Bff', h.read(9)) flags-=1 elif c==23: # Patch Triangle (l,)=unpack('<B', h.read(1)) n=len(v[idx][flags]) for i in range(n,n+l,3): f[idx][flags].append([i+2,i+1,i]) for i in range(l): (d,)=unpack('<H', h.read(2)) p=pool[curpool][d] v[idx][flags].append([(p[0]-lon)*hscale, (p[1]-lat)*hscale, p[2]*vscale]) if len(p)>=7: t[idx][flags].append([p[5],p[6]]) elif c==24: # Patch Triangle - cross-pool (l,)=unpack('<B', h.read(1)) n=len(v[idx][flags]) for i in range(n,n+l,3): f[idx][flags].append([i+2,i+1,i]) for i in range(l): (c,d)=unpack('<HH', h.read(4)) p=pool[c][d] v[idx][flags].append([(p[0]-lon)*hscale, (p[1]-lat)*hscale, p[2]*vscale]) if len(p)>=7: t[idx][flags].append([p[5],p[6]]) elif c==25: # Patch Triangle Range (first,last)=unpack('<HH', h.read(4)) n=len(v[idx][flags]) for i in range(n,n+last-first,3): f[idx][flags].append([i+2,i+1,i]) for d in range(first,last): p=pool[curpool][d] v[idx][flags].append([(p[0]-lon)*hscale, (p[1]-lat)*hscale, p[2]*vscale]) if len(p)>=7: t[idx][flags].append([p[5],p[6]]) #elif c==26: # Patch Triangle Strip (not used by DSF2Text) #elif c==27: #elif c==28: elif c==29: # Patch Triangle Fan (l,)=unpack('<B', h.read(1)) n=len(v[idx][flags]) for i in range(1,l-1): f[idx][flags].append([n+i+1,n+i,n]) for i in range(l): (d,)=unpack('<H', h.read(2)) p=pool[curpool][d] v[idx][flags].append([(p[0]-lon)*hscale, (p[1]-lat)*hscale, p[2]*vscale]) if len(p)>=7: t[idx][flags].append([p[5],p[6]]) elif c==30: # Patch Triangle Fan - cross-pool (l,)=unpack('<B', h.read(1)) n=len(v[idx][flags]) for i in range(1,l-1): f[idx][flags].append([n+i+1,n+i,n]) for i in range(l): (c,d)=unpack('<HH', h.read(4)) p=pool[c][d] v[idx][flags].append([(p[0]-lon)*hscale, (p[1]-lat)*hscale, p[2]*vscale]) if len(p)>=7: t[idx][flags].append([p[5],p[6]]) elif c==31: # Patch Triangle Fan Range (first,last)=unpack('<HH', h.read(4)) n=len(v[idx][flags]) for i in range(1,last-first-1): f[idx][flags].append([n+i+1,n+i,n]) for d in range(first, last): p=pool[curpool][d] v[idx][flags].append([(p[0]-lon)*hscale, (p[1]-lat)*hscale, p[2]*vscale]) if len(p)>=7: t[idx][flags].append([p[5],p[6]]) elif c==32: # Comment (l,)=unpack('<B', h.read(1)) h.read(l) elif c==33: # Comment (l,)=unpack('<H', h.read(2)) h.read(l) elif c==34: # Comment (l,)=unpack('<I', h.read(4)) h.read(l) else: raise IOError, (c, "Unrecognised command (%d)" % c, c) h.close() Window.DrawProgressBar(0.99, "Realising") scene=Scene.GetCurrent() scene.layers=[1,2] for flags in [0]:# was [1,0]: # overlay first so overlays for idx in range(len(terrain)): if not f[idx][flags]: continue if idx: name=basename(terrain[idx])[:-4] if flags: name=name+'.2' if terrain[idx] in libterrain: (texture, angle, xscale, zscale)=readTER(libterrain[terrain[idx]]) elif exists(join(dirname(path), pardir, pardir, terrain[idx])): (texture, angle, xscale, zscale)=readTER(abspath(join(dirname(path), pardir, pardir, terrain[idx]))) else: raise IOError(0, 'Terrain %s not found' % terrain[idx], terrain[idx]) try: mat=Material.Get(name) except: mat=Material.New(name) mat.rgbCol=[1.0, 1.0, 1.0] mat.spec=0 try: img=Image.Get(basename(texture)) except: img=Image.Load(texture) tex=Texture.New(name) tex.setType('Image') tex.image=img mat.setTexture(0, tex) if flags: mat.zOffset=1 mat.mode |= Material.Modes.ZTRANSP mtex=mat.getTextures()[0] mtex.size=(xscale*250, zscale*250, 0) mtex.zproj=Texture.Proj.NONE if t[idx][flags]: mtex.texco=Texture.TexCo.UV else: mtex.texco=Texture.TexCo.GLOB else: name=terrain[idx] mat=Material.New(terrain[idx]) mat.rgbCol=[0.1, 0.1, 0.2] mat.spec=0 mesh=Mesh.New(name) mesh.mode &= ~(Mesh.Modes.TWOSIDED|Mesh.Modes.AUTOSMOOTH) mesh.mode |= Mesh.Modes.NOVNORMALSFLIP mesh.materials += [mat] mesh.verts.extend(v[idx][flags]) mesh.faces.extend(f[idx][flags]) if t[idx][flags]: faceno=0 for face in mesh.faces: face.uv=[Vector(t[idx][flags][i][0], t[idx][flags][i][1]) for i in f[idx][flags][faceno]] face.image=img faceno+=1 mesh.update() ob = Object.New("Mesh", name) ob.link(mesh) scene.objects.link(ob) ob.Layer=flags+1 ob.addProperty('terrain', terrain[idx]) mesh.sel=True mesh.remDoubles(0.001) # must be after linked to object mesh.sel=False if 0: # Unreliable for face in mesh.faces: for v in face.verts: if v.co[2]!=0.0: break else: face.mat=1 # water lamp=Lamp.New("Lamp", "Sun") ob = Object.New("Lamp", "Sun") ob.link(lamp) scene.objects.link(ob) lamp.type=1 ob.Layer=3 ob.setLocation(500, 500, 1000)
def animatedensity(self, filenamelist, renderingpath, isovalue): context = self.scene.getRenderingContext() context.extensions = True context.renderPath = renderingpath #context.imageType=Render.JPEG context.sFrame = 1 context.eFrame = 1 context.sizeX = width context.sizeY = height cubeobject = cube(filenamelist[0]) cubeobject.readCube() atoms = [] ipokeytypeloc = Object.IpoKeyTypes.LOC ipokeytyperot = Object.IpoKeyTypes.ROT for i in range(len(cubeobject.atomtypes)): me = Mesh.Primitives.Icosphere( spheresubdivisions, atomicradii.get(cubeobject.atomtypes[i], 2.0)) me.materials = [ materials.get(cubeobject.atomtypes[i], materials["default"]) ] for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, 'Atom') obj.setLocation(cubeobject.coord[i][0], cubeobject.coord[i][1], cubeobject.coord[i][2]) atoms.append(obj) bonds = [] for i in range(len(cubeobject.atomtypes)): for j in range(i + 1, len(cubeobject.atomtypes)): vec1 = Mathutils.Vector(cubeobject.coord[i]) vec2 = Mathutils.Vector(cubeobject.coord[j]) vec = vec2 - vec1 distcovalent = covalentradii.get( cubeobject.atomtypes[i], 2.0) + covalentradii.get( cubeobject.atomtypes[j], 2.0) if (vec.length - distcovalent) <= 0.10 * distcovalent: me = Mesh.Primitives.Tube(32, stickradius, vec.length) for face in me.faces: face.smooth = True obj = self.scene.objects.new(me, 'Cylinder') axis = Mathutils.CrossVecs(Vector([0, 0, 1]), vec) angle = Mathutils.AngleBetweenVecs(Vector([0, 0, 1]), vec) rotmat = Mathutils.RotationMatrix(angle, 4, "R", axis) obj.setMatrix(obj.matrix * rotmat) obj.setLocation((vec1 + vec2) * 0.5) bonds.append([i, j, vec, obj, vec.length]) self.isosurface(cubeobject, isovalue) context.render() filename = "RENDER/image_0000.jpg" context.saveRenderedImage(filename) for j in range(1, len(filenamelist)): print(("Rendering:", j)) filename = "RENDER/image_%04d.jpg" % (j) for ob in self.scene.objects: if "Lobe" in ob.name: self.scene.unlink(ob) cubeobject = cube(filenamelist[j]) cubeobject.readCube() for i in range(len(atoms)): atoms[i].setLocation(cubeobject.coord[i][0], cubeobject.coord[i][1], cubeobject.coord[i][2]) atoms[i].insertIpoKey(ipokeytypeloc) for i in range(len(bonds)): vec1 = Mathutils.Vector(cubeobject.coord[bonds[i][0]]) vec2 = Mathutils.Vector(cubeobject.coord[bonds[i][1]]) vec = vec2 - vec1 dist = vec.length axis = Mathutils.CrossVecs(bonds[i][2], vec) angle = Mathutils.AngleBetweenVecs(bonds[i][2], vec) rotmat = Mathutils.RotationMatrix(angle, 4, "R", axis) bonds[i][3].setMatrix(bonds[i][3].matrix * rotmat) bonds[i][3].setLocation((vec1 + vec2) * 0.5) bonds[i][3].setSize(1.0, 1.0, dist / bonds[i][4]) bonds[i][3].insertIpoKey(ipokeytypeloc) bonds[i][3].insertIpoKey(ipokeytyperot) bonds[i][2] = vec bonds[i][4] = dist self.isosurface(cubeobject, isovalue) context.render() context.saveRenderedImage(filename)
def wireMesh(me): globalSize = Draw.PupFloatInput('wire width', 0.1, -10.0, 10.0, 0.01, 4) if globalSize == None: return globalHalfsz =globalSize/2 ratio = Draw.PupMenu('Edge Width%t|Fixed Width|Scale with edge len') normalMethod = Draw.PupMenu('Use Normal%t|Vertex Normal|Edge Normal') if ratio == -1 or normalMethod == -1: return t = sys.time() origEdgeLen = len(me.edges) origFaceLen = len(me.faces) eIdx = 0 while eIdx < origEdgeLen: e = me.edges[eIdx] if not e.flag & NMesh.EdgeFlags['SELECT']: eIdx+=1 continue if ratio == 1: size = globalSize halfsz = globalHalfsz else: size = globalSize * measure(e.v1, e.v2) halfsz = size/2 if normalMethod == 1: # vertex normal v1nor = makeVNormal(me, e.v1, origEdgeLen) v2nor = makeVNormal(me, e.v2, origEdgeLen) newPt1 = Vector( e.v1.co[0] + (v1nor[0]*size), e.v1.co[1] + (v1nor[1]*size), e.v1.co[2] + (v1nor[2]*size) ) newPt2 = Vector( e.v2.co[0] + (v2nor[0]*size), e.v2.co[1] + (v2nor[1]*size), e.v2.co[2] + (v2nor[2]*size) ) if normalMethod == 2: # Face Normal edgeNormal = Vector([e.v1.no[0] + e.v2.no[0], e.v1.no[1]+e.v2.no[1], e.v1.no[2]+e.v2.no[2] ]) edgeNormal.normalize() newPt1 = Vector( e.v1.co[0] + (edgeNormal[0]*size), e.v1.co[1] + (edgeNormal[1]*size), e.v1.co[2] + (edgeNormal[2]*size) ) newPt2 = Vector( e.v2.co[0] + (edgeNormal[0]*size), e.v2.co[1] + (edgeNormal[1]*size), e.v2.co[2] + (edgeNormal[2]*size) ) # #~ newPt1************newPt2 # #~ * * # #~ * * # #~ * * # #~ ****vert1**************Vert2**** * * * * norA = TriangleNormal(e.v1.co, e.v2.co, newPt1) norB = TriangleNormal(e.v2.co, newPt2, newPt1) nor1 = norA + norB nor1.normalize() # make face A me.verts.append(NMesh.Vert(e.v1.co[0] + (nor1[0]*halfsz), e.v1.co[1] + (nor1[1]*halfsz), e.v1.co[2] + (nor1[2]*halfsz)) ) me.verts.append(NMesh.Vert(e.v2.co[0] + (nor1[0]*halfsz), e.v2.co[1] + (nor1[1]*halfsz), e.v2.co[2] + (nor1[2]*halfsz)) ) me.verts.append(NMesh.Vert(newPt2[0] + (nor1[0]*halfsz), newPt2[1] + (nor1[1]*halfsz), newPt2[2] + (nor1[2]*halfsz)) ) me.verts.append(NMesh.Vert(newPt1[0] + (nor1[0]*halfsz), newPt1[1] + (nor1[1]*halfsz), newPt1[2] + (nor1[2]*halfsz)) ) fA = NMesh.Face(me.verts[-4:]) # make face B me.verts.append(NMesh.Vert(e.v1.co[0] + (nor1[0]*-halfsz), e.v1.co[1] + (nor1[1]*-halfsz), e.v1.co[2] + (nor1[2]*-halfsz)) ) me.verts.append(NMesh.Vert(e.v2.co[0] + (nor1[0]*-halfsz), e.v2.co[1] + (nor1[1]*-halfsz), e.v2.co[2] + (nor1[2]*-halfsz)) ) me.verts.append(NMesh.Vert(newPt2[0] + (nor1[0]*-halfsz), newPt2[1] + (nor1[1]*-halfsz), newPt2[2] + (nor1[2]*-halfsz)) ) me.verts.append(NMesh.Vert(newPt1[0] + (nor1[0]*-halfsz), newPt1[1] + (nor1[1]*-halfsz), newPt1[2] + (nor1[2]*-halfsz)) ) fB = NMesh.Face([me.verts[-1], me.verts[-2], me.verts[-3], me.verts[-4]]) # make face C- top fC = NMesh.Face([fB.v[1], fB.v[0], fA.v[3], fA.v[2]]) # make face D- bottom fD = NMesh.Face([fA.v[1], fA.v[0], fB.v[3], fB.v[2]]) # a negative number is used for an inset wire- this flips the normals the wrong way- For easyness this is a simple way to fix the problem. if globalSize < 0: fA.v.reverse() fB.v.reverse() fC.v.reverse() fD.v.reverse() me.faces.extend([fA, fB, fC, fD]) eIdx+=1 print 'Wire Time: %.6f' % (sys.time()-t)
def docyl(S, R, P0, P1): coords = [] p0 = Vector(P0[0], P0[1], P0[2]) p1 = Vector(P1[0], P1[1], P1[2]) t = Vector(P1[0] - P0[0], P1[1] - P0[1], P1[2] - P0[2]) t.normalize() if t * Vector(1, 0, 0) < 0.8: n = Vector(1, 0, 0) - (Vector(1, 0, 0) * t) * t else: n = Vector(0, 1, 0) - (Vector(0, 1, 0) * t) * t n.normalize() b = Vector(t[1] * n[2] - t[2] * n[1], t[2] * n[0] - t[0] * n[2], t[0] * n[1] - t[1] * n[0]) b.normalize() for i in xrange(S): angle = float(i) * 2. * pi / float(S) vec = cos(angle) * R * n + sin(angle) * R * b c0 = p0 + vec c1 = p1 + vec coords += [[c0[0], c0[1], c0[2]]] coords += [[c1[0], c1[1], c1[2]]] faces = [] for i in xrange(S): faces += [[ 2 * i, (2 * i + 1) % (2 * S), (2 * i + 3) % (2 * S), (2 * i + 2) % (2 * S) ]] me = Mesh.New('Strut') me.verts.extend(coords) me.faces.extend(faces) return Scene.GetCurrent().objects.new(me)
def uvcalc_main(obList): global USER_FILL_HOLES global USER_FILL_HOLES_QUALITY global USER_STRETCH_ASPECT global USER_ISLAND_MARGIN # objects= bpy.data.scenes.active.objects # we can will tag them later. # obList = [ob for ob in objects.context if ob.type == 'Mesh'] # Face select object may not be selected. # ob = objects.active # if ob and ob.sel == 0 and ob.type == 'Mesh': # # Add to the list # obList =[ob] # del objects if not obList: Draw.PupMenu("error, no selected mesh objects") return # Create the variables. USER_PROJECTION_LIMIT = Draw.Create(66) USER_ONLY_SELECTED_FACES = Draw.Create(1) USER_SHARE_SPACE = Draw.Create(1) # Only for hole filling. USER_STRETCH_ASPECT = Draw.Create(1) # Only for hole filling. USER_ISLAND_MARGIN = Draw.Create(0.0) # Only for hole filling. USER_FILL_HOLES = Draw.Create(0) USER_FILL_HOLES_QUALITY = Draw.Create(50) # Only for hole filling. USER_VIEW_INIT = Draw.Create(0) # Only for hole filling. USER_AREA_WEIGHT = Draw.Create(1) # Only for hole filling. pup_block = [ "Projection", ("Angle Limit:", USER_PROJECTION_LIMIT, 1, 89, "lower for more projection groups, higher for less distortion."), ("Selected Faces Only", USER_ONLY_SELECTED_FACES, "Use only selected faces from all selected meshes."), ("Init from view", USER_VIEW_INIT, "The first projection will be from the view vector."), ("Area Weight", USER_AREA_WEIGHT, "Weight projections vector by face area."), "", "", "", "UV Layout", ("Share Tex Space", USER_SHARE_SPACE, "Objects Share texture space, map all objects into 1 uvmap."), ("Stretch to bounds", USER_STRETCH_ASPECT, "Stretch the final output to texture bounds."), ("Island Margin:", USER_ISLAND_MARGIN, 0.0, 0.5, "Margin to reduce bleed from adjacent islands."), "Fill in empty areas", ("Fill Holes", USER_FILL_HOLES, "Fill in empty areas reduced texture waistage (slow)."), ( "Fill Quality:", USER_FILL_HOLES_QUALITY, 1, 100, "Depends on fill holes, how tightly to fill UV holes, (higher is slower)", ), ] # Reuse variable if len(obList) == 1: ob = "Unwrap %i Selected Mesh" else: ob = "Unwrap %i Selected Meshes" # if not Draw.PupBlock(ob % len(obList), pup_block): # return # del ob # Convert from being button types USER_PROJECTION_LIMIT = USER_PROJECTION_LIMIT.val USER_ONLY_SELECTED_FACES = USER_ONLY_SELECTED_FACES.val USER_SHARE_SPACE = USER_SHARE_SPACE.val USER_STRETCH_ASPECT = USER_STRETCH_ASPECT.val USER_ISLAND_MARGIN = USER_ISLAND_MARGIN.val USER_FILL_HOLES = USER_FILL_HOLES.val USER_FILL_HOLES_QUALITY = USER_FILL_HOLES_QUALITY.val USER_VIEW_INIT = USER_VIEW_INIT.val USER_AREA_WEIGHT = USER_AREA_WEIGHT.val USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) USER_PROJECTION_LIMIT_HALF_CONVERTED = cos((USER_PROJECTION_LIMIT / 2) * DEG_TO_RAD) # Toggle Edit mode # is_editmode = Window.EditMode() # if is_editmode: # Window.EditMode(0) # Assume face select mode! an annoying hack to toggle face select mode because Mesh dosent like faceSelectMode. if USER_SHARE_SPACE: # Sort by data name so we get consistant results try: obList.sort(key=lambda ob: ob.getData(name_only=1)) except: obList.sort(lambda ob1, ob2: cmp(ob1.getData(name_only=1), ob2.getData(name_only=1))) collected_islandList = [] # Window.WaitCursor(1) time1 = sys.time() # Tag as False se we dont operate on teh same mesh twice. bpy.data.meshes.tag = False for ob in obList: me = ob.getData(mesh=1) if me.tag or me.lib: continue # Tag as used me.tag = True if not me.faceUV: # Mesh has no UV Coords, dont bother. me.faceUV = True if USER_ONLY_SELECTED_FACES: meshFaces = [thickface(f) for f in me.faces if f.sel] else: meshFaces = map(thickface, me.faces) if not meshFaces: continue # Window.DrawProgressBar(0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces))) # ======= # Generate a projection list from face normals, this is ment to be smart :) # make a list of face props that are in sync with meshFaces # Make a Face List that is sorted by area. # meshFaces = [] # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. try: meshFaces.sort(key=lambda a: -a.area) except: meshFaces.sort(lambda a, b: cmp(b.area, a.area)) # remove all zero area faces while meshFaces and meshFaces[-1].area <= SMALL_NUM: # Set their UV's to 0,0 for uv in meshFaces[-1].uv: uv.zero() meshFaces.pop() # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data. # Generate Projection Vecs # 0d is 1.0 # 180 IS -0.59846 # Initialize projectVecs if USER_VIEW_INIT: # Generate Projection projectVecs = [ Vector(Window.GetViewVector()) * ob.matrixWorld.copy().invert().rotationPart() ] # We add to this allong the way else: projectVecs = [] newProjectVec = meshFaces[0].no newProjectMeshFaces = [] # Popping stuffs it up. # Predent that the most unique angke is ages away to start the loop off mostUniqueAngle = -1.0 # This is popped tempMeshFaces = meshFaces[:] # This while only gathers projection vecs, faces are assigned later on. while 1: # If theres none there then start with the largest face # add all the faces that are close. for fIdx in xrange(len(tempMeshFaces) - 1, -1, -1): # Use half the angle limit so we dont overweight faces towards this # normal and hog all the faces. if newProjectVec.dot(tempMeshFaces[fIdx].no) > USER_PROJECTION_LIMIT_HALF_CONVERTED: newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) # Add the average of all these faces normals as a projectionVec averageVec = Vector(0, 0, 0) if USER_AREA_WEIGHT: for fprop in newProjectMeshFaces: averageVec += fprop.no * fprop.area else: for fprop in newProjectMeshFaces: averageVec += fprop.no if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN projectVecs.append(averageVec.normalize()) # Get the next vec! # Pick the face thats most different to all existing angles :) mostUniqueAngle = 1.0 # 1.0 is 0d. no difference. mostUniqueIndex = 0 # dummy for fIdx in xrange(len(tempMeshFaces) - 1, -1, -1): angleDifference = -1.0 # 180d difference. # Get the closest vec angle we are to. for p in projectVecs: temp_angle_diff = p.dot(tempMeshFaces[fIdx].no) if angleDifference < temp_angle_diff: angleDifference = temp_angle_diff if angleDifference < mostUniqueAngle: # We have a new most different angle mostUniqueIndex = fIdx mostUniqueAngle = angleDifference if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: # print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) # Now weight the vector to all its faces, will give a more direct projection # if the face its self was not representive of the normal from surrounding faces. newProjectVec = tempMeshFaces[mostUniqueIndex].no newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] else: if len(projectVecs) >= 1: # Must have at least 2 projections break # If there are only zero area faces then its possible # there are no projectionVecs if not len(projectVecs): Draw.PupMenu("error, no projection vecs where generated, 0 area faces can cause this.") return faceProjectionGroupList = [[] for i in xrange(len(projectVecs))] # MAP and Arrange # We know there are 3 or 4 faces here for fIdx in xrange(len(meshFaces) - 1, -1, -1): fvec = meshFaces[fIdx].no i = len(projectVecs) # Initialize first bestAng = fvec.dot(projectVecs[0]) bestAngIdx = 0 # Cycle through the remaining, first alredy done while i - 1: i -= 1 newAng = fvec.dot(projectVecs[i]) if newAng > bestAng: # Reverse logic for dotvecs bestAng = newAng bestAngIdx = i # Store the area for later use. faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) # Cull faceProjectionGroupList, # Now faceProjectionGroupList is full of faces that face match the project Vecs list for i in xrange(len(projectVecs)): # Account for projectVecs having no faces. if not faceProjectionGroupList[i]: continue # Make a projection matrix from a unit length vector. MatProj = VectoMat(projectVecs[i]) # Get the faces UV's from the projected vertex. for f in faceProjectionGroupList[i]: f_uv = f.uv for j, v in enumerate(f.v): f_uv[j][:] = (MatProj * v.co)[:2] if USER_SHARE_SPACE: # Should we collect and pack later? islandList = getUvIslands(faceProjectionGroupList, me) collected_islandList.extend(islandList) else: # Should we pack the islands for this 1 object? islandList = getUvIslands(faceProjectionGroupList, me) packIslands(islandList) # update the mesh here if we need to. # We want to pack all in 1 go, so pack now if USER_SHARE_SPACE: # Window.DrawProgressBar(0.9, "Box Packing for all objects...") packIslands(collected_islandList) print "Smart Projection time: %.2f" % (sys.time() - time1)
def makeMeshMaterialCopy(matName, faces): ''' Make a new mesh with only face the faces that use this material. faces can be any iterable object - containing ints. ''' faceVertUsers = [False] * len(myContextMesh_vertls) ok=0 for fIdx in faces: for vindex in myContextMesh_facels[fIdx]: faceVertUsers[vindex] = True if matName != None: # if matName is none then this is a set(), meaning we are using the untextured faces and do not need to store textured faces. materialFaces.add(fIdx) ok=1 if not ok: return myVertMapping = {} vertMappingIndex = 0 vertsToUse = [i for i in xrange(len(myContextMesh_vertls)) if faceVertUsers[i]] myVertMapping = dict( [ (ii, i) for i, ii in enumerate(vertsToUse) ] ) tempName= '%s_%s' % (contextObName, matName) # matName may be None. bmesh = bpy.data.meshes.new(tempName) if matName == None: img= None else: bmat = MATDICT[matName][1] bmesh.materials= [bmat] try: img= TEXTURE_DICT[bmat.name] except: img= None bmesh_verts = bmesh.verts bmesh_verts.extend( [Vector()] ) bmesh_verts.extend( [myContextMesh_vertls[i] for i in vertsToUse] ) # +1 because of DUMMYVERT face_mapping= bmesh.faces.extend( [ [ bmesh_verts[ myVertMapping[vindex]+1] for vindex in myContextMesh_facels[fIdx]] for fIdx in faces ], indexList=True ) if bmesh.faces and (contextMeshUV or img): bmesh.faceUV= 1 for ii, i in enumerate(faces): # Mapped index- faces may have not been added- if so, then map to the correct index # BUGGY API - face_mapping is not always the right length map_index= face_mapping[ii] if map_index != None: targetFace= bmesh.faces[map_index] if contextMeshUV: # v.index-1 because of the DUMMYVERT targetFace.uv= [contextMeshUV[vindex] for vindex in myContextMesh_facels[i]] if img: targetFace.image= img # bmesh.transform(contextMatrix) ob = SCN_OBJECTS.new(bmesh, tempName) ''' if contextMatrix_tx: ob.setMatrix(contextMatrix_tx) ''' if contextMatrix_rot: ob.setMatrix(contextMatrix_rot) importedObjects.append(ob) bmesh.calcNormals()
def consolidate_mesh_images(mesh_list, scn, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_KEEP_ASPECT, PREF_IMAGE_MARGIN): #, PREF_SIZE_FROM_UV=True): ''' Main packing function All meshes from mesh_list must have faceUV else this function will fail. ''' face_groups = {} for me in mesh_list: for f in me.faces: if f.mode & TEXMODE: image = f.image if image: try: face_groups[ image.name] # will fail if teh groups not added. except: try: size = image.size except: B.Draw.PupMenu( 'Aborting: Image cold not be loaded|' + image.name) return face_groups[image.name] = faceGroup( mesh_list, image, size, PREF_IMAGE_MARGIN) if not face_groups: B.Draw.PupMenu('No Images found in mesh(es). Aborting!') return if len(face_groups) < 2: B.Draw.PupMenu( 'Only 1 image found|Select a mesh(es) using 2 or more images.') return ''' if PREF_SIZE_FROM_UV: for fg in face_groups.itervalues(): fg.set_worldspace_scale() ''' # RENDER THE FACES. render_scn = B.Scene.New() render_scn.makeCurrent() render_context = render_scn.getRenderingContext() render_context.setRenderPath( '') # so we can ignore any existing path and save to the abs path. PREF_IMAGE_PATH_EXPAND = B.sys.expandpath(PREF_IMAGE_PATH) + '.png' # TEST THE FILE WRITING. try: # Can we write to this file??? f = open(PREF_IMAGE_PATH_EXPAND, 'w') f.close() except: B.Draw.PupMenu('Error%t|Could not write to path|' + PREF_IMAGE_PATH_EXPAND) return render_context.imageSizeX(PREF_IMAGE_SIZE) render_context.imageSizeY(PREF_IMAGE_SIZE) render_context.enableOversampling(True) render_context.setOversamplingLevel(16) render_context.setRenderWinSize(100) render_context.setImageType(Render.PNG) render_context.enableExtensions(True) render_context.enablePremultiply() # No alpha needed. render_context.enableRGBAColor() render_context.threads = 2 #Render.EnableDispView() # Broken?? # New Mesh and Object render_mat = B.Material.New() render_mat.mode |= \ B.Material.Modes.SHADELESS | \ B.Material.Modes.TEXFACE | \ B.Material.Modes.TEXFACE_ALPHA | \ B.Material.Modes.ZTRANSP render_mat.setAlpha(0.0) render_me = B.Mesh.New() render_me.verts.extend([Vector( 0, 0, 0)]) # Stupid, dummy vert, preverts errors. when assigning UV's/ render_ob = B.Object.New('Mesh') render_ob.link(render_me) render_scn.link(render_ob) render_me.materials = [render_mat] # New camera and object render_cam_data = B.Camera.New('ortho') render_cam_ob = B.Object.New('Camera') render_cam_ob.link(render_cam_data) render_scn.link(render_cam_ob) render_scn.objects.camera = render_cam_ob render_cam_data.type = 'ortho' render_cam_data.scale = 1.0 # Position the camera render_cam_ob.LocZ = 1.0 render_cam_ob.LocX = 0.5 render_cam_ob.LocY = 0.5 # List to send to to boxpack function. boxes2Pack = [fg.box_pack for fg in face_groups.itervalues()] packWidth, packHeight = B.Geometry.BoxPack2D(boxes2Pack) if PREF_KEEP_ASPECT: packWidth = packHeight = max(packWidth, packHeight) # packedLs is a list of [(anyUniqueID, left, bottom, width, height)...] # Re assign the face groups boxes to the face_group. for box in boxes2Pack: face_groups[box[4]].box_pack = box # box[4] is the ID (image name) # Add geometry to the mesh for fg in face_groups.itervalues(): # Add verts clockwise from the bottom left. _x = fg.box_pack[0] / packWidth _y = fg.box_pack[1] / packHeight _w = fg.box_pack[2] / packWidth _h = fg.box_pack[3] / packHeight render_me.verts.extend([\ Vector(_x, _y, 0),\ Vector(_x, _y +_h, 0),\ Vector(_x + _w, _y +_h, 0),\ Vector(_x + _w, _y, 0),\ ]) render_me.faces.extend([\ render_me.verts[-1],\ render_me.verts[-2],\ render_me.verts[-3],\ render_me.verts[-4],\ ]) target_face = render_me.faces[-1] target_face.image = fg.image target_face.mode |= TEXMODE # Set the UV's, we need to flip them HOZ? target_face.uv[0].x = target_face.uv[1].x = fg.xmax target_face.uv[2].x = target_face.uv[3].x = fg.xmin target_face.uv[0].y = target_face.uv[3].y = fg.ymin target_face.uv[1].y = target_face.uv[2].y = fg.ymax for uv in target_face.uv: uv_rot = ((uv - fg.cent) * fg.rot_mat[1]) + fg.cent uv.x = uv_rot.x uv.y = uv_rot.y render_context.render() Render.CloseRenderWindow() render_context.saveRenderedImage(PREF_IMAGE_PATH_EXPAND) #if not B.sys.exists(PREF_IMAGE_PATH_EXPAND): # raise 'Error!!!' # NOW APPLY THE SAVED IMAGE TO THE FACES! #print PREF_IMAGE_PATH_EXPAND try: target_image = B.Image.Load(PREF_IMAGE_PATH_EXPAND) except: B.Draw.PupMenu('Error: Could not render or load the image at path|' + PREF_IMAGE_PATH_EXPAND) return # Set to the 1 image. for me in mesh_list: for f in me.faces: if f.mode & TEXMODE and f.image: f.image = target_image for fg in face_groups.itervalues(): fg.move2packed(packWidth, packHeight) scn.makeCurrent() render_me.verts = None # free a tiny amount of memory. B.Scene.Unlink(render_scn) target_image.makeCurrent()
def __init__(self, loop, me, closed): # Vert loop # Use next and prev, nextDist, prevDist # Get Loops centre. fac= len(loop) verts = me.verts self.centre= reduce(lambda a,b: a+verts[b].co/fac, loop, Vector()) # Convert Vert loop to Edges. self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop))] if not closed: self.edges[0].fake = True # fake edge option self.closed = closed # Assign linked list for eIdx in xrange(len(self.edges)-1): self.edges[eIdx].next = self.edges[eIdx+1] self.edges[eIdx].prev = self.edges[eIdx-1] # Now last self.edges[-1].next = self.edges[0] self.edges[-1].prev = self.edges[-2] # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. self.normal = Vector() for e in self.edges: n = (self.centre-e.co1).cross(self.centre-e.co2) # Do we realy need tot normalize? n.normalize() self.normal += n # Generate the angle va= e.cent - e.prev.cent vb= e.next.cent - e.cent e.angle= AngleBetweenVecs(va, vb) # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.next.angle)/2 # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.prev.angle)/2 self.normal.normalize() # Generate a normal for each edge. for e in self.edges: n1 = e.co1 n2 = e.co2 n3 = e.prev.co1 a = n1-n2 b = n1-n3 normal1 = a.cross(b) normal1.normalize() n1 = e.co2 n3 = e.next.co2 n2 = e.co1 a = n1-n2 b = n1-n3 normal2 = a.cross(b) normal2.normalize() # Reuse normal1 var normal1 += normal1 + normal2 normal1.normalize() e.normal = normal1
def main(): global USER_FILL_HOLES global USER_FILL_HOLES_QUALITY global USER_STRETCH_ASPECT global USER_ISLAND_MARGIN objects = bpy.data.scenes.active.objects # we can will tag them later. obList = [ob for ob in objects.context if ob.type == 'Mesh'] # Face select object may not be selected. ob = objects.active if ob and ob.sel == 0 and ob.type == 'Mesh': # Add to the list obList = [ob] del objects if not obList: Draw.PupMenu('error, no selected mesh objects') return # Create the variables. USER_PROJECTION_LIMIT = Draw.Create(66) USER_ONLY_SELECTED_FACES = Draw.Create(1) USER_SHARE_SPACE = Draw.Create(1) # Only for hole filling. USER_STRETCH_ASPECT = Draw.Create(1) # Only for hole filling. USER_ISLAND_MARGIN = Draw.Create(0.0) # Only for hole filling. USER_FILL_HOLES = Draw.Create(0) USER_FILL_HOLES_QUALITY = Draw.Create(50) # Only for hole filling. USER_VIEW_INIT = Draw.Create(0) # Only for hole filling. USER_AREA_WEIGHT = Draw.Create(1) # Only for hole filling. pup_block = [\ 'Projection',\ ('Angle Limit:', USER_PROJECTION_LIMIT, 1, 89, 'lower for more projection groups, higher for less distortion.'),\ ('Selected Faces Only', USER_ONLY_SELECTED_FACES, 'Use only selected faces from all selected meshes.'),\ ('Init from view', USER_VIEW_INIT, 'The first projection will be from the view vector.'),\ ('Area Weight', USER_AREA_WEIGHT, 'Weight projections vector by face area.'),\ '',\ '',\ '',\ 'UV Layout',\ ('Share Tex Space', USER_SHARE_SPACE, 'Objects Share texture space, map all objects into 1 uvmap.'),\ ('Stretch to bounds', USER_STRETCH_ASPECT, 'Stretch the final output to texture bounds.'),\ ('Island Margin:', USER_ISLAND_MARGIN, 0.0, 0.5, 'Margin to reduce bleed from adjacent islands.'),\ 'Fill in empty areas',\ ('Fill Holes', USER_FILL_HOLES, 'Fill in empty areas reduced texture waistage (slow).'),\ ('Fill Quality:', USER_FILL_HOLES_QUALITY, 1, 100, 'Depends on fill holes, how tightly to fill UV holes, (higher is slower)'),\ ] # Reuse variable if len(obList) == 1: ob = "Unwrap %i Selected Mesh" else: ob = "Unwrap %i Selected Meshes" # HACK, loop until mouse is lifted. ''' while Window.GetMouseButtons() != 0: sys.sleep(10) ''' if not Draw.PupBlock(ob % len(obList), pup_block): return del ob # Convert from being button types USER_PROJECTION_LIMIT = USER_PROJECTION_LIMIT.val USER_ONLY_SELECTED_FACES = USER_ONLY_SELECTED_FACES.val USER_SHARE_SPACE = USER_SHARE_SPACE.val USER_STRETCH_ASPECT = USER_STRETCH_ASPECT.val USER_ISLAND_MARGIN = USER_ISLAND_MARGIN.val USER_FILL_HOLES = USER_FILL_HOLES.val USER_FILL_HOLES_QUALITY = USER_FILL_HOLES_QUALITY.val USER_VIEW_INIT = USER_VIEW_INIT.val USER_AREA_WEIGHT = USER_AREA_WEIGHT.val USER_PROJECTION_LIMIT_CONVERTED = cos(USER_PROJECTION_LIMIT * DEG_TO_RAD) USER_PROJECTION_LIMIT_HALF_CONVERTED = cos( (USER_PROJECTION_LIMIT / 2) * DEG_TO_RAD) # Toggle Edit mode is_editmode = Window.EditMode() if is_editmode: Window.EditMode(0) # Assume face select mode! an annoying hack to toggle face select mode because Mesh dosent like faceSelectMode. if USER_SHARE_SPACE: # Sort by data name so we get consistant results try: obList.sort(key=lambda ob: ob.getData(name_only=1)) except: obList.sort(lambda ob1, ob2: cmp(ob1.getData(name_only=1), ob2.getData(name_only=1))) collected_islandList = [] Window.WaitCursor(1) time1 = sys.time() # Tag as False se we dont operate on teh same mesh twice. bpy.data.meshes.tag = False for ob in obList: me = ob.getData(mesh=1) if me.tag or me.lib: continue # Tag as used me.tag = True if not me.faceUV: # Mesh has no UV Coords, dont bother. me.faceUV = True if USER_ONLY_SELECTED_FACES: meshFaces = [thickface(f) for f in me.faces if f.sel] else: meshFaces = map(thickface, me.faces) if not meshFaces: continue Window.DrawProgressBar( 0.1, 'SmartProj UV Unwrapper, mapping "%s", %i faces.' % (me.name, len(meshFaces))) # ======= # Generate a projection list from face normals, this is ment to be smart :) # make a list of face props that are in sync with meshFaces # Make a Face List that is sorted by area. # meshFaces = [] # meshFaces.sort( lambda a, b: cmp(b.area , a.area) ) # Biggest first. try: meshFaces.sort(key=lambda a: -a.area) except: meshFaces.sort(lambda a, b: cmp(b.area, a.area)) # remove all zero area faces while meshFaces and meshFaces[-1].area <= SMALL_NUM: # Set their UV's to 0,0 for uv in meshFaces[-1].uv: uv.zero() meshFaces.pop() # Smallest first is slightly more efficient, but if the user cancels early then its better we work on the larger data. # Generate Projection Vecs # 0d is 1.0 # 180 IS -0.59846 # Initialize projectVecs if USER_VIEW_INIT: # Generate Projection projectVecs = [ Vector(Window.GetViewVector()) * ob.matrixWorld.copy().invert().rotationPart() ] # We add to this allong the way else: projectVecs = [] newProjectVec = meshFaces[0].no newProjectMeshFaces = [] # Popping stuffs it up. # Predent that the most unique angke is ages away to start the loop off mostUniqueAngle = -1.0 # This is popped tempMeshFaces = meshFaces[:] # This while only gathers projection vecs, faces are assigned later on. while 1: # If theres none there then start with the largest face # add all the faces that are close. for fIdx in xrange(len(tempMeshFaces) - 1, -1, -1): # Use half the angle limit so we dont overweight faces towards this # normal and hog all the faces. if newProjectVec.dot(tempMeshFaces[fIdx].no ) > USER_PROJECTION_LIMIT_HALF_CONVERTED: newProjectMeshFaces.append(tempMeshFaces.pop(fIdx)) # Add the average of all these faces normals as a projectionVec averageVec = Vector(0, 0, 0) if USER_AREA_WEIGHT: for fprop in newProjectMeshFaces: averageVec += (fprop.no * fprop.area) else: for fprop in newProjectMeshFaces: averageVec += fprop.no if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN projectVecs.append(averageVec.normalize()) # Get the next vec! # Pick the face thats most different to all existing angles :) mostUniqueAngle = 1.0 # 1.0 is 0d. no difference. mostUniqueIndex = 0 # dummy for fIdx in xrange(len(tempMeshFaces) - 1, -1, -1): angleDifference = -1.0 # 180d difference. # Get the closest vec angle we are to. for p in projectVecs: temp_angle_diff = p.dot(tempMeshFaces[fIdx].no) if angleDifference < temp_angle_diff: angleDifference = temp_angle_diff if angleDifference < mostUniqueAngle: # We have a new most different angle mostUniqueIndex = fIdx mostUniqueAngle = angleDifference if mostUniqueAngle < USER_PROJECTION_LIMIT_CONVERTED: #print 'adding', mostUniqueAngle, USER_PROJECTION_LIMIT, len(newProjectMeshFaces) # Now weight the vector to all its faces, will give a more direct projection # if the face its self was not representive of the normal from surrounding faces. newProjectVec = tempMeshFaces[mostUniqueIndex].no newProjectMeshFaces = [tempMeshFaces.pop(mostUniqueIndex)] else: if len(projectVecs) >= 1: # Must have at least 2 projections break # If there are only zero area faces then its possible # there are no projectionVecs if not len(projectVecs): Draw.PupMenu( 'error, no projection vecs where generated, 0 area faces can cause this.' ) return faceProjectionGroupList = [[] for i in xrange(len(projectVecs))] # MAP and Arrange # We know there are 3 or 4 faces here for fIdx in xrange(len(meshFaces) - 1, -1, -1): fvec = meshFaces[fIdx].no i = len(projectVecs) # Initialize first bestAng = fvec.dot(projectVecs[0]) bestAngIdx = 0 # Cycle through the remaining, first alredy done while i - 1: i -= 1 newAng = fvec.dot(projectVecs[i]) if newAng > bestAng: # Reverse logic for dotvecs bestAng = newAng bestAngIdx = i # Store the area for later use. faceProjectionGroupList[bestAngIdx].append(meshFaces[fIdx]) # Cull faceProjectionGroupList, # Now faceProjectionGroupList is full of faces that face match the project Vecs list for i in xrange(len(projectVecs)): # Account for projectVecs having no faces. if not faceProjectionGroupList[i]: continue # Make a projection matrix from a unit length vector. MatProj = VectoMat(projectVecs[i]) # Get the faces UV's from the projected vertex. for f in faceProjectionGroupList[i]: f_uv = f.uv for j, v in enumerate(f.v): f_uv[j][:] = (MatProj * v.co)[:2] if USER_SHARE_SPACE: # Should we collect and pack later? islandList = getUvIslands(faceProjectionGroupList, me) collected_islandList.extend(islandList) else: # Should we pack the islands for this 1 object? islandList = getUvIslands(faceProjectionGroupList, me) packIslands(islandList) # update the mesh here if we need to. # We want to pack all in 1 go, so pack now if USER_SHARE_SPACE: Window.DrawProgressBar(0.9, "Box Packing for all objects...") packIslands(collected_islandList) print "Smart Projection time: %.2f" % (sys.time() - time1) # Window.DrawProgressBar(0.9, "Smart Projections done, time: %.2f sec." % (sys.time() - time1)) if is_editmode: Window.EditMode(1) Window.DrawProgressBar(1.0, "") Window.WaitCursor(0) Window.RedrawAll()
def generate_footprint(): # get mesh objects objects = filter( lambda obj: obj.type == 'Mesh' and obj.name.lower().startswith( 'footprint'), scene.objects) if not objects: error( 'Error! Object list is empty. (No mesh objects whose names begin with "footprint".)' ) return False # check whether visual transforms applied v = [ obj for obj in objects if tuple(obj.rot) != (0, 0, 0) or tuple(obj.size) != (1, 1, 1) ] if v: error('Error! The following mesh ' + ('objects have' if len(v) > 1 else 'object has') + ' non-applied visual transforms:') for obj in v: error('\x20\x20%s -> rot: %s, size: %s' % (str(obj), str(obj.rot), str(obj.size))) error('Solution: apply visual transforms.') return False footprint = [] for obj in objects: log(str(obj)) mesh = obj.getData(mesh=True) obj_loc = obj.matrix[3].xyz + Vector(0.5, 0.5, 0) name = obj.name.split('.') name = name[1] if len(name) > 1 else "0" def test_point(x0, y0, i, j): x = x0 + 0.0625 * (i + 0.5) y = y0 + 0.0625 * (j + 0.5) ray, orig = Vector(0, 0, 1), Vector(x, y, 0) for face in mesh.faces: verts = [v.co + obj_loc for v in face.verts] if Intersect(verts[0], verts[1], verts[2], ray, orig, 1) or \ ( len(face.verts) == 4 and \ Intersect(verts[0], verts[2], verts[3], ray, orig, 1) ): return True return False # bounding box box = obj.getBoundBox(1) X, Y, Z = zip(*map(tuple, box)) Z = None # not used minx, maxx = int(floor(min(X) + 0.5)), int(ceil(max(X) + 0.5)) miny, maxy = int(floor(min(Y) + 0.5)), int(ceil(max(Y) + 0.5)) data = [(0x02, 'minx', minx), (0x02, 'maxx', maxx - 1), (0x02, 'miny', miny), (0x02, 'maxy', maxy - 1)] log('--Name: "%s"' % name) log('--Size: %i x %i' % (maxx - minx, maxy - miny)) for x, y in product(xrange(minx, maxx), xrange(miny, maxy)): key = '(%i,%i)' % (x, y) s = '' for j in xrange(16): a = sum(2**i for i in xrange(16) if test_point(x, y, i, j)) s += pack('<H', a) data.append((0x09, key, s)) footprint.append((0x07, name, data)) #<- objects return (0x07, 'footprint', footprint)
class edgeLoop(object): __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges' def __init__(self, loop, me, closed): # Vert loop # Use next and prev, nextDist, prevDist # Get Loops centre. fac = len(loop) verts = me.verts self.centre = reduce(lambda a, b: a + verts[b].co / fac, loop, Vector()) # Convert Vert loop to Edges. self.edges = [ edge(verts[loop[vIdx - 1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop)) ] if not closed: self.edges[0].fake = True # fake edge option self.closed = closed # Assign linked list for eIdx in xrange(len(self.edges) - 1): self.edges[eIdx].next = self.edges[eIdx + 1] self.edges[eIdx].prev = self.edges[eIdx - 1] # Now last self.edges[-1].next = self.edges[0] self.edges[-1].prev = self.edges[-2] # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. self.normal = Vector() for e in self.edges: n = (self.centre - e.co1).cross(self.centre - e.co2) # Do we realy need tot normalize? n.normalize() self.normal += n # Generate the angle va = e.cent - e.prev.cent vb = e.next.cent - e.cent e.angle = AngleBetweenVecs(va, vb) # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.next.angle)/2 # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.prev.angle)/2 self.normal.normalize() # Generate a normal for each edge. for e in self.edges: n1 = e.co1 n2 = e.co2 n3 = e.prev.co1 a = n1 - n2 b = n1 - n3 normal1 = a.cross(b) normal1.normalize() n1 = e.co2 n3 = e.next.co2 n2 = e.co1 a = n1 - n2 b = n1 - n3 normal2 = a.cross(b) normal2.normalize() # Reuse normal1 var normal1 += normal1 + normal2 normal1.normalize() e.normal = normal1 #print e.normal def backup(self): # Keep a backup of the edges self.backup_edges = self.edges[:] def restore(self): self.edges = self.backup_edges[:] for e in self.edges: e.removed = 0 def reverse(self): self.edges.reverse() self.normal.negate() for e in self.edges: e.normal.negate() e.v1, e.v2 = e.v2, e.v1 e.co1, e.co2 = e.co2, e.co1 e.next, e.prev = e.prev, e.next def removeSmallest(self, cullNum, otherLoopLen): ''' Removes N Smallest edges and backs up the loop, this is so we can loop between 2 loops as if they are the same length, backing up and restoring incase the loop needs to be skinned with another loop of a different length. ''' global CULL_METHOD if CULL_METHOD == 1: # Shortest edge eloopCopy = self.edges[:] # Length sort, smallest first try: eloopCopy.sort(key=lambda e1: e1.length) except: eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length)) # Dont use atm #eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first #eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first remNum = 0 for i, e in enumerate(eloopCopy): if not e.fake: e.removed = 1 self.edges.remove( e) # Remove from own list, still in linked list. remNum += 1 if not remNum < cullNum: break else: # CULL METHOD is even culled = 0 step = int(otherLoopLen / float(cullNum)) * 2 currentEdge = self.edges[0] while culled < cullNum: # Get the shortest face in the next STEP step_count = 0 bestAng = 360.0 smallestEdge = None while step_count <= step or smallestEdge == None: step_count += 1 if not currentEdge.removed: # 0 or -1 will not be accepted if currentEdge.angle < bestAng and not currentEdge.fake: smallestEdge = currentEdge bestAng = currentEdge.angle currentEdge = currentEdge.next # In that stepping length we have the smallest edge.remove it smallestEdge.removed = 1 self.edges.remove(smallestEdge) # Start scanning from the edge we found? - result is over fanning- no good. #currentEdge= smallestEdge.next culled += 1
def getuv(): temp_data=file.read(STRUCT_SIZE_2FLOAT) new_chunk.bytes_read += STRUCT_SIZE_2FLOAT #2 float x 4 bytes each return Vector( unpack('<2f', temp_data) )
def docyl(S, R, Pts): coords = [] p0 = Vector(Pts[0][0], Pts[0][1], Pts[0][2]) p1 = Vector(Pts[1][0], Pts[1][1], Pts[1][2]) t = Vector(Pts[1][0] - Pts[0][0], Pts[1][1] - Pts[0][1], Pts[1][2] - Pts[0][2]) t.normalize() if t * Vector(1, 0, 0) < 0.8: n = Vector(1, 0, 0) - (Vector(1, 0, 0) * t) * t else: n = Vector(0, 1, 0) - (Vector(0, 1, 0) * t) * t n.normalize() b = Vector(t[1] * n[2] - t[2] * n[1], t[2] * n[0] - t[0] * n[2], t[0] * n[1] - t[1] * n[0]) b.normalize() for i in xrange(S): angle = float(i) * 2. * pi / float(S) vec = cos(angle) * R * n + sin(angle) * R * b c0 = p0 + vec c1 = p1 + vec coords += [[c0[0], c0[1], c0[2]]] coords += [[c1[0], c1[1], c1[2]]] faces = [] for i in xrange(S): faces += [[ 2 * i, (2 * i + 2) % (2 * S), (2 * i + 3) % (2 * S), (2 * i + 1) % (2 * S) ]] # midpoints coords += [[p0[0], p0[1], p0[2]]] coords += [[p1[0], p1[1], p1[2]]] cid0 = len(coords) - 2 cid1 = len(coords) - 1 for i in xrange(S): idx = [] idx2 = [] idx.append(2 * i + 0) idx.append(cid0) idx.append(2 * ((i + 1) % S)) idx2.append(2 * i + 1) idx2.append(2 * ((i + 1) % S) + 1) idx2.append(cid1) faces += [idx] faces += [idx2] print faces me = Mesh.New('Strut') me.verts.extend(coords) me.faces.extend(faces) # Add new object to scene and return it return Scene.GetCurrent().objects.new(me)
class edgeLoop(object): __slots__ = 'centre', 'edges', 'normal', 'closed', 'backup_edges' def __init__(self, loop, me, closed): # Vert loop # Use next and prev, nextDist, prevDist # Get Loops centre. fac= len(loop) verts = me.verts self.centre= reduce(lambda a,b: a+verts[b].co/fac, loop, Vector()) # Convert Vert loop to Edges. self.edges = [edge(verts[loop[vIdx-1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop))] if not closed: self.edges[0].fake = True # fake edge option self.closed = closed # Assign linked list for eIdx in xrange(len(self.edges)-1): self.edges[eIdx].next = self.edges[eIdx+1] self.edges[eIdx].prev = self.edges[eIdx-1] # Now last self.edges[-1].next = self.edges[0] self.edges[-1].prev = self.edges[-2] # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. self.normal = Vector() for e in self.edges: n = (self.centre-e.co1).cross(self.centre-e.co2) # Do we realy need tot normalize? n.normalize() self.normal += n # Generate the angle va= e.cent - e.prev.cent vb= e.next.cent - e.cent e.angle= AngleBetweenVecs(va, vb) # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.next.angle)/2 # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.prev.angle)/2 self.normal.normalize() # Generate a normal for each edge. for e in self.edges: n1 = e.co1 n2 = e.co2 n3 = e.prev.co1 a = n1-n2 b = n1-n3 normal1 = a.cross(b) normal1.normalize() n1 = e.co2 n3 = e.next.co2 n2 = e.co1 a = n1-n2 b = n1-n3 normal2 = a.cross(b) normal2.normalize() # Reuse normal1 var normal1 += normal1 + normal2 normal1.normalize() e.normal = normal1 #print e.normal def backup(self): # Keep a backup of the edges self.backup_edges = self.edges[:] def restore(self): self.edges = self.backup_edges[:] for e in self.edges: e.removed = 0 def reverse(self): self.edges.reverse() self.normal.negate() for e in self.edges: e.normal.negate() e.v1, e.v2 = e.v2, e.v1 e.co1, e.co2 = e.co2, e.co1 e.next, e.prev = e.prev, e.next def removeSmallest(self, cullNum, otherLoopLen): ''' Removes N Smallest edges and backs up the loop, this is so we can loop between 2 loops as if they are the same length, backing up and restoring incase the loop needs to be skinned with another loop of a different length. ''' global CULL_METHOD if CULL_METHOD == 1: # Shortest edge eloopCopy = self.edges[:] # Length sort, smallest first try: eloopCopy.sort(key = lambda e1: e1.length) except: eloopCopy.sort(lambda e1, e2: cmp(e1.length, e2.length )) # Dont use atm #eloopCopy.sort(lambda e1, e2: cmp(e1.angle*e1.length, e2.angle*e2.length)) # Length sort, smallest first #eloopCopy.sort(lambda e1, e2: cmp(e1.angle, e2.angle)) # Length sort, smallest first remNum = 0 for i, e in enumerate(eloopCopy): if not e.fake: e.removed = 1 self.edges.remove( e ) # Remove from own list, still in linked list. remNum += 1 if not remNum < cullNum: break else: # CULL METHOD is even culled = 0 step = int(otherLoopLen / float(cullNum)) * 2 currentEdge = self.edges[0] while culled < cullNum: # Get the shortest face in the next STEP step_count= 0 bestAng= 360.0 smallestEdge= None while step_count<=step or smallestEdge==None: step_count+=1 if not currentEdge.removed: # 0 or -1 will not be accepted if currentEdge.angle<bestAng and not currentEdge.fake: smallestEdge= currentEdge bestAng= currentEdge.angle currentEdge = currentEdge.next # In that stepping length we have the smallest edge.remove it smallestEdge.removed = 1 self.edges.remove(smallestEdge) # Start scanning from the edge we found? - result is over fanning- no good. #currentEdge= smallestEdge.next culled+=1
def __init__(self, loop, me, closed): # Vert loop # Use next and prev, nextDist, prevDist # Get Loops centre. fac = len(loop) verts = me.verts self.centre = reduce(lambda a, b: a + verts[b].co / fac, loop, Vector()) # Convert Vert loop to Edges. self.edges = [ edge(verts[loop[vIdx - 1]], verts[loop[vIdx]]) for vIdx in xrange(len(loop)) ] if not closed: self.edges[0].fake = True # fake edge option self.closed = closed # Assign linked list for eIdx in xrange(len(self.edges) - 1): self.edges[eIdx].next = self.edges[eIdx + 1] self.edges[eIdx].prev = self.edges[eIdx - 1] # Now last self.edges[-1].next = self.edges[0] self.edges[-1].prev = self.edges[-2] # GENERATE AN AVERAGE NORMAL FOR THE WHOLE LOOP. self.normal = Vector() for e in self.edges: n = (self.centre - e.co1).cross(self.centre - e.co2) # Do we realy need tot normalize? n.normalize() self.normal += n # Generate the angle va = e.cent - e.prev.cent vb = e.next.cent - e.cent e.angle = AngleBetweenVecs(va, vb) # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.next.angle)/2 # Blur the angles #for e in self.edges: # e.angle= (e.angle+e.prev.angle)/2 self.normal.normalize() # Generate a normal for each edge. for e in self.edges: n1 = e.co1 n2 = e.co2 n3 = e.prev.co1 a = n1 - n2 b = n1 - n3 normal1 = a.cross(b) normal1.normalize() n1 = e.co2 n3 = e.next.co2 n2 = e.co1 a = n1 - n2 b = n1 - n3 normal2 = a.cross(b) normal2.normalize() # Reuse normal1 var normal1 += normal1 + normal2 normal1.normalize() e.normal = normal1
def mkpkfmesh(pkffile,N,S,R): # Here we use the biarc client included in the libbiarc tools directory # to recover a mesh cli2 = popen2("env") for i in cli2[1].readlines(): print i cli2[1].flush() del cli2 cli = popen2("biarccli %s" % pkffile) if cli[1].readline().strip()!='OK': return cli[0].write('closed\n') cli[0].flush() cli[1].readline() cli[0].write("mesh:%i:%i:%f\n" % (N,S,R) ) cli[0].flush() # Skip first dot '.' cli[1].readline() coords = [] for i in xrange(N+1): for j in xrange(S+1): x,y,z = map(lambda v: float(v),cli[1].readline().strip().split()) if j==S: continue coords += [[x,y,z]] cli[0].write('exit\n') del cli def idx(i,j): return (i)*S+j faces = [] for i in xrange(N): for j in xrange(S): faces += [[idx(i,j),idx(i,(j+1)%S), idx((i+1)%(N),(j+1)%S),idx((i+1)%(N),j)]] # Glue the Ends def distance(a,b): x,y,z=a[0]-b[0],a[1]-b[1],a[2]-b[2] return (x*x+y*y+z*z) # XXX Permutation index disabled in mesh generation (libbiarc) # Find permutation index # pidx = 0 # cdist = distance(coords[0],coords[idx(N-1,0)]) # for i in xrange(1,S): # d = distance(coords[i],coords[idx(N-1,0)]) # if d<cdist: # cdist = d # pidx = i # for j in xrange(S): # faces += [[ idx(N-2,j),idx(N-2,(j+1)%S), # idx(0,(j+1+pidx)%S),idx(0,(j+pidx)%S) ]] me = Mesh.New('myMesh') # We remove the last row of coords (same as first) # The face indexing is correct (c.f. above permutation index) me.verts.extend(coords[:S*N]) me.faces.extend(faces) print me.getUVLayerNames() # Init texture coordinates for i in xrange(N): for j in xrange(S): t0,s0 = float(j)/float(S), float(i)/float(N) t1,s1 = float(j+1)/float(S), float(i+1)/float(N) n = i*S+j me.faces[n].uv = [ Vector(s0,t0), Vector(s0,t1), Vector(s1,t1), Vector(s1,t0) ] print 'Tex coords' for i in me.faces: print i.uv scn = Scene.GetCurrent() # link object to current scene ob = scn.objects.new(me, 'PKFMesh') return ob