from Blender import * try: import psyco psyco.full() except: print 'no psyco for you!' DotVecs= Mathutils.DotVecs #======================================================== # SPACIAL TREE - Seperate Class - use if you want to # USed for getting vert is a proximity LEAF_SIZE = 128 class octreeNode: def __init__(self, verts, parent): # Assunme we are a leaf node, until split is run. self.verts = verts self.children = [] if parent == None: # ROOT NODE, else set bounds when making children, # BOUNDS v= verts[0] maxx,maxy,maxz= v.co minx,miny,minz= maxx,maxy,maxz for v in verts: x,y,z= v.co if x>maxx: maxx= x if y>maxy: maxy= y if z>maxz: maxz= z if x LEAF_SIZE: self.makeChildren() # 8 new children, self.verts = None # Alredy assumed a leaf not so dont do anything here. def makeChildren(self): verts= self.verts # Devide into 8 children. axisDividedVerts = [[],[],[],[],[],[],[],[]] # Verts Only divx = (self.maxx + self.minx) / 2 divy = (self.maxy + self.miny) / 2 divz = (self.maxz + self.minz) / 2 # Sort into 8 for v in verts: x,y,z = v.co if x > divx: if y > divy: if z > divz: axisDividedVerts[0].append(v) else: axisDividedVerts[1].append(v) else: if z > divz: axisDividedVerts[2].append(v) else: axisDividedVerts[3].append(v) else: if y > divy: if z > divz: axisDividedVerts[4].append(v) else: axisDividedVerts[5].append(v) else: if z > divz: axisDividedVerts[6].append(v) else: axisDividedVerts[7].append(v) # populate self.children for i in xrange(8): octNode = octreeNode(axisDividedVerts[i], self) # Set bounds manually if i == 0: octNode.minx = divx octNode.maxx = self.maxx octNode.miny = divy octNode.maxy = self.maxy octNode.minz = divz octNode.maxz = self.maxz elif i == 1: octNode.minx = divx octNode.maxx = self.maxx octNode.miny = divy octNode.maxy = self.maxy octNode.minz = self.minz # octNode.maxz = divz # elif i == 2: octNode.minx = divx octNode.maxx = self.maxx octNode.miny = self.miny # octNode.maxy = divy # octNode.minz = divz octNode.maxz = self.maxz elif i == 3: octNode.minx = divx octNode.maxx = self.maxx octNode.miny = self.miny # octNode.maxy = divy # octNode.minz = self.minz # octNode.maxz = divz # elif i == 4: octNode.minx = self.minx # octNode.maxx = divx # octNode.miny = divy octNode.maxy = self.maxy octNode.minz = divz octNode.maxz = self.maxz elif i == 5: octNode.minx = self.minx # octNode.maxx = divx # octNode.miny = divy octNode.maxy = self.maxy octNode.minz = self.minz # octNode.maxz = divz # elif i == 6: octNode.minx = self.minx # octNode.maxx = divx # octNode.miny = self.miny # octNode.maxy = divy # octNode.minz = divz octNode.maxz = self.maxz elif i == 7: octNode.minx = self.minx # octNode.maxx = divx # octNode.miny = self.miny # octNode.maxy = divy # octNode.minz = self.minz # octNode.maxz = divz # #octNode.setCornerPoints() octNode.splitNode() # Splits the node if it can. self.children.append(octNode) # GETS VERTS IN A Distance RANGE- def getVertsInRange(self, loc, normal, range_val, vertList): #loc= Mathutils.Vector(loc) # MUST BE VECTORS #normal= Mathutils.Vector(normal) ''' loc: Vector of the location to search from normal: None or Vector - if a vector- will only get verts on this side of the vector range_val: maximum distance. A negative value will fill the list with teh closest vert only. vertList: starts as an empty list list that this function fills with verts that match ''' xloc,yloc,zloc= loc if range_val<0: range_val= -range_val FIND_CLOSEST= True vertList.append(None) # just update the 1 vertex else: FIND_CLOSEST= False if self.children: # Check if the bounds are in range_val, for childNode in self.children: # First test if we are surrounding the point. if\ childNode.minx - range_val < xloc and\ childNode.maxx + range_val > xloc and\ childNode.miny - range_val < yloc and\ childNode.maxy + range_val > yloc and\ childNode.minz - range_val < zloc and\ childNode.maxz + range_val > zloc: # Recurse down or get virts. childNode.getVertsInRange(loc, normal, range_val, vertList) #continue # Next please else: # we are a leaf node. Test vert locations. if not normal: # Length only check for v in self.verts: length = (loc - v.co).length if length < range_val: if FIND_CLOSEST: # Just update the 1 vert vertList[0]= (v, length) range_val= length # Shink the length so we only get verts from their. else: vertList.append((v, length)) else: # Lengh and am I infront of the vert. for v in self.verts: length = (loc - v.co).length if length < range_val: # Check if the points in front dot= DotVecs(normal, loc) - DotVecs(normal, v.co) if dot<0: vertList.append((v, length)) # END TREE # EXAMPLE RADIO IN PYTHON USING THE ABOVE FUNCTION """ import BPyMesh # Radio bake def bake(): _AngleBetweenVecs_= Mathutils.AngleBetweenVecs def AngleBetweenVecs(a1,a2): try: return _AngleBetweenVecs_(a1,a2) except: return 180 scn = Scene.GetCurrent() ob = scn.getActiveObject() me = ob.getData(mesh=1) dist= Draw.PupFloatInput('MaxDist:', 2.0, 0.1, 20.0, 0.1, 3) if dist==None: return # Make nice normals BPyMesh.meshCalcNormals(me) len_verts= len(me.verts) #me.sel= False meshOctTree = octreeNode(me.verts, None) # Store face areas vertex_areas= [0.0] * len_verts # Get vertex areas - all areas of face users for f in me.faces: a= f.area for v in f.v: vertex_areas[v.index] += a bias= 0.001 t= sys.time() # Tone for the verts vert_tones= [0.0] * len_verts maxtone= 0.0 mintone= 100000000 for i, v in enumerate(me.verts): if not i%10: print 'verts to go', len_verts-i v_co= v.co v_no= v.no verts_in_range= [] meshOctTree.getVertsInRange(v_co, v_no, dist, verts_in_range) tone= 0.0 # These are verts in our range for test_v, length in verts_in_range: if bias 90: # were facing this vert #if 1: # Current value us between zz90 and 180 # make between 0 and 90 # so 0 is right angles and 90 is direct opposite vertex normal normal_diff= (normal_diff-90) # Vertex area needs to be taken into account so we dont have small faces over influencing. vertex_area= vertex_areas[test_v.index] # Get the angle the vertex is in location from the location and normal of the vert. above_diff= AngleBetweenVecs(test_v.co-v.co, v_no) ## Result will be between 0 :above and 90: horizon.. invert this so horizon has littel effect above_diff= 90-above_diff # dist-length or 1.0/length both work well tone= (dist-length) * vertex_area * above_diff * normal_diff vert_tones[i] += tone if maxtonevert_tones[i]: mintone= vert_tones[i] if not maxtone: Draw.PupMenu('No verts in range, use a larger range') return # Apply tones for f in me.faces: f_col= f.col for i, v in enumerate(f.v): c= f_col[i] v_index= v.index tone= int(((maxtone - vert_tones[v.index]) / maxtone) * 255 ) #print tone c.r= c.g= c.b= tone print 'time', sys.time()-t if __name__=="__main__": bake() """