def circle (self, radius, axis, offset): # since we're doing line segments, just vertices in our geom format = GeomVertexFormat.getV3() # build our data structure and get a handle to the vertex column vdata = GeomVertexData ('', format, Geom.UHStatic) vertices = GeomVertexWriter (vdata, 'vertex') # build a linestrip vertex buffer lines = GeomLinestrips (Geom.UHStatic) for i in range (0, self.subdiv): angle = i / float(self.subdiv) * 2.0 * math.pi ca = math.cos (angle) sa = math.sin (angle) if axis == "x": vertices.addData3f (0, radius * ca, radius * sa + offset) if axis == "y": vertices.addData3f (radius * ca, 0, radius * sa + offset) if axis == "z": vertices.addData3f (radius * ca, radius * sa, offset) for i in range (1, self.subdiv): lines.addVertices(i - 1, i) lines.addVertices (self.subdiv - 1, 0) lines.closePrimitive() geom = Geom (vdata) geom.addPrimitive (lines) # Add our primitive to the geomnode self.gnode.addGeom (geom)
def create_hexagon(radius): """ Creates a hexagon shape that is centered at (0,0,0) with the corners having a distance of radius to the center and the normals pointing in direction (0,-1,0). Returns the tuple (PandaNode, GeomVertexData). """ format = GeomVertexFormat.getV3n3c4t2() vdata=GeomVertexData('hexagon', format, Geom.UHStatic) vertex=GeomVertexWriter(vdata, 'vertex') normal=GeomVertexWriter(vdata, 'normal') # create the vertices vertex.addData3f(0,0,0) normal.addData3f(0,-1,0) # add the other vertices for phi in range(0,360,60): # right-hand-rule (with middle finger pointing upwards): the y-axis points towards the screen, # therefore the hexagon will be created in the x,z plane, with x-axis pointing to the right # and the z-axis pointing up # get the next vertex coordinates by rotating the point (0,0,radius) in the x,z plane x,z = rotate_phi_degrees_counter_clockwise(phi, (0,radius)) #print (x,z) vertex.addData3f(x,0,z) normal.addData3f(0,-1,0) # the normal vector points away from the screen # add the vertices to a geometry primitives prim = GeomTrifans(Geom.UHStatic) for i in range(7): prim.addVertex(i) prim.addVertex(1) prim.closePrimitive() geom = Geom(vdata) geom.addPrimitive(prim) hex_node = GeomNode('') hex_node.addGeom(geom) return hex_node, vdata
def draw(self): format=GeomVertexFormat.getV3n3cpt2() vdata=GeomVertexData('square', format, Geom.UHDynamic) vertex=GeomVertexWriter(vdata, 'vertex') normal=GeomVertexWriter(vdata, 'normal') color=GeomVertexWriter(vdata, 'color') circle=Geom(vdata) # Create vertices vertex.addData3f(self.pos) color.addData4f(self.color) for v in range(self._EDGES): x = self.pos.getX() + (self.size * math.cos((2*math.pi/self._EDGES)*v)) y = self.pos.getY() + (self.size * math.sin((2*math.pi/self._EDGES)*v)) z = self.pos.getZ() vertex.addData3f(x, y, z) color.addData4f(self.color) # Create triangles for t in range(self._EDGES): tri = GeomTriangles(Geom.UHDynamic) tri.addVertex(0) tri.addVertex(t+1) if (t+2) > self._EDGES: tri.addVertex(1) else: tri.addVertex(t+2) tri.closePrimitive() circle.addPrimitive(tri) gn = GeomNode('Circle') gn.addGeom(circle) np = NodePath(gn) np.setHpr(0, 90, 0) return np
def create_triangle(x_z_left, x_z_top, x_z_right, static=True): x1,z1 = x_z_left x2,z2 = x_z_top x3,z3 = x_z_right format = GeomVertexFormat.getV3n3c4t2() vdata=GeomVertexData('', format, Geom.UHStatic) vertex=GeomVertexWriter(vdata, 'vertex') normal=GeomVertexWriter(vdata, 'normal') vertex.addData3f(x1, 0, z1) # left vertex.addData3f(x2, 0, z2) # top vertex.addData3f(x3, 0, z3) # right for _i in range(3): normal.addData3f(0,-1,0) if static: prim_hint = Geom.UHStatic else: prim_hint = Geom.UHDynamic prim = GeomTriangles(prim_hint) prim.addVertices(0,2,1) prim.closePrimitive() geom = Geom(vdata) geom.addPrimitive(prim) node = GeomNode('') node.addGeom(geom) return node
def generate(self): format = GeomVertexFormat.getV3() data = GeomVertexData("Data", format, Geom.UHStatic) vertices = GeomVertexWriter(data, "vertex") vertices.addData3f(-self.w, -self.h, -self.d) vertices.addData3f(+self.w, -self.h, -self.d) vertices.addData3f(-self.w, +self.h, -self.d) vertices.addData3f(+self.w, +self.h, -self.d) vertices.addData3f(-self.w, -self.h, +self.d) vertices.addData3f(+self.w, -self.h, +self.d) vertices.addData3f(-self.w, +self.h, +self.d) vertices.addData3f(+self.w, +self.h, +self.d) triangles = GeomTriangles(Geom.UHStatic) def addQuad(v0, v1, v2, v3): triangles.addVertices(v0, v1, v2) triangles.addVertices(v0, v2, v3) triangles.closePrimitive() addQuad(4, 5, 7, 6) # Z+ addQuad(0, 2, 3, 1) # Z- addQuad(3, 7, 5, 1) # X+ addQuad(4, 6, 2, 0) # X- addQuad(2, 6, 7, 3) # Y+ addQuad(0, 1, 5, 4) # Y+ geom = Geom(data) geom.addPrimitive(triangles) node = GeomNode("BoxMaker") node.addGeom(geom) return NodePath(node)
def create_side(x_z_top_left, x_z_bottom_right, static=True): x1, z1 = x_z_top_left x2, z2 = x_z_bottom_right format = GeomVertexFormat.getV3n3c4t2() vdata = GeomVertexData('', format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') vertex.addData3f(x1, 0, z1) # top left vertex.addData3f(x2, 0, z1) # top right vertex.addData3f(x2, 0, z2) # bottom right vertex.addData3f(x1, 0, z2) # bottom left for _i in range(4): normal.addData3f(0, - 1, 0) if static: prim_hint = Geom.UHStatic else: prim_hint = Geom.UHDynamic prim = GeomTristrips(prim_hint) prim.addVertices(1, 0, 2, 3) prim.closePrimitive() geom = Geom(vdata) geom.addPrimitive(prim) node = GeomNode('') node.addGeom(geom) return (node, vdata)
def drawCircle(self, radius, axis, offset): # since we're doing line segments, just vertices in our geom format = GeomVertexFormat.getV3() # build our data structure and get a handle to the vertex column vdata = GeomVertexData('', format, Geom.UHStatic) vertices = GeomVertexWriter(vdata, 'vertex') # build a linestrip vertex buffer lines = GeomLinestrips(Geom.UHStatic) for i in range(0, self.subdiv): angle = i / float(self.subdiv) * 2.0 * math.pi ca = math.cos(angle) sa = math.sin(angle) if axis == "x": vertices.addData3f(0, radius * ca, radius * sa + offset) if axis == "y": vertices.addData3f(radius * ca, 0, radius * sa + offset) if axis == "z": vertices.addData3f(radius * ca, radius * sa, offset) for i in range(1, self.subdiv): lines.addVertices(i - 1, i) lines.addVertices(self.subdiv - 1, 0) lines.closePrimitive() geom = Geom(vdata) geom.addPrimitive(lines) # Add our primitive to the geomnode self.gnode.addGeom(geom)
def init_node_path_line(self, light_number): if self.node_path_line: self.node_path_line.remove() vdata = GeomVertexData('name_me', self.format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') primitive = GeomLines(Geom.UHStatic) vertex.addData3f(*coords_to_panda(0, 0, 0)) vertex.addData3f(*coords_to_panda(*self.direction.coords)) if light_number == 0: line_color = (0.0, 1.0, 1.0, 1.0) elif light_number == 1: line_color = (1.0, 0.0, 1.0, 1.0) elif light_number == 2: line_color = (1.0, 1.0, 0.0, 1.0) color.addData4f(*line_color) color.addData4f(*line_color) primitive.addNextVertices(2) primitive.closePrimitive() geom = Geom(vdata) geom.addPrimitive(primitive) node = GeomNode('gnode') node.addGeom(geom) self.node_path_line = self.parent.node_path_ui.attachNewNode(node) self.node_path_line.setScale(1000) self.node_path_line.setPos(100, 100, 0) self.show_line(self.parent.parent.lights_edit_window.IsShown())
def init_node_path(self): if self.node_path: self.node_path.remove() vdata = GeomVertexData('name_me', self.format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') primitive = GeomTristrips(Geom.UHStatic) film_size = base.cam.node().getLens().getFilmSize() x = film_size.getX() / 2.0 z = x * 0.75 vertex.addData3f(-x, 10000, z) vertex.addData3f(x, 10000, z) vertex.addData3f(-x, 10000, -z) vertex.addData3f(x, 10000, -z) color.addData4f(*[x / 255.0 for x in self.color1] + [1.0]) color.addData4f(*[x / 255.0 for x in self.color1] + [1.0]) color.addData4f(*[x / 255.0 for x in self.color2] + [1.0]) color.addData4f(*[x / 255.0 for x in self.color2] + [1.0]) primitive.addNextVertices(4) primitive.closePrimitive() geom = Geom(vdata) geom.addPrimitive(primitive) node = GeomNode('gnode') node.addGeom(geom) self.node_path = base.camera.attachNewNode(node)
def init_node_path(self): if self.node_path: self.node_path.remove() vdata = GeomVertexData('name_me', self.format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') primitive = GeomLines(Geom.UHStatic) vertex.addData3f(*coords_to_panda(0, 0, 0)) vertex.addData3f(*coords_to_panda(1000, 0, 0)) vertex.addData3f(*coords_to_panda(0, 0, 0)) vertex.addData3f(*coords_to_panda(0, -1000, 0)) vertex.addData3f(*coords_to_panda(0, 0, 0)) vertex.addData3f(*coords_to_panda(0, 0, 1000)) color.addData4f(1.0, 0.0, 0.0, 1.0) color.addData4f(1.0, 0.0, 0.0, 1.0) color.addData4f(0.0, 1.0, 0.0, 1.0) color.addData4f(0.0, 1.0, 0.0, 1.0) color.addData4f(0.0, 0.0, 1.0, 1.0) color.addData4f(0.0, 0.0, 1.0, 1.0) primitive.addNextVertices(6) primitive.closePrimitive() geom = Geom(vdata) geom.addPrimitive(primitive) node = GeomNode('gnode') node.addGeom(geom) self.node_path = self.parent.node_path_ui.attachNewNode(node)
def __init__(self, width=1, depth=1, height=1, origin=Point3(0, 0, 0)): # Create vetex data format gvf = GeomVertexFormat.getV3n3() gvd = GeomVertexData("vertexData", gvf, Geom.UHStatic) # Create vetex writers for each type of data we are going to store gvwV = GeomVertexWriter(gvd, "vertex") gvwN = GeomVertexWriter(gvd, "normal") # Write out all points for p in GetPointsForBox(width, depth, height): gvwV.addData3f(Point3(p) - origin) # Write out all the normals for n in ((-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1)): for i in range(4): gvwN.addData3f(n) geom = Geom(gvd) for i in range(0, gvwV.getWriteRow(), 4): # Create and add both triangles geom.addPrimitive(GetGeomTriangle(i, i + 1, i + 2)) geom.addPrimitive(GetGeomTriangle(i, i + 2, i + 3)) # Init the node path, wrapping the box geomNode = GeomNode("box") geomNode.addGeom(geom) NodePath.__init__(self, geomNode)
def drawSquare(self, x1,y1,z1, x2,y2,z2): format=GeomVertexFormat.getV3n3cpt2() vdata=GeomVertexData('square', format, Geom.UHStatic) vertex=GeomVertexWriter(vdata, 'vertex') normal=GeomVertexWriter(vdata, 'normal') color=GeomVertexWriter(vdata, 'color') texcoord=GeomVertexWriter(vdata, 'texcoord') #make sure we draw the sqaure in the right plane #if x1!=x2: vertex.addData3f(x1, y1, z1) vertex.addData3f(x2, y1, z1) vertex.addData3f(x2, y2, z2) vertex.addData3f(x1, y2, z2) normal.addData3f(self.myNormalize(Vec3(2*x1-1, 2*y1-1, 2*z1-1))) normal.addData3f(self.myNormalize(Vec3(2*x2-1, 2*y1-1, 2*z1-1))) normal.addData3f(self.myNormalize(Vec3(2*x2-1, 2*y2-1, 2*z2-1))) normal.addData3f(self.myNormalize(Vec3(2*x1-1, 2*y2-1, 2*z2-1))) #adding different colors to the vertex for visibility color.addData4f(0.0,0.5,0.0,0.5) color.addData4f(0.0,0.5,0.0,0.5) color.addData4f(0.0,0.5,0.0,0.5) color.addData4f(0.0,0.5,0.0,0.5) texcoord.addData2f(0.0, 1.0) texcoord.addData2f(0.0, 0.0) texcoord.addData2f(1.0, 0.0) texcoord.addData2f(1.0, 1.0) #quads arent directly supported by the Geom interface #you might be interested in the CardMaker class if you are #interested in rectangle though tri1=GeomTriangles(Geom.UHStatic) tri2=GeomTriangles(Geom.UHStatic) tri1.addVertex(0) tri1.addVertex(1) tri1.addVertex(3) tri2.addConsecutiveVertices(1,3) tri1.closePrimitive() tri2.closePrimitive() square=Geom(vdata) square.addPrimitive(tri1) square.addPrimitive(tri2) #square.setIntoCollideMask(BitMask32.bit(1)) squareNP = NodePath(GeomNode('square gnode')) squareNP.node().addGeom(square) squareNP.setTransparency(1) squareNP.setAlphaScale(.5) squareNP.setTwoSided(True) squareNP.setCollideMask(BitMask32.bit(1)) return squareNP
def createPitchLineOld(self,points=[0.5,0.25,-0.25,-0.5], tick=0.00,colour=None): """ create a line to hint at the pitch of the aircraft on the hud """ if colour is None: colour = self.colour l = LineNodePath(aspect2d,'pitchline',4,Vec4(colour[0],colour[1], colour[2],colour[3])) plist = [] for p in points: plist.append((p,0.0,0.0)) plist.insert(0,(points[0],0.0,tick)) plist.append((points[3],0.0,tick)) linelist = [] linelist = [[plist[p],plist[p+1]] for p in range(len(plist)-1)] linelist.pop(2) l.drawLines(linelist) l.create() # These lines are drawn from scratch rather than using a graphic file format = GeomVertexFormat.getV3() vdata = GeomVertexData("vertices",format,Geom.UHStatic) # create vertices to add to use in creating lines vertexWriter=GeomVertexWriter(vdata,"vertex") # here we define enough positions to create two separated lines for p in points: vertexWriter.addData3f(p,0.0,0.0) # and another two positions for the 'ticks' at the line ends vertexWriter.addData3f(points[0],0.0,tick) vertexWriter.addData3f(points[3],0.0,tick) # create the primitives line = GeomLines(Geom.UHStatic) line.addVertices(4,0) # the tick part line.addVertices(0,1) # part of the horizontal line line.closePrimitive() line2 = GeomLines(Geom.UHStatic) line2.addVertices(2,3) # other part of the horizontal line line2.addVertices(3,5) # second tick line2.closePrimitive() # add the lines to a geom object lineGeom = Geom(vdata) lineGeom.addPrimitive(line) lineGeom.addPrimitive(line2) # create the node.. lineGN=GeomNode("splitline") lineGN.addGeom(lineGeom) # and parent the node to aspect2d lineNP = aspect2d.attachNewNode(lineGN) return lineNP
class SphereNode( GeomNode ): def __init__(self,subdivides=3,scale=1.0): super(SphereNode,self).__init__('sphere') uniform = True # see if scale is a tuple try: xs,ys,zs = scale uniform = False except TypeError: # no, it's a scalar xs,ys,zs = scale,scale,scale north = (0.0,1.0,0.0) g = Octahedron() for i in range(subdivides): g.UniformSubdivide( midpointdisplace = NormalizeVert ) #print "%d faces per sphere"%len(g.faces) # okay, we're gonna use setShaderInput to set constants for # surface coverages and planetary seed, so all we need per # vertex is position and normal # and we kind of don't need normal for a unit sphere, but # we want to use the same shader for other thangs format=GeomVertexFormat.getV3n3() vdata=GeomVertexData('sphere', format, Geom.UHDynamic) vertex=GeomVertexWriter(vdata, 'vertex') normal=GeomVertexWriter(vdata, 'normal') for (x,y,z) in g.verts: vertex.addData3f( x*xs, y*ys, z*zs ) if uniform: normal.addData3f( x, y, z ) else: n = NormalizeVert( (x/(xs*xs),y/(ys*ys),z/(zs*zs)) ) normal.addData3f( n[0], n[1], n[2] ) trilist=GeomTriangles(Geom.UHDynamic) for (a,b,c) in g.faces: trilist.addVertex(a) trilist.addVertex(b) trilist.addVertex(c) trilist.closePrimitive() self.geom = Geom(vdata) self.geom.addPrimitive( trilist ) self.addGeom( self.geom )
class SphereNode(GeomNode): def __init__(self, subdivides=3, scale=1.0): super(SphereNode, self).__init__('sphere') uniform = True # see if scale is a tuple try: xs, ys, zs = scale uniform = False except TypeError: # no, it's a scalar xs, ys, zs = scale, scale, scale north = (0.0, 1.0, 0.0) g = Octahedron() for i in range(subdivides): g.UniformSubdivide(midpointdisplace=NormalizeVert) #print "%d faces per sphere"%len(g.faces) # okay, we're gonna use setShaderInput to set constants for # surface coverages and planetary seed, so all we need per # vertex is position and normal # and we kind of don't need normal for a unit sphere, but # we want to use the same shader for other thangs format = GeomVertexFormat.getV3n3() vdata = GeomVertexData('sphere', format, Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') for (x, y, z) in g.verts: vertex.addData3f(x * xs, y * ys, z * zs) if uniform: normal.addData3f(x, y, z) else: n = NormalizeVert( (x / (xs * xs), y / (ys * ys), z / (zs * zs))) normal.addData3f(n[0], n[1], n[2]) trilist = GeomTriangles(Geom.UHDynamic) for (a, b, c) in g.faces: trilist.addVertex(a) trilist.addVertex(b) trilist.addVertex(c) trilist.closePrimitive() self.geom = Geom(vdata) self.geom.addPrimitive(trilist) self.addGeom(self.geom)
def init_node_path(self): if self.node_path: self.node_path.remove() polygon = self.source vdata = GeomVertexData('name_me', self.format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') texcoord = GeomVertexWriter(vdata, 'texcoord') primitive = GeomTristrips(Geom.UHStatic) vertex.addData3f(*coords_to_panda(*polygon.A.point.coords)) vertex.addData3f(*coords_to_panda(*polygon.B.point.coords)) vertex.addData3f(*coords_to_panda(*polygon.C.point.coords)) if hasattr(polygon, 'D'): vertex.addData3f(*coords_to_panda(*polygon.D.point.coords)) else: vertex.addData3f(*coords_to_panda(*polygon.C.point.coords)) if polygon.A.normal: normal.addData3f(*coords_to_panda(*polygon.A.normal.coords)) normal.addData3f(*coords_to_panda(*polygon.B.normal.coords)) normal.addData3f(*coords_to_panda(*polygon.C.normal.coords)) if hasattr(polygon, 'D'): normal.addData3f(*coords_to_panda(*polygon.D.normal.coords)) if polygon.A.normal: gray = 1.0 else: gray = 0.0 self.old_color = (gray, gray, gray, 1.0) color.addData4f(gray, gray, gray, 1.0) color.addData4f(gray, gray, gray, 1.0) color.addData4f(gray, gray, gray, 1.0) if hasattr(polygon, 'D'): color.addData4f(gray, gray, gray, 1.0) if polygon.A.texcoord: pal = ((polygon.texture_palette + 1) * 256) texcoord_A = uv_to_panda2(polygon, pal, *polygon.A.texcoord.coords) texcoord_B = uv_to_panda2(polygon, pal, *polygon.B.texcoord.coords) texcoord_C = uv_to_panda2(polygon, pal, *polygon.C.texcoord.coords) texcoord.addData2f(*texcoord_A) texcoord.addData2f(*texcoord_B) texcoord.addData2f(*texcoord_C) if hasattr(polygon, 'D'): texcoord_D = uv_to_panda2(polygon, pal, *polygon.D.texcoord.coords) texcoord.addData2f(*texcoord_D) primitive.addNextVertices(4) primitive.closePrimitive() geom = Geom(vdata) geom.addPrimitive(primitive) node = GeomNode('gnode') node.addGeom(geom) self.node_path = self.parent.node_path_mesh.attachNewNode(node)
def __init__(self, radius=1.0, height=1.0, numSegs=16, degrees=360, axis=Vec3(0, 0, 1), origin=Point3(0, 0, 0)): # Create vetex data format gvf = GeomVertexFormat.getV3n3() gvd = GeomVertexData("vertexData", gvf, Geom.UHStatic) # Create vetex writers for each type of data we are going to store gvwV = GeomVertexWriter(gvd, "vertex") gvwN = GeomVertexWriter(gvd, "normal") # Get the points for an arc points = GetPointsForArc(degrees, numSegs, True) for i in range(len(points) - 1): # Rotate the points around the desired axis p1 = Point3(points[i][0], points[i][1], 0) * radius p1 = RotatePoint3(p1, Vec3(0, 0, 1), axis) - origin p2 = Point3(points[i + 1][0], points[i + 1][1], 0) * radius p2 = RotatePoint3(p2, Vec3(0, 0, 1), axis) - origin cross = (p2 - axis).cross(p1 - axis) cross.normalize() gvwV.addData3f(p1) gvwV.addData3f(axis * height - origin) gvwV.addData3f(p2) gvwN.addData3f(cross) gvwN.addData3f(cross) gvwN.addData3f(cross) # Base gvwV.addData3f(p2) gvwV.addData3f(Point3(0, 0, 0) - origin) gvwV.addData3f(p1) gvwN.addData3f(-axis) gvwN.addData3f(-axis) gvwN.addData3f(-axis) geom = Geom(gvd) for i in range(0, gvwV.getWriteRow(), 3): # Create and add triangle geom.addPrimitive(GetGeomTriangle(i, i + 1, i + 2)) # Init the node path, wrapping the box geomNode = GeomNode("cone") geomNode.addGeom(geom) NodePath.__init__(self, geomNode)
def createUninterpolatedRoadMesh(self): ''' ''' # Creating the Vertex self.createVertices(self.track.getPoints(), self.street_data) # Connect the Vertex self.connectVertices(self.street_data) geom = Geom(self.vdata) geom.addPrimitive(self.prim) node = GeomNode('street') node.addGeom(geom) # nodePath = self.render.attachNewNode(node) return node
def createBorderRightCollisionMesh(self): ''' ''' # Creating the Vertex self.createVertices(self.track_points, self.street_data.border_r_coll) # Connect the Vertex self.connectVertices(self.street_data.border_r_coll) geom = Geom(self.vdata) geom.addPrimitive(self.prim) node = GeomNode('border_r_coll') node.addGeom(geom) # nodePath = self.render.attachNewNode(node) return node
def init_node_path(self): if self.node_path: self.node_path.remove() vdata = GeomVertexData('name_me', self.format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') primitive = GeomTristrips(Geom.UHStatic) y = self.height * 12 + self.depth * 12 + 1 try: (slope, rotation) = slope_types[self.slope_type] except KeyError: print 'Unknown slope type:', self.slope_type (slope, rotation) = (flat, 0) if self.slope_height == 0: (slope, rotation) = (flat, 0) scale_y = self.slope_height * 12 vertex.addData3f(*coords_to_panda(-14.0, -slope['sw'] * scale_y, -14.0)) vertex.addData3f(*coords_to_panda(-14.0, -slope['nw'] * scale_y, 14.0)) vertex.addData3f(*coords_to_panda(14.0, -slope['ne'] * scale_y, 14.0)) vertex.addData3f(*coords_to_panda(14.0, -slope['se'] * scale_y, -14.0)) vertex.addData3f(*coords_to_panda(-14.0, -slope['sw'] * scale_y, -14.0)) tile_color = (0.5, 0.5, 1.0) if self.cant_walk: tile_color = (1.0, 0.5, 0.5) if self.cant_cursor: tile_color = (0.5, 0.0, 0.0) if (self.x + self.z) % 2 == 0: tile_color = tuple([x * 0.8 for x in tile_color]) self.tile_color = tile_color color.addData4f(*tile_color + (1.0,)) color.addData4f(*tile_color + (1.0,)) color.addData4f(*tile_color + (1.0,)) color.addData4f(*tile_color + (1.0,)) color.addData4f(*tile_color + (1.0,)) primitive.addNextVertices(5) primitive.closePrimitive() geom = Geom(vdata) geom.addPrimitive(primitive) node = GeomNode('gnode') node.addGeom(geom) self.node_path = self.parent.node_path.attachNewNode(node) self.node_path.setH(rotation) can_stand_height = 0 if not self.cant_cursor: can_stand_height = 1 self.node_path.setPos(*coords_to_panda(self.x * 28 + 14, -((self.height + self.depth) * 12 + 1 + can_stand_height), self.z * 28 + 14)) self.node_path.setTag('terrain_xyz', '%u,%u,%u' % (self.x, self.y, self.z))
class PointCloudNode(GeomNode): def __init__(self, name, points, color=(1.0,1.0,1.0,1.0), colors=None): GeomNode.__init__(self, name) self._points = points self._color = color self._colors = colors self._create_vertex_data() self._create_geom_primitives() self._create_geoms() # set visualisation parameters #if self._wireframe: # self.setAttrib(RenderModeAttrib.make(RenderModeAttrib.MWireframe, 2, 1)) #self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone)) self.setAttrib(RenderModeAttrib.make(RenderModeAttrib.MWireframe, 2, 0)) def _create_vertex_data(self): """Creates and fills the vertex data store.""" format = GeomVertexFormat.getV3c4() vdata = GeomVertexData('cloud', format, Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') for index, point in enumerate(self._points): vertex.addData3f(*point[0:3]) if self._colors != None: color.addData4f(*self._colors[index]) else: color.addData4f(*self._color) self._vdata = vdata def _create_geom_primitives(self): """Creates and fill a GeomTriangles with vertex indices.""" pts = GeomPoints(Geom.UHDynamic) pts.addNextVertices(len(self._points)) pts.closePrimitive() self._geom_primitives = [pts, ] def _create_geoms(self): """Creates a Geom attached to self and adds the current primitives.""" self._geom = Geom(self._vdata) for primitive in self._geom_primitives: self._geom.addPrimitive(primitive) self.addGeom(self._geom)
def createCentreMarkOld(self,colour=None): """ create a line to hint at the pitch of the aircraft on the hud """ if colour is None: colour = self.colour # These lines are drawn from scratch rather than using a graphic file format = GeomVertexFormat.getV3() vdata = GeomVertexData("vertices",format,Geom.UHStatic) # create vertices to add to use in creating lines vertexWriter=GeomVertexWriter(vdata,"vertex") # essentially I am trying to create a line that gives an idea of # where the forward vector of the plane is pointing which # helps indicate the pitch # the bends in the line could be used to indicate a few angles but # I am not sure how useful this really is. vertexWriter.addData3f(0.15,0.0,0.0) vertexWriter.addData3f(0.10,0.0,0.0) vertexWriter.addData3f(0.05,0.0,-0.025) vertexWriter.addData3f(0.00,0.0,0.025) vertexWriter.addData3f(-0.05,0.0,-0.025) vertexWriter.addData3f(-0.10,0.0,0.0) vertexWriter.addData3f(-0.15,0.0,0.0) # create the primitives line = GeomLines(Geom.UHStatic) line.addVertices(0,1) line.addVertices(1,2) line.addVertices(2,3) line.addVertices(3,4) line.addVertices(4,5) line.addVertices(5,6) line.closePrimitive() # add the lines to a geom object lineGeom = Geom(vdata) lineGeom.addPrimitive(line) # create the node.. lineGN=GeomNode("centremark") lineGN.addGeom(lineGeom) # and parent the node to aspect2d lineNP = aspect2d.attachNewNode(lineGN) return lineNP
def create_line(x1, z1, x2, z2): format = GeomVertexFormat.getV3n3c4t2() vdata = GeomVertexData('', format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') vertex.addData3f(x1, 0, z1) vertex.addData3f(x2, 0, z2) for _i in range(2): normal.addData3f(0, - 1, 0) prim_hint = Geom.UHStatic prim = GeomLines(prim_hint) prim.addVertices(0, 1) prim.closePrimitive() geom = Geom(vdata) geom.addPrimitive(prim) node = GeomNode('') node.addGeom(geom) return (node, vdata)
def create_table_geom(): format = GeomVertexFormat.getV3n3c4t2() # GeomVertexData. vdata = GeomVertexData('table_vertex', format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') texcoord = GeomVertexWriter(vdata, 'texcoord') vertex.addData3f(xmax, ymin, 0) normal.addData3f(0, 0, 1) color.addData4f(0, 0, 1, 1) texcoord.addData2f(1, 0) vertex.addData3f(xmax, ymax, 0) normal.addData3f(0, 0, 1) color.addData4f(0, 0, 1, 1) texcoord.addData2f(1, 1) vertex.addData3f(xmin, ymax, 0) normal.addData3f(0, 0, 1) color.addData4f(0, 0, 1, 1) texcoord.addData2f(0, 1) vertex.addData3f(xmin, ymin, 0) normal.addData3f(0, 0, 1) color.addData4f(0, 0, 1, 1) texcoord.addData2f(0, 0) prim = GeomTriangles(Geom.UHStatic) prim.addVertex(0) prim.addVertex(1) prim.addVertex(2) prim.closePrimitive() prim.addVertex(0) prim.addVertex(2) prim.addVertex(3) prim.closePrimitive() geom = Geom(vdata) geom.addPrimitive(prim) return geom
def init_node_path(self): if self.node_path: self.node_path.remove() vdata = GeomVertexData('name_me', self.format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') primitive = GeomTristrips(Geom.UHStatic) vertex.addData3f(-2.0, -2.0, -2.0) vertex.addData3f(2.0, -2.0, -2.0) vertex.addData3f(0, 2.0, -2.0) vertex.addData3f(0, 0, 2.0) vertex.addData3f(-2.0, -2.0, -2.0) vertex.addData3f(0, 0, 2.0) vertex.addData3f(2.0, -2.0, -2.0) vertex.addData3f(0, 0, 2.0) vertex.addData3f(0, 2.0, -2.0) color_tuple = (1.0, 1.0, 1.0) if self.point == 'A': color_tuple = (1.0, 0.0, 0.0) elif self.point == 'B': color_tuple = (0.0, 1.0, 0.0) elif self.point == 'C': color_tuple = (0.0, 0.0, 1.0) elif self.point == 'D': color_tuple = (1.0, 1.0, 0.0) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) color.addData4f(*color_tuple + (1.0,)) primitive.addNextVertices(9) primitive.closePrimitive() geom = Geom(vdata) geom.addPrimitive(primitive) node = GeomNode('gnode') node.addGeom(geom) self.node_path = self.parent.parent.node_path_ui.attachNewNode(node) self.node_path.setP(180) self.node_path.setPos(*coords_to_panda(*self.coords))
def makeCircle(vdata, numVertices=40,offset=Vec3(0,0,0), direction=1): circleGeom=Geom(vdata) vertWriter=GeomVertexWriter(vdata, "vertex") normalWriter=GeomVertexWriter(vdata, "normal") colorWriter=GeomVertexWriter(vdata, "color") uvWriter=GeomVertexWriter(vdata, "texcoord") drawWriter=GeomVertexWriter(vdata, "drawFlag") #make sure we start at the end of the GeomVertexData so we dont overwrite anything #that might be there already startRow=vdata.getNumRows() vertWriter.setRow(startRow) colorWriter.setRow(startRow) uvWriter.setRow(startRow) normalWriter.setRow(startRow) drawWriter.setRow(startRow) angle=2*math.pi/numVertices currAngle=angle for i in range(numVertices): position=Vec3(math.cos(currAngle)+offset.getX(), math.sin(currAngle)+offset.getY(),offset.getZ()) vertWriter.addData3f(position) uvWriter.addData2f(position.getX()/2.0+0.5,position.getY()/2.0+0.5) colorWriter.addData4f(1.0, 1.0, 1.0, 1.0) position.setZ(position.getZ()*direction) position.normalize() normalWriter.addData3f(position) #at default Opengl only draws "front faces" (all shapes whose vertices are arranged CCW). We #need direction so we can specify which side we want to be the front face currAngle+=angle*direction circle=GeomTrifans(Geom.UHStatic) circle.addConsecutiveVertices(startRow, numVertices) circle.closePrimitive() circleGeom.addPrimitive(circle) return circleGeom
class HalfEdgeMeshNode(GeomNode): def __init__(self, name, halfedge_mesh, color, wireframe=False): GeomNode.__init__(self, name) self._halfedge_mesh = halfedge_mesh self._color = color self._wireframe = wireframe self._create_vertex_data() self._create_geoms() # set visualisation parameters if self._wireframe: self.setAttrib(RenderModeAttrib.make(RenderModeAttrib.MWireframe, 2, 1)) self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone)) def _create_vertex_data(self): """Creates and fills the vertex data store.""" format = GeomVertexFormat.getV3n3cp() vdata = GeomVertexData("surface", format, Geom.UHDynamic) tri = GeomTriangles(Geom.UHDynamic) vertex = GeomVertexWriter(vdata, "vertex") normal = GeomVertexWriter(vdata, "normal") color = GeomVertexWriter(vdata, "color") for triangle in self._halfedge_mesh.faces: for v in triangle.iter_vertices(): vertex.addData3f(*v.coordinates) normal.addData3f(*v.normal) color.addData4f(*self._color) tri.addNextVertices(1) self._vdata = vdata tri.closePrimitive() self._geom_primitives = [tri] def _create_geoms(self): """Creates a Geom attached to self and adds the current primitives.""" self._geom = Geom(self._vdata) for primitive in self._geom_primitives: self._geom.addPrimitive(primitive) self.addGeom(self._geom)
def init_node_path(self): if self.node_path: self.node_path.remove() vdata = GeomVertexData('name_me', self.format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') primitive = GeomLines(Geom.UHStatic) vertex.addData3f(*coords_to_panda(*self.vector)) vertex.addData3f(*coords_to_panda(*[-x for x in self.vector])) color.addData4f((1.0, 0.0, 0.0, 1.0,)) color.addData4f((0.0, 0.0, 1.0, 1.0,)) primitive.addNextVertices(2) primitive.closePrimitive() geom = Geom(vdata) geom.addPrimitive(primitive) node = GeomNode('gnode') node.addGeom(geom) self.node_path = self.parent.parent.node_path_ui.attachNewNode(node) self.node_path.setScale(20) self.node_path.setPos(*coords_to_panda(*self.coords))
def makeCylinder(vdata,numVertices=40): topCircleGeom=makeCircle(vdata, numVertices,Vec3(0,0, 1)) bottomCircleGeom=makeCircle(vdata, numVertices,Vec3(0,0,0),-1) body=GeomTristrips(Geom.UHStatic) j=40 i=0 while i < numVertices+1: body.addVertex(i) body.addVertex(j) i+=1 if j==40: j=2*numVertices-1 else: j-=1 body.addVertex(i) body.addVertex(j) j-=1 i+=1 body.addVertex(numVertices-1) body.addVertex(0) body.addVertex(numVertices) body.closePrimitive() #print body cylinderGeom=Geom(vdata) cylinderGeom.addPrimitive(body) cylinderGeom.copyPrimitivesFrom(topCircleGeom) cylinderGeom.copyPrimitivesFrom(bottomCircleGeom) cylinderGeom.decomposeInPlace() cylinderGeom.unifyInPlace() return cylinderGeom
def drawRect(self, width, height, axis): # since we're doing line segments, just vertices in our geom format = GeomVertexFormat.getV3() # build our data structure and get a handle to the vertex column vdata = GeomVertexData('', format, Geom.UHStatic) vertices = GeomVertexWriter(vdata, 'vertex') # build a linestrip vertex buffer lines = GeomLinestrips(Geom.UHStatic) # draw a box if axis == "x": vertices.addData3f(0, -width, -height) vertices.addData3f(0, width, -height) vertices.addData3f(0, width, height) vertices.addData3f(0, -width, height) if axis == "y": vertices.addData3f(-width, 0, -height) vertices.addData3f(width, 0, -height) vertices.addData3f(width, 0, height) vertices.addData3f(-width, 0, height) if axis == "z": vertices.addData3f(-width, -height, 0) vertices.addData3f(width, -height, 0) vertices.addData3f(width, height, 0) vertices.addData3f(-width, height, 0) for i in range(1, 3): lines.addVertices(i - 1, i) lines.addVertices(3, 0) lines.closePrimitive() geom = Geom(vdata) geom.addPrimitive(lines) # Add our primitive to the geomnode self.gnode.addGeom(geom)
def generate(self): format = GeomVertexFormat.getV3() data = GeomVertexData("Data", format, Geom.UHStatic) vertices = GeomVertexWriter(data, "vertex") size = self.size vertices.addData3f(-size, -size, -size) vertices.addData3f(+size, -size, -size) vertices.addData3f(-size, +size, -size) vertices.addData3f(+size, +size, -size) vertices.addData3f(-size, -size, +size) vertices.addData3f(+size, -size, +size) vertices.addData3f(-size, +size, +size) vertices.addData3f(+size, +size, +size) triangles = GeomTriangles(Geom.UHStatic) def addQuad(v0, v1, v2, v3): triangles.addVertices(v0, v1, v2) triangles.addVertices(v0, v2, v3) triangles.closePrimitive() addQuad(4, 5, 7, 6) # Z+ addQuad(0, 2, 3, 1) # Z- addQuad(3, 7, 5, 1) # X+ addQuad(4, 6, 2, 0) # X- addQuad(2, 6, 7, 3) # Y+ addQuad(0, 1, 5, 4) # Y+ geom = Geom(data) geom.addPrimitive(triangles) node = GeomNode("CubeMaker") node.addGeom(geom) path = NodePath(node) path.setColor(1.0, 0.0, 1.0) return NodePath(node)
def rect (self, width, height, axis): # since we're doing line segments, just vertices in our geom format = GeomVertexFormat.getV3() # build our data structure and get a handle to the vertex column vdata = GeomVertexData ('', format, Geom.UHStatic) vertices = GeomVertexWriter (vdata, 'vertex') # build a linestrip vertex buffer lines = GeomLinestrips (Geom.UHStatic) # draw a box if axis == "x": vertices.addData3f (0, -width, -height) vertices.addData3f (0, width, -height) vertices.addData3f (0, width, height) vertices.addData3f (0, -width, height) if axis == "y": vertices.addData3f (-width, 0, -height) vertices.addData3f (width, 0, -height) vertices.addData3f (width, 0, height) vertices.addData3f (-width, 0, height) if axis == "z": vertices.addData3f (-width, -height, 0) vertices.addData3f (width, -height, 0) vertices.addData3f (width, height, 0) vertices.addData3f (-width, height, 0) for i in range (1, 3): lines.addVertices(i - 1, i) lines.addVertices (3, 0) lines.closePrimitive() geom = Geom (vdata) geom.addPrimitive (lines) # Add our primitive to the geomnode self.gnode.addGeom (geom)
def line (self, start, end): # since we're doing line segments, just vertices in our geom format = GeomVertexFormat.getV3() # build our data structure and get a handle to the vertex column vdata = GeomVertexData ('', format, Geom.UHStatic) vertices = GeomVertexWriter (vdata, 'vertex') # build a linestrip vertex buffer lines = GeomLinestrips (Geom.UHStatic) vertices.addData3f (start[0], start[1], start[2]) vertices.addData3f (end[0], end[1], end[2]) lines.addVertices (0, 1) lines.closePrimitive() geom = Geom (vdata) geom.addPrimitive (lines) # Add our primitive to the geomnode self.gnode.addGeom (geom)
def drawLine(self, start, end): # since we're doing line segments, just vertices in our geom format = GeomVertexFormat.getV3() # build our data structure and get a handle to the vertex column vdata = GeomVertexData('', format, Geom.UHStatic) vertices = GeomVertexWriter(vdata, 'vertex') # build a linestrip vertex buffer lines = GeomLinestrips(Geom.UHStatic) vertices.addData3f(start[0], start[1], start[2]) vertices.addData3f(end[0], end[1], end[2]) lines.addVertices(0, 1) lines.closePrimitive() geom = Geom(vdata) geom.addPrimitive(lines) # Add our primitive to the geomnode self.gnode.addGeom(geom)
def draw(self): format = GeomVertexFormat.getV3n3cpt2() vdata = GeomVertexData('square', format, Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') circle = Geom(vdata) # Create vertices vertex.addData3f(self.pos) color.addData4f(self.color) for v in range(self._EDGES): x = self.pos.getX() + (self.size * math.cos( (2 * math.pi / self._EDGES) * v)) y = self.pos.getY() + (self.size * math.sin( (2 * math.pi / self._EDGES) * v)) z = self.pos.getZ() vertex.addData3f(x, y, z) color.addData4f(self.color) # Create triangles for t in range(self._EDGES): tri = GeomTriangles(Geom.UHDynamic) tri.addVertex(0) tri.addVertex(t + 1) if (t + 2) > self._EDGES: tri.addVertex(1) else: tri.addVertex(t + 2) tri.closePrimitive() circle.addPrimitive(tri) gn = GeomNode('Circle') gn.addGeom(circle) np = NodePath(gn) np.setHpr(0, 90, 0) return np
def pandaRender(self): frameList = [] for node in self.compositeFrames.getiterator('composite-frame'): if node.tag == "composite-frame" and node.attrib.get("id") == str(self.internalFrameIndex): for frameCallNode in node: for frameNode in self.frames.getiterator('frame'): if frameNode.tag == "frame" and frameNode.attrib.get("id") == frameCallNode.attrib.get("id"): offsetX = 0 if frameCallNode.attrib.get("offset-x") == None else float(frameCallNode.attrib.get("offset-x")) offsetY = 0 if frameCallNode.attrib.get("offset-y") == None else float(frameCallNode.attrib.get("offset-y")) tweenId = frameCallNode.attrib.get("tween") frameInTween = 0 if frameCallNode.attrib.get("frame-in-tween") == None else int(frameCallNode.attrib.get("frame-in-tween")) addWidth = 0 if frameNode.attrib.get("w") == None else float(frameNode.attrib.get("w")) addHeight = 0 if frameNode.attrib.get("h") == None else float(frameNode.attrib.get("h")) sInPixels = 0 if frameNode.attrib.get("s") == None else float(frameNode.attrib.get("s")) tInPixels = 0 if frameNode.attrib.get("t") == None else float(frameNode.attrib.get("t")) swInPixels = sInPixels + addWidth thInPixels = tInPixels + addHeight s = (sInPixels / self.baseWidth) t = 1 - (tInPixels / self.baseHeight) # Complemented to deal with loading image upside down. S = (swInPixels / self.baseWidth) T = 1 - (thInPixels / self.baseHeight) # Complemented to deal with loading image upside down. blend = "overwrite" if frameCallNode.attrib.get("blend") == None else frameCallNode.attrib.get("blend") scaleX = 1 if frameCallNode.attrib.get("scale-x") == None else float(frameCallNode.attrib.get("scale-x")) scaleY = 1 if frameCallNode.attrib.get("scale-y") == None else float(frameCallNode.attrib.get("scale-y")) color = Color(1,1,1,1) tweenHasColor = False frameCallHasColor = False frameCallColorName = frameCallNode.attrib.get("color-name") if frameCallColorName != None: # Get color at frame call as first resort. frameCallHasColor = True for colorNode in self.colors.getiterator('color'): if colorNode.tag == 'color' and colorNode.attrib.get("name") == frameCallColorName: R = 1 if colorNode.attrib.get("r") == None else float(colorNode.attrib.get("r")) G = 1 if colorNode.attrib.get("g") == None else float(colorNode.attrib.get("g")) B = 1 if colorNode.attrib.get("b") == None else float(colorNode.attrib.get("b")) A = 1 if colorNode.attrib.get("a") == None else float(colorNode.attrib.get("a")) color = Color(R, G, B, A) break # leave for loop when we find the correct color pass if tweenId != None and tweenId != "0": # Get color at tween frame as second resort. thisTween = None frameLength = 1 advancementFunction = "linear" foundTween = False pointList = [] colorList = [] for tweenNode in self.tweens.getiterator('motion-tween'): if tweenNode.tag == "motion-tween" and tweenNode.attrib.get("id") == tweenId: foundTween = True frameLength = 1 if tweenNode.attrib.get("length-in-frames") == None else tweenNode.attrib.get("length-in-frames") advancementFunction = "linear" if tweenNode.attrib.get("advancement-function") == None else tweenNode.attrib.get("advancement-function") for pointOrColorNode in tweenNode.getiterator(): if pointOrColorNode.tag == "point": pX = 0 if pointOrColorNode.attrib.get("x") == None else float(pointOrColorNode.attrib.get("x")) pY = 0 if pointOrColorNode.attrib.get("y") == None else float(pointOrColorNode.attrib.get("y")) pointList.append(Point(pX, pY, 0)) elif pointOrColorNode.tag == "color-state": colorName = "white" if pointOrColorNode.attrib.get("name") == None else pointOrColorNode.attrib.get("name") for colorNode in self.colors.getiterator('color'): if colorNode.tag == 'color' and colorNode.attrib.get("name") == colorName: R = 1 if colorNode.attrib.get("r") == None else float(colorNode.attrib.get("r")) G = 1 if colorNode.attrib.get("g") == None else float(colorNode.attrib.get("g")) B = 1 if colorNode.attrib.get("b") == None else float(colorNode.attrib.get("b")) A = 1 if colorNode.attrib.get("a") == None else float(colorNode.attrib.get("a")) colorList.append(Color(R, G, B, A)) break # leave for loop when we find the correct color reference pass # Run through all child nodes of selected tween break # Exit after finding correct tween pass if foundTween: thisTween = Tween(frameLength, advancementFunction, pointList, colorList) offset = thisTween.XYFromFrame(frameInTween); offsetFromTweenX = int(offset.X); offsetFromTweenY = int(offset.Y); offsetX += int(offset.X); offsetY += int(offset.Y); if thisTween.hasColorComponent(): tweenHasColor = True; if frameCallHasColor == False: color = thisTween.colorFromFrame(frameInTween); pass if frameNode.attrib.get("color-name") != None and frameCallHasColor == False and tweenHasColor == False: # Get color at frame definition as last resort. for colorNode in colors.getiterator('color'): if colorNode.tag == 'color' and colorNode.attrib.get("name") == frameNode.attrib.get("color-name"): R = 1 if colorNode.attrib.get("r") == None else float(colorNode.attrib.get("r")) G = 1 if colorNode.attrib.get("g") == None else float(colorNode.attrib.get("g")) B = 1 if colorNode.attrib.get("b") == None else float(colorNode.attrib.get("b")) A = 1 if colorNode.attrib.get("a") == None else float(colorNode.attrib.get("a")) color = Color(R, G, B, A) break # leave for loop when we find the correct color pass rotationZ = 0 if frameCallNode.attrib.get("rotation-z") == None else float(frameCallNode.attrib.get("rotation-z")) frameList.append(Frame(Bound(offsetX, offsetY, addWidth, addHeight), s, t, S, T, blend, scaleX, scaleY, color, rotationZ)) pass break # Leave once we've found the appropriate frame # Prepare tracking list of consumed nodes. self.clearNodesForDrawing() # Make an identifier to tack onto primitive names in Panda3d's scene graph. frameIndexForName = 1 # Loop through loaded frames that make up composite frame. for loadedFrame in frameList: # For debugging purposes, print the object. if False: loadedFrame.printAsString() # Set up place to store primitive 3d object; note: requires vertex data made by GeomVertexData squareMadeByTriangleStrips = GeomTristrips(Geom.UHDynamic) # Set up place to hold 3d data and for the following coordinates: # square's points (V3: x, y, z), # the colors at each point of the square (c4: r, g, b, a), and # for the UV texture coordinates at each point of the square (t2: S, T). vertexData = GeomVertexData('square-'+str(frameIndexForName), GeomVertexFormat.getV3c4t2(), Geom.UHDynamic) vertex = GeomVertexWriter(vertexData, 'vertex') color = GeomVertexWriter(vertexData, 'color') texcoord = GeomVertexWriter(vertexData, 'texcoord') # Add the square's data # Upper-Left corner of square vertex.addData3f(-loadedFrame.bound.Width / 2.0, 0, -loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R,loadedFrame.color.G,loadedFrame.color.B,loadedFrame.color.A) texcoord.addData2f(loadedFrame.s, loadedFrame.T) # Upper-Right corner of square vertex.addData3f(loadedFrame.bound.Width / 2.0, 0, -loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R,loadedFrame.color.G,loadedFrame.color.B,loadedFrame.color.A) texcoord.addData2f(loadedFrame.S, loadedFrame.T) # Lower-Left corner of square vertex.addData3f(-loadedFrame.bound.Width / 2.0, 0, loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R,loadedFrame.color.G,loadedFrame.color.B,loadedFrame.color.A) texcoord.addData2f(loadedFrame.s, loadedFrame.t) # Lower-Right corner of square vertex.addData3f(loadedFrame.bound.Width / 2.0, 0, loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R,loadedFrame.color.G,loadedFrame.color.B,loadedFrame.color.A) texcoord.addData2f(loadedFrame.S, loadedFrame.t) # Pass data to primitive squareMadeByTriangleStrips.addNextVertices(4) squareMadeByTriangleStrips.closePrimitive() square = Geom(vertexData) square.addPrimitive(squareMadeByTriangleStrips) # Pass primtive to drawing node drawPrimitiveNode=GeomNode('square-'+str(frameIndexForName)) drawPrimitiveNode.addGeom(square) # Pass node to scene (effect camera) nodePath = self.effectCameraNodePath.attachNewNode(drawPrimitiveNode) # Linear dodge: if loadedFrame.blendMode == "darken": nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOneMinusFbufferColor, ColorBlendAttrib.OOneMinusIncomingColor)) pass elif loadedFrame.blendMode == "multiply": nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OFbufferColor, ColorBlendAttrib.OZero)) pass elif loadedFrame.blendMode == "color-burn": nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OZero, ColorBlendAttrib.OOneMinusIncomingColor)) pass elif loadedFrame.blendMode == "linear-burn": nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OZero, ColorBlendAttrib.OIncomingColor)) pass elif loadedFrame.blendMode == "lighten": nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MMax, ColorBlendAttrib.OIncomingColor, ColorBlendAttrib.OFbufferColor)) pass elif loadedFrame.blendMode == "color-dodge": nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOne)) pass elif loadedFrame.blendMode == "linear-dodge": nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOneMinusIncomingColor)) pass else: # Overwrite: nodePath.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OIncomingAlpha, ColorBlendAttrib.OOneMinusIncomingAlpha)) pass nodePath.setDepthTest(False) # Apply texture nodePath.setTexture(self.tex) # Apply translation, then rotation, then scaling to node. nodePath.setPos((loadedFrame.bound.X + loadedFrame.bound.Width / 2.0, 1, -loadedFrame.bound.Y - loadedFrame.bound.Height / 2.0)) nodePath.setR(loadedFrame.rotationZ) nodePath.setScale(loadedFrame.scaleX, 1, loadedFrame.scaleY) nodePath.setTwoSided(True) self.consumedNodesList.append(nodePath) frameIndexForName = frameIndexForName + 1 # Loop continues on through each frame called in the composite frame. pass
def drawBody(nodePath, vdata, pos, vecList, radius=1, keepDrawing=True,numVertices=8): circleGeom=Geom(vdata) vertWriter=GeomVertexWriter(vdata, "vertex") colorWriter=GeomVertexWriter(vdata, "color") normalWriter=GeomVertexWriter(vdata, "normal") drawReWriter=GeomVertexRewriter(vdata, "drawFlag") texReWriter=GeomVertexRewriter(vdata, "texcoord") startRow=vdata.getNumRows() vertWriter.setRow(startRow) colorWriter.setRow(startRow) normalWriter.setRow(startRow) sCoord=0 if (startRow!=0): texReWriter.setRow(startRow-numVertices) sCoord=texReWriter.getData2f().getX()+1 drawReWriter.setRow(startRow-numVertices) if(drawReWriter.getData1f()==False): sCoord-=1 drawReWriter.setRow(startRow) texReWriter.setRow(startRow) angleSlice=2*math.pi/numVertices currAngle=0 #axisAdj=Mat4.rotateMat(45, axis)*Mat4.scaleMat(radius)*Mat4.translateMat(pos) perp1=vecList[1] perp2=vecList[2] #vertex information is written here for i in range(numVertices): adjCircle=pos+(perp1*math.cos(currAngle)+perp2*math.sin(currAngle))*radius normal=perp1*math.cos(currAngle)+perp2*math.sin(currAngle) normalWriter.addData3f(normal) vertWriter.addData3f(adjCircle) texReWriter.addData2f(sCoord,(i+0.001)/(numVertices-1)) colorWriter.addData4f(0.5,0.5,0.5,1) drawReWriter.addData1f(keepDrawing) currAngle+=angleSlice drawReader=GeomVertexReader(vdata, "drawFlag") drawReader.setRow(startRow-numVertices) #we cant draw quads directly so we use Tristrips if (startRow!=0) & (drawReader.getData1f()!=False): lines=GeomTristrips(Geom.UHStatic) half=int(numVertices*0.5) for i in range(numVertices): lines.addVertex(i+startRow) if i< half: lines.addVertex(i+startRow-half) else: lines.addVertex(i+startRow-half-numVertices) lines.addVertex(startRow) lines.addVertex(startRow-half) lines.closePrimitive() lines.decompose() circleGeom.addPrimitive(lines) circleGeomNode=GeomNode("Debug") circleGeomNode.addGeom(circleGeom) #I accidentally made the front-face face inwards. Make reverse makes the tree render properly and #should cause any surprises to any poor programmer that tries to use this code circleGeomNode.setAttrib(CullFaceAttrib.makeReverse(),1) global numPrimitives numPrimitives+=numVertices*2 nodePath.attachNewNode(circleGeomNode)
def draw_body(self, position, vector_list, radius = 1, keep_drawing = True, num_vertices = 8): circle_geom = Geom(self.vdata) vertex_writer = GeomVertexWriter(self.vdata, "vertex") color_writer = GeomVertexWriter(self.vdata, "color") normal_writer = GeomVertexWriter(self.vdata, "normal") draw_rewriter = GeomVertexRewriter(self.vdata, "drawFlag") tex_rewriter = GeomVertexRewriter(self.vdata, "texcoord") start_row = self.vdata.getNumRows() vertex_writer.setRow(start_row) color_writer.setRow(start_row) normal_writer.setRow(start_row) sCoord = 0 if start_row != 0: tex_rewriter.setRow(start_row - num_vertices) sCoord = tex_rewriter.getData2f().getX() + 1 draw_rewriter.setRow(start_row - num_vertices) if draw_rewriter.getData1f() == False: sCoord -= 1 draw_rewriter.setRow(start_row) tex_rewriter.setRow(start_row) angle_slice = 2 * math.pi / num_vertices current_angle = 0 perp1 = vector_list[1] perp2 = vector_list[2] # write vertex information for i in range(num_vertices): adjacent_circle = position + (perp1 * math.cos(current_angle) + perp2 * math.sin(current_angle)) * radius normal = perp1 * math.cos(current_angle) + perp2 * math.sin(current_angle) normal_writer.addData3f(normal) vertex_writer.addData3f(adjacent_circle) tex_rewriter.addData2f(sCoord, (i + 0.001) / (num_vertices - 1)) color_writer.addData4f(0.5, 0.5, 0.5, 1.0) draw_rewriter.addData1f(keep_drawing) current_angle += angle_slice draw_reader = GeomVertexReader(self.vdata, "drawFlag") draw_reader.setRow(start_row - num_vertices) # we can't draw quads directly so use Tristrips if start_row != 0 and draw_reader.getData1f() != False: lines = GeomTristrips(Geom.UHStatic) half = int(num_vertices * 0.5) for i in range(num_vertices): lines.addVertex(i + start_row) if i < half: lines.addVertex(i + start_row - half) else: lines.addVertex(i + start_row - half - num_vertices) lines.addVertex(start_row) lines.addVertex(start_row - half) lines.closePrimitive() lines.decompose() circle_geom.addPrimitive(lines) circle_geom_node = GeomNode("Debug") circle_geom_node.addGeom(circle_geom) circle_geom_node.setAttrib(CullFaceAttrib.makeReverse(), 1) self.get_model().attachNewNode(circle_geom_node)
def make_layer(self, i, a, b): # get data data = self.subdata[a][b] # set color + alpha of vertex texture def ap(n): alpha = 0 if i == n: alpha = 1.0 return alpha def tp(n): list = [0, 0, 0, 0] if i == n: list = [1, 1, 1, 0.75] return list # set vertex data vdata = GeomVertexData('plane', GeomVertexFormat.getV3n3c4t2(), Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') uv = GeomVertexWriter(vdata, 'texcoord') # set vertices number = 0 for x in range(0, len(data) - 1): for y in range(0, len(data[x]) - 1): # get vertex data v1 = Vec3(x, y, data[x][y]['h']) c1 = data[x][y]['c'] t1 = data[x][y]['texnum'] v2 = Vec3(x+1, y, data[x+1][y]['h']) c2 = data[x+1][y]['c'] t2 = data[x+1][y]['texnum'] v3 = Vec3(x+1, y+1, data[x+1][y+1]['h']) c3 = data[x+1][y+1]['c'] t3 = data[x+1][y+1]['texnum'] v4 = Vec3(x, y+1, data[x][y+1]['h']) c4 = data[x][y+1]['c'] t4 = data[x][y+1]['texnum'] n=(0, 0, 1) # normal # assign vertex colors + alpha a1, a2, a3, a4 = ap(t1), ap(t2), ap(t3), ap(t4) t1, t2, t3, t4 = tp(t1), tp(t2), tp(t3), tp(t4) if v1[2]==0: t1 = [data[x][y]['c'][0], data[x][y]['c'][1], data[x][y]['c'][2], a1] if v2[2]==0: t2 = [data[x+1][y]['c'][0], data[x+1][y]['c'][1], data[x+1][y]['c'][2], a2] if v3[2]==0: t3 = [data[x+1][y+1]['c'][0], data[x+1][y+1]['c'][1], data[x+1][y+1]['c'][2], a3] if v4[2]==0: t4 = [data[x][y+1]['c'][0], data[x][y+1]['c'][1], data[x][y+1]['c'][2], a4] if a1 == 0 and a2 == 0 and a3 == 0 and a4 == 0: continue # add vertices vertex.addData3f(v1) normal.addData3f(*n) color.addData4f(*t1) uv.addData2f(0,0) vertex.addData3f(v2) normal.addData3f(*n) color.addData4f(*t2) uv.addData2f(1,0) vertex.addData3f(v3) normal.addData3f(*n) color.addData4f(*t3) uv.addData2f(1,1) vertex.addData3f(v1) normal.addData3f(*n) color.addData4f(*t1) uv.addData2f(0,0) vertex.addData3f(v3) normal.addData3f(*n) color.addData4f(*t3) uv.addData2f(1,1) vertex.addData3f(v4) normal.addData3f(*n) color.addData4f(*t4) uv.addData2f(0,1) number = number + 2 # add triangles prim = GeomTriangles(Geom.UHStatic) for n in range(number): prim.addVertices((n * 3) + 2, (n * 3) + 0, (n * 3) + 1) prim.closePrimitive() # make geom geom = Geom(vdata) geom.addPrimitive(prim) # make geom node node = GeomNode("layer" + str(i) + "_" + str(a) + "_" + str(b)) node.addGeom(geom) # make mesh nodePath mesh = NodePath(node) # load and assign texture txfile = self.tiles[i]['tex'] tx = base.loader.loadTexture(txfile) tx.setMinfilter(Texture.FTLinearMipmapLinear) mesh.setDepthTest(DepthTestAttrib.MLessEqual) mesh.setDepthWrite(False) mesh.setTransparency(True) mesh.setTexture(tx) # set render order mesh.setBin("", 1) # locate mesh mesh.setPos(self.divsep * (a * int(len(self.data[a]) / self.div)), self.divsep * (b * int(len(self.data[b]) / self.div)), 0.001) # reparent mesh mesh.reparentTo(self.root) # return mesh return mesh
class SurfaceNode(GeomNode): def __init__(self, name, width, height, points, normals=[], color=(1.0,1.0,1.0,1.0), wireframe=False): GeomNode.__init__(self, name) self._width = width self._height = height assert(len(points) == self._width * self._height) if normals: assert(len(normals) == self._width * self._height) self._points = points self._normals = normals self._color = color self._wireframe = wireframe self._create_vertex_data() self._create_geom_primitives() self._create_geoms() # set visualisation parameters if self._wireframe: self.setAttrib(RenderModeAttrib.make(RenderModeAttrib.MWireframe, 2, 1)) self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone)) def _create_vertex_data(self): """Creates and fills the vertex data store.""" format = GeomVertexFormat.getV3n3cp() vdata = GeomVertexData('plane', format, Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') for x in xrange(self._width): for y in xrange(self._height): cur_index = x * self._height + y vertex.addData3f(*self._points[cur_index][0:3]) if self._normals: normal.addData3f(*self._normals[cur_index]) else: normal.addData3f(0, 0, 1) color.addData4f(*self._color) self._vdata = vdata def _create_geom_primitives(self): """Creates and fill a GeomTriangles with vertex indices.""" tri = GeomTriangles(Geom.UHDynamic) for x in xrange(self._width-1): for y in xrange(self._height-1): cur_index = x * self._height + y tri.addVertex(cur_index) tri.addVertex(cur_index+1) tri.addVertex(cur_index+self._height) tri.addVertex(cur_index+1) tri.addVertex(cur_index+self._height) tri.addVertex(cur_index+self._height+1) tri.closePrimitive() self._geom_primitives = [tri, ] def _create_geoms(self): """Creates a Geom attached to self and adds the current primitives.""" self._geom = Geom(self._vdata) for primitive in self._geom_primitives: self._geom.addPrimitive(primitive) self.addGeom(self._geom)
def pandaRender(self): frameList = [] for node in self.compositeFrames.getiterator("composite-frame"): if node.tag == "composite-frame" and node.attrib.get("id") == str(self.internalFrameIndex): for frameCallNode in node: for frameNode in self.frames.getiterator("frame"): if frameNode.tag == "frame" and frameNode.attrib.get("id") == frameCallNode.attrib.get("id"): offsetX = ( 0 if frameCallNode.attrib.get("offset-x") == None else float(frameCallNode.attrib.get("offset-x")) ) offsetY = ( 0 if frameCallNode.attrib.get("offset-y") == None else float(frameCallNode.attrib.get("offset-y")) ) tweenId = frameCallNode.attrib.get("tween") frameInTween = ( 0 if frameCallNode.attrib.get("frame-in-tween") == None else int(frameCallNode.attrib.get("frame-in-tween")) ) addWidth = 0 if frameNode.attrib.get("w") == None else float(frameNode.attrib.get("w")) addHeight = 0 if frameNode.attrib.get("h") == None else float(frameNode.attrib.get("h")) sInPixels = 0 if frameNode.attrib.get("s") == None else float(frameNode.attrib.get("s")) tInPixels = 0 if frameNode.attrib.get("t") == None else float(frameNode.attrib.get("t")) swInPixels = sInPixels + addWidth thInPixels = tInPixels + addHeight s = sInPixels / self.baseWidth t = 1 - ( tInPixels / self.baseHeight ) # Complemented to deal with loading image upside down. S = swInPixels / self.baseWidth T = 1 - ( thInPixels / self.baseHeight ) # Complemented to deal with loading image upside down. blend = ( "overwrite" if frameCallNode.attrib.get("blend") == None else frameCallNode.attrib.get("blend") ) scaleX = ( 1 if frameCallNode.attrib.get("scale-x") == None else float(frameCallNode.attrib.get("scale-x")) ) scaleY = ( 1 if frameCallNode.attrib.get("scale-y") == None else float(frameCallNode.attrib.get("scale-y")) ) color = Color(1, 1, 1, 1) tweenHasColor = False frameCallHasColor = False frameCallColorName = frameCallNode.attrib.get("color-name") if frameCallColorName != None: # Get color at frame call as first resort. frameCallHasColor = True for colorNode in self.colors.getiterator("color"): if colorNode.tag == "color" and colorNode.attrib.get("name") == frameCallColorName: R = 1 if colorNode.attrib.get("r") == None else float(colorNode.attrib.get("r")) G = 1 if colorNode.attrib.get("g") == None else float(colorNode.attrib.get("g")) B = 1 if colorNode.attrib.get("b") == None else float(colorNode.attrib.get("b")) A = 1 if colorNode.attrib.get("a") == None else float(colorNode.attrib.get("a")) color = Color(R, G, B, A) break # leave for loop when we find the correct color pass if tweenId != None and tweenId != "0": # Get color at tween frame as second resort. thisTween = None frameLength = 1 advancementFunction = "linear" foundTween = False pointList = [] colorList = [] for tweenNode in self.tweens.getiterator("motion-tween"): if tweenNode.tag == "motion-tween" and tweenNode.attrib.get("id") == tweenId: foundTween = True frameLength = ( 1 if tweenNode.attrib.get("length-in-frames") == None else tweenNode.attrib.get("length-in-frames") ) advancementFunction = ( "linear" if tweenNode.attrib.get("advancement-function") == None else tweenNode.attrib.get("advancement-function") ) for pointOrColorNode in tweenNode.getiterator(): if pointOrColorNode.tag == "point": pX = ( 0 if pointOrColorNode.attrib.get("x") == None else float(pointOrColorNode.attrib.get("x")) ) pY = ( 0 if pointOrColorNode.attrib.get("y") == None else float(pointOrColorNode.attrib.get("y")) ) pointList.append(Point(pX, pY, 0)) elif pointOrColorNode.tag == "color-state": colorName = ( "white" if pointOrColorNode.attrib.get("name") == None else pointOrColorNode.attrib.get("name") ) for colorNode in self.colors.getiterator("color"): if ( colorNode.tag == "color" and colorNode.attrib.get("name") == colorName ): R = ( 1 if colorNode.attrib.get("r") == None else float(colorNode.attrib.get("r")) ) G = ( 1 if colorNode.attrib.get("g") == None else float(colorNode.attrib.get("g")) ) B = ( 1 if colorNode.attrib.get("b") == None else float(colorNode.attrib.get("b")) ) A = ( 1 if colorNode.attrib.get("a") == None else float(colorNode.attrib.get("a")) ) colorList.append(Color(R, G, B, A)) break # leave for loop when we find the correct color reference pass # Run through all child nodes of selected tween break # Exit after finding correct tween pass if foundTween: thisTween = Tween(frameLength, advancementFunction, pointList, colorList) offset = thisTween.XYFromFrame(frameInTween) offsetFromTweenX = int(offset.X) offsetFromTweenY = int(offset.Y) offsetX += int(offset.X) offsetY += int(offset.Y) if thisTween.hasColorComponent(): tweenHasColor = True if frameCallHasColor == False: color = thisTween.colorFromFrame(frameInTween) pass if ( frameNode.attrib.get("color-name") != None and frameCallHasColor == False and tweenHasColor == False ): # Get color at frame definition as last resort. for colorNode in colors.getiterator("color"): if colorNode.tag == "color" and colorNode.attrib.get( "name" ) == frameNode.attrib.get("color-name"): R = 1 if colorNode.attrib.get("r") == None else float(colorNode.attrib.get("r")) G = 1 if colorNode.attrib.get("g") == None else float(colorNode.attrib.get("g")) B = 1 if colorNode.attrib.get("b") == None else float(colorNode.attrib.get("b")) A = 1 if colorNode.attrib.get("a") == None else float(colorNode.attrib.get("a")) color = Color(R, G, B, A) break # leave for loop when we find the correct color pass rotationZ = ( 0 if frameCallNode.attrib.get("rotation-z") == None else float(frameCallNode.attrib.get("rotation-z")) ) frameList.append( Frame( Bound(offsetX, offsetY, addWidth, addHeight), s, t, S, T, blend, scaleX, scaleY, color, rotationZ, ) ) pass break # Leave once we've found the appropriate frame # Prepare tracking list of consumed nodes. self.clearNodesForDrawing() # Make an identifier to tack onto primitive names in Panda3d's scene graph. frameIndexForName = 1 # Loop through loaded frames that make up composite frame. for loadedFrame in frameList: # For debugging purposes, print the object. if False: loadedFrame.printAsString() # Set up place to store primitive 3d object; note: requires vertex data made by GeomVertexData squareMadeByTriangleStrips = GeomTristrips(Geom.UHDynamic) # Set up place to hold 3d data and for the following coordinates: # square's points (V3: x, y, z), # the colors at each point of the square (c4: r, g, b, a), and # for the UV texture coordinates at each point of the square (t2: S, T). vertexData = GeomVertexData( "square-" + str(frameIndexForName), GeomVertexFormat.getV3c4t2(), Geom.UHDynamic ) vertex = GeomVertexWriter(vertexData, "vertex") color = GeomVertexWriter(vertexData, "color") texcoord = GeomVertexWriter(vertexData, "texcoord") # Add the square's data # Upper-Left corner of square vertex.addData3f(-loadedFrame.bound.Width / 2.0, 0, -loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R, loadedFrame.color.G, loadedFrame.color.B, loadedFrame.color.A) texcoord.addData2f(loadedFrame.s, loadedFrame.T) # Upper-Right corner of square vertex.addData3f(loadedFrame.bound.Width / 2.0, 0, -loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R, loadedFrame.color.G, loadedFrame.color.B, loadedFrame.color.A) texcoord.addData2f(loadedFrame.S, loadedFrame.T) # Lower-Left corner of square vertex.addData3f(-loadedFrame.bound.Width / 2.0, 0, loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R, loadedFrame.color.G, loadedFrame.color.B, loadedFrame.color.A) texcoord.addData2f(loadedFrame.s, loadedFrame.t) # Lower-Right corner of square vertex.addData3f(loadedFrame.bound.Width / 2.0, 0, loadedFrame.bound.Height / 2.0) color.addData4f(loadedFrame.color.R, loadedFrame.color.G, loadedFrame.color.B, loadedFrame.color.A) texcoord.addData2f(loadedFrame.S, loadedFrame.t) # Pass data to primitive squareMadeByTriangleStrips.addNextVertices(4) squareMadeByTriangleStrips.closePrimitive() square = Geom(vertexData) square.addPrimitive(squareMadeByTriangleStrips) # Pass primtive to drawing node drawPrimitiveNode = GeomNode("square-" + str(frameIndexForName)) drawPrimitiveNode.addGeom(square) # Pass node to scene (effect camera) nodePath = self.effectCameraNodePath.attachNewNode(drawPrimitiveNode) # Linear dodge: if loadedFrame.blendMode == "darken": nodePath.setAttrib( ColorBlendAttrib.make( ColorBlendAttrib.MAdd, ColorBlendAttrib.OOneMinusFbufferColor, ColorBlendAttrib.OOneMinusIncomingColor, ) ) pass elif loadedFrame.blendMode == "multiply": nodePath.setAttrib( ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OFbufferColor, ColorBlendAttrib.OZero) ) pass elif loadedFrame.blendMode == "color-burn": nodePath.setAttrib( ColorBlendAttrib.make( ColorBlendAttrib.MAdd, ColorBlendAttrib.OZero, ColorBlendAttrib.OOneMinusIncomingColor ) ) pass elif loadedFrame.blendMode == "linear-burn": nodePath.setAttrib( ColorBlendAttrib.make( ColorBlendAttrib.MAdd, ColorBlendAttrib.OZero, ColorBlendAttrib.OIncomingColor ) ) pass elif loadedFrame.blendMode == "lighten": nodePath.setAttrib( ColorBlendAttrib.make( ColorBlendAttrib.MMax, ColorBlendAttrib.OIncomingColor, ColorBlendAttrib.OFbufferColor ) ) pass elif loadedFrame.blendMode == "color-dodge": nodePath.setAttrib( ColorBlendAttrib.make(ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOne) ) pass elif loadedFrame.blendMode == "linear-dodge": nodePath.setAttrib( ColorBlendAttrib.make( ColorBlendAttrib.MAdd, ColorBlendAttrib.OOne, ColorBlendAttrib.OOneMinusIncomingColor ) ) pass else: # Overwrite: nodePath.setAttrib( ColorBlendAttrib.make( ColorBlendAttrib.MAdd, ColorBlendAttrib.OIncomingAlpha, ColorBlendAttrib.OOneMinusIncomingAlpha ) ) pass nodePath.setDepthTest(False) # Apply texture nodePath.setTexture(self.tex) # Apply translation, then rotation, then scaling to node. nodePath.setPos( ( loadedFrame.bound.X + loadedFrame.bound.Width / 2.0, 1, -loadedFrame.bound.Y - loadedFrame.bound.Height / 2.0, ) ) nodePath.setR(loadedFrame.rotationZ) nodePath.setScale(loadedFrame.scaleX, 1, loadedFrame.scaleY) nodePath.setTwoSided(True) self.consumedNodesList.append(nodePath) frameIndexForName = frameIndexForName + 1 # Loop continues on through each frame called in the composite frame. pass
def draw(self): format = GeomVertexFormat.getV3n3cpt2() vdata = GeomVertexData('square', format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') texcoord = GeomVertexWriter(vdata, 'texcoord') #make sure we draw the sqaure in the right plane #if x1!=x2: vertex.addData3f(self.x1, self.y1, self.z1) vertex.addData3f(self.x2, self.y1, self.z1) vertex.addData3f(self.x2, self.y2, self.z2) vertex.addData3f(self.x1, self.y2, self.z2) normal.addData3f( Vec3(2 * self.x1 - 1, 2 * self.y1 - 1, 2 * self.z1 - 1).normalize()) normal.addData3f( Vec3(2 * self.x2 - 1, 2 * self.y1 - 1, 2 * self.z1 - 1).normalize()) normal.addData3f( Vec3(2 * self.x2 - 1, 2 * self.y2 - 1, 2 * self.z2 - 1).normalize()) normal.addData3f( Vec3(2 * self.x1 - 1, 2 * self.y2 - 1, 2 * self.z2 - 1).normalize()) #adding different colors to the vertex for visibility color.addData4f(self.r, self.g, self.b, self.a) color.addData4f(self.r, self.g, self.b, self.a) color.addData4f(self.r, self.g, self.b, self.a) color.addData4f(self.r, self.g, self.b, self.a) texcoord.addData2f(0.0, 1.0) texcoord.addData2f(0.0, 0.0) texcoord.addData2f(1.0, 0.0) texcoord.addData2f(1.0, 1.0) #quads arent directly supported by the Geom interface #you might be interested in the CardMaker class if you are #interested in rectangle though tri1 = GeomTriangles(Geom.UHStatic) tri2 = GeomTriangles(Geom.UHStatic) tri1.addVertex(0) tri1.addVertex(1) tri1.addVertex(3) tri2.addConsecutiveVertices(1, 3) tri1.closePrimitive() tri2.closePrimitive() square = Geom(vdata) square.addPrimitive(tri1) square.addPrimitive(tri2) #square.setIntoCollideMask(BitMask32.bit(1)) self.squareNP = NodePath(GeomNode('square gnode')) self.squareNP.node().addGeom(square) self.squareNP.setTransparency(1) self.squareNP.setAlphaScale(.5) self.squareNP.setTwoSided(True) #squareNP.setCollideMask(BitMask32.bit(1)) self.squareNP.reparentTo(self.parent) return self.squareNP
class MarchingCubeNode(GeomNode): def __init__(self, name, surface, color, wireframe=False): GeomNode.__init__(self, name) self._surface = surface self._color = color self._wireframe = wireframe self._init_tables() self._create_vertex_data() self._create_geoms() # set visualisation parameters if self._wireframe: self.setAttrib(RenderModeAttrib.make(RenderModeAttrib.MWireframe, 2, 1)) self.setAttrib(CullFaceAttrib.make(CullFaceAttrib.MCullNone)) def _create_vertex_data(self): """Creates and fills the vertex data store.""" format = GeomVertexFormat.getV3n3cp() vdata = GeomVertexData('surface', format, Geom.UHDynamic) tri = GeomTriangles(Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') vertmap = [(0, 1), (1, 2), (2, 3), (3, 0), (4, 5), (5, 6), (6, 7), (7, 4), (0, 4), (1, 5), (2, 6), (3, 7)] def generate_index(x, y, z): return x + \ y * (self._surface.mls_subdivisions+2) + \ z * (self._surface.mls_subdivisions+2)**2 numbering_scheme = [ (0, 0, 1), (1, 0, 1), (1, 0, 0), (0, 0, 0), (0, 1, 1), (1, 1, 1), (1, 1, 0), (0, 1, 0)] vertices = zeros((12,), dtype='3f') vertex_normals = zeros((12,), dtype='3f') # walk the cubes for x_index in range(self._surface.mls_subdivisions+1): for y_index in range(self._surface.mls_subdivisions+1): for z_index in range(self._surface.mls_subdivisions+1): #points = map(lambda offsets: self._surface.mls_points[generate_index(array([x_index, y_index, z_index]) + offsets)], numbering_scheme) points = [ self._surface.mls_points[generate_index(x_index + 0, y_index + 0, z_index + 1)], self._surface.mls_points[generate_index(x_index + 1, y_index + 0, z_index + 1)], self._surface.mls_points[generate_index(x_index + 1, y_index + 0, z_index + 0)], self._surface.mls_points[generate_index(x_index + 0, y_index + 0, z_index + 0)], self._surface.mls_points[generate_index(x_index + 0, y_index + 1, z_index + 1)], self._surface.mls_points[generate_index(x_index + 1, y_index + 1, z_index + 1)], self._surface.mls_points[generate_index(x_index + 1, y_index + 1, z_index + 0)], self._surface.mls_points[generate_index(x_index + 0, y_index + 1, z_index + 0)], ] values = [ self._surface.mls_distances[generate_index(x_index + 0, y_index + 0, z_index + 1)], self._surface.mls_distances[generate_index(x_index + 1, y_index + 0, z_index + 1)], self._surface.mls_distances[generate_index(x_index + 1, y_index + 0, z_index + 0)], self._surface.mls_distances[generate_index(x_index + 0, y_index + 0, z_index + 0)], self._surface.mls_distances[generate_index(x_index + 0, y_index + 1, z_index + 1)], self._surface.mls_distances[generate_index(x_index + 1, y_index + 1, z_index + 1)], self._surface.mls_distances[generate_index(x_index + 1, y_index + 1, z_index + 0)], self._surface.mls_distances[generate_index(x_index + 0, y_index + 1, z_index + 0)], ] #values = map(lambda offsets: self._surface.mls_distances[generate_index(array([x_index, y_index, z_index]) + offsets)], numbering_scheme) cubeindex = self._get_cubeindex(values) for n in range(12): if self.edge_table[cubeindex] & (2**n): t_v, t_n = self._interpolate(points[vertmap[n][0]], points[vertmap[n][1]], values[vertmap[n][0]], values[vertmap[n][1]]) vertices[n] = t_v vertex_normals[n] = t_n/norm(t_n) else: vertices[n] = 0 vertex_normals[n] = 0 triangles = [] i = 0 while self.triangle_table[cubeindex][i] != -1: triangles.append([self.triangle_table[cubeindex][i], self.triangle_table[cubeindex][i+1], self.triangle_table[cubeindex][i+2]]) i += 3 for triangle in triangles: vertex.addData3f(*vertices[triangle[0]]) vertex.addData3f(*vertices[triangle[1]]) vertex.addData3f(*vertices[triangle[2]]) normal.addData3f(*vertex_normals[triangle[0]]) normal.addData3f(*vertex_normals[triangle[1]]) normal.addData3f(*vertex_normals[triangle[2]]) #color.addData4f(self._color[0], self._color[1], self._color[2], self._color[3]) #color.addData4f(self._color[0], self._color[1], self._color[2], self._color[3]) #color.addData4f(self._color[0], self._color[1], self._color[2], self._color[3]) color.addData4f(*self._color) color.addData4f(*self._color) color.addData4f(*self._color) tri.addNextVertices(3) self._vdata = vdata tri.closePrimitive() self._geom_primitives = [tri, ] def _iter_cells(self): def generate_index(point): x, y, z = point return x + \ y * (self._surface.mls_subdivisions+2) + \ z * (self._surface.mls_subdivisions+2)**2 numbering_scheme = [ (0, 0, 1), (1, 0, 1), (1, 0, 0), (0, 0, 0), (0, 1, 1), (1, 1, 1), (1, 1, 0), (0, 1, 0)] for x_index in range(self._surface.mls_subdivisions+1): for y_index in range(self._surface.mls_subdivisions+1): for z_index in range(self._surface.mls_subdivisions+1): coordinates = map(lambda offsets: self._surface.mls_points[generate_index(array([x_index, y_index, z_index]) + offsets)], numbering_scheme) values = map(lambda offsets: self._surface.mls_distances[generate_index(array([x_index, y_index, z_index]) + offsets)], numbering_scheme) #print("y") yield (coordinates, values) def _get_cubeindex(self, values): cubeindex = 0 for n in range(8): if values[n] < 0: cubeindex |= 2**n return cubeindex def _interpolate(self, point1, point2, value1, value2): point = point1 + (-value1) * (point2 - point1) / (value2 - value1) return (point, self._surface.square_solver.get_normal(point, self._surface.mls_degree)) def _create_geoms(self): """Creates a Geom attached to self and adds the current primitives.""" self._geom = Geom(self._vdata) for primitive in self._geom_primitives: self._geom.addPrimitive(primitive) self.addGeom(self._geom) def _init_tables(self): self.edge_table = array([ 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0]) self.triangle_table = [ [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1], [3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1], [3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1], [3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1], [9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1], [1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1], [9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1], [2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1], [8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1], [9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1], [4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1], [3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1], [1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1], [4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1], [4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1], [9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1], [1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1], [5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1], [2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1], [9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1], [0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1], [2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1], [10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1], [4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1], [5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1], [5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1], [9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1], [0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1], [1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1], [10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1], [8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1], [2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1], [7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1], [9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1], [2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1], [11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1], [9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1], [5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1], [11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1], [11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1], [1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1], [9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1], [5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1], [2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1], [0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1], [5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1], [6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1], [0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1], [3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1], [6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1], [5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1], [1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1], [10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1], [6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1], [1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1], [8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1], [7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1], [3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1], [5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1], [0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1], [9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1], [8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1], [5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1], [0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1], [6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1], [10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1], [10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1], [8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1], [1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1], [3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1], [0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1], [10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1], [0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1], [3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1], [6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1], [9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1], [8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1], [3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1], [6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1], [0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1], [10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1], [10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1], [1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1], [2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1], [7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1], [7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1], [2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1], [1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1], [11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1], [8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1], [0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1], [7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1], [10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1], [2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1], [6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1], [7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1], [2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1], [1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1], [10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1], [10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1], [0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1], [7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1], [6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1], [8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1], [9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1], [6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1], [1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1], [4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1], [10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1], [8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1], [0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1], [1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1], [8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1], [10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1], [4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1], [10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1], [5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1], [11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1], [9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1], [6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1], [7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1], [3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1], [7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1], [9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1], [3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1], [6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1], [9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1], [1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1], [4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1], [7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1], [6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1], [3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1], [0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1], [6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1], [1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1], [0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1], [11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1], [6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1], [5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1], [9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1], [1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1], [1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1], [10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1], [0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1], [5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1], [10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1], [11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1], [0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1], [9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1], [7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1], [2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1], [8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1], [9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1], [9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1], [1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1], [9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1], [9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1], [5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1], [0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1], [10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1], [2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1], [0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1], [0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1], [9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1], [5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1], [3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1], [5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1], [8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1], [0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1], [9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1], [0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1], [1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1], [3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1], [4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1], [9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1], [11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1], [11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1], [2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1], [9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1], [3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1], [1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1], [4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1], [4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1], [0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1], [3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1], [3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1], [0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1], [9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1], [1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]]
def generate_sphere(name, radius, resolution): """ Generates a sphere with the provided resolution. @type name: string @param name: Name of this sphere. @type radius: number @param radius: Radius of sphere in kilometers. @type resolution: number @param resolution: Resolution of sphere (minimum 2) @rtype: GeomNode @return: A GeomNode with the given sphere. """ if resolution < 2: raise ValueError, "resolution must be >= 2" horizBands = resolution*2 vertBands = horizBands*2 vertexFormat = GeomVertexFormat.getV3n3c4t2() vdata = GeomVertexData('%s_vdata' % name, vertexFormat, Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') color = GeomVertexWriter(vdata, 'color') normal = GeomVertexWriter(vdata, 'normal') texcoord = GeomVertexWriter(vdata, 'texcoord') vertDelta = omath.TWOPI / vertBands horizDelta = omath.TWOPI / horizBands numVertices = 0 for i in range(vertBands+1): lowTheta = i * vertDelta highTheta = (i+1) * vertDelta cosLowTheta = math.cos(lowTheta) sinLowTheta = math.sin(lowTheta) cosHighTheta = math.cos(highTheta) sinHighTheta = math.sin(highTheta) for j in range(horizBands): horizTheta = j * horizDelta cosHorizTheta = math.cos(horizTheta) sinHorizTheta = math.sin(horizTheta) ex = cosLowTheta*cosHorizTheta ey = sinLowTheta ez = cosLowTheta*sinHorizTheta vertex.addData3f(ex*radius, ey*radius, ez*radius) normal.addData3f(ex, ey, ez) color.addData4f(.75, .75, .75, 1) texcoord.addData2f(i / vertBands, j / horizBands) ex = cosHighTheta*cosHorizTheta ey = sinHighTheta ez = cosHighTheta*sinHorizTheta vertex.addData3f(ex*radius, ey*radius, ez*radius) normal.addData3f(ex, ey, ez) color.addData4f(.75, .75, .75, 1) texcoord.addData2f(i / vertBands, j / horizBands) numVertices += 2 prim = GeomTristrips(Geom.UHStatic) prim.addConsecutiveVertices(0, numVertices) prim.closePrimitive() geom = Geom(vdata) geom.addPrimitive(prim) geomNode = GeomNode(name) geomNode.addGeom(geom) return GeomScaler(geomNode)
def __init__(self, inner, outer, sectors): super(RingNode, self).__init__('ring') self.inner = inner self.outer = outer self.sectors = sectors ringgeo = RawGeometry() # inner and outer radii are the true circular limits, so expand a little bit # for the sectored mesh mesh_inner = self.inner * 0.9 mesh_outer = self.outer * 1.1 angular_width = 2.0 * math.pi / self.sectors for sector in range(self.sectors): start = sector * angular_width end = (sector + 1) * angular_width # add a quad x0 = math.sin(start) * mesh_inner x1 = math.sin(start) * mesh_outer x2 = math.sin(end) * mesh_inner x3 = math.sin(end) * mesh_outer z0 = math.cos(start) * mesh_inner z1 = math.cos(start) * mesh_outer z2 = math.cos(end) * mesh_inner z3 = math.cos(end) * mesh_outer index = len(ringgeo.verts) ringgeo.verts.append((x0, 0, z0)) ringgeo.verts.append((x1, 0, z1)) ringgeo.verts.append((x2, 0, z2)) ringgeo.verts.append((x3, 0, z3)) # double-side the faces so they render from either side # top pair... ringgeo.faces.append((index + 0, index + 1, index + 2)) ringgeo.faces.append((index + 1, index + 3, index + 2)) # bottom pair... ringgeo.faces.append((index + 0, index + 2, index + 1)) ringgeo.faces.append((index + 1, index + 2, index + 3)) format = GeomVertexFormat.getV3n3() vdata = GeomVertexData('ring', format, Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') for (x, y, z) in ringgeo.verts: vertex.addData3f(x, y, z) normal.addData3f(0, 1, 0) trilist = GeomTriangles(Geom.UHDynamic) for (a, b, c) in ringgeo.faces: trilist.addVertex(a) trilist.addVertex(b) trilist.addVertex(c) trilist.closePrimitive() ring = Geom(vdata) ring.addPrimitive(trilist) self.addGeom(ring)
def addGeometry(self, geomData): debugGui = dict() format = GeomVertexFormat.getV3n3t2() vdata = GeomVertexData('name', format, Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') texcoord = GeomVertexWriter(vdata, 'texcoord') prim = GeomTriangles(Geom.UHStatic) postphonedTriangles = list() vtxTargetId0 = vtxTargetId1 = vtxTargetId2 = None vtxDataCounter = 0 for vtxSourceId0, vtxSourceId1, vtxSourceId2 in geomData.triangles: vx0,vy0,vz0 = v0 = geomData.getVertex(vtxSourceId0) vx1,vy1,vz1 = v1 = geomData.getVertex(vtxSourceId1) vx2,vy2,vz2 = v2 = geomData.getVertex(vtxSourceId2) # prepare the vertices uvx0, uvy0 = uv0 = geomData.getUv(vtxSourceId0) uvx1, uvy1 = uv1 = geomData.getUv(vtxSourceId1) uvx2, uvy2 = uv2 = geomData.getUv(vtxSourceId2) # n0 = geomData.getNormal(vtxSourceId0) n1 = geomData.getNormal(vtxSourceId1) n2 = geomData.getNormal(vtxSourceId2) # make it wrap nicely if min(uvx0,uvx1,uvx2) < .25 and max(uvx0,uvx1,uvx2) > 0.75: if uvx0 < 0.25: uvx0 += 1.0 if uvx1 < 0.25: uvx1 += 1.0 if uvx2 < 0.25: uvx2 += 1.0 vertex.addData3f(*v0) normal.addData3f(*n0) texcoord.addData2f(*uv0) vtxTargetId0 = vtxDataCounter vtxDataCounter += 1 vertex.addData3f(*v1) normal.addData3f(*n1) texcoord.addData2f(*uv1) vtxTargetId1 = vtxDataCounter vtxDataCounter += 1 vertex.addData3f(*v2) normal.addData3f(*n2) texcoord.addData2f(*uv2) vtxTargetId2 = vtxDataCounter vtxDataCounter += 1 prim.addVertex(vtxTargetId0) prim.addVertex(vtxTargetId1) prim.addVertex(vtxTargetId2) prim.closePrimitive() if False: if vtxSourceId0 not in debugGui: i = InfoTextBillaboarded(render) i.setScale(0.05) i.billboardNodePath.setPos(Vec3(x0,y0,z0)*1.1) i.setText('%i: %.1f %.1f %.1f\n%.1f %.1f' % (vtxSourceId0, x0,y0,z0, nx0, ny0)) debugGui[vtxSourceId0] = i if vtxSourceId1 not in debugGui: i = InfoTextBillaboarded(render) i.setScale(0.05) i.billboardNodePath.setPos(Vec3(x1,y1,z1)*1.1) i.setText('%i: %.1f %.1f %.1f\n%.1f %.1f' % (vtxSourceId1, x1,y1,z1, nx1, ny1)) debugGui[vtxSourceId1] = i if vtxSourceId2 not in debugGui: i = InfoTextBillaboarded(render) i.setScale(0.05) i.billboardNodePath.setPos(Vec3(x2,y2,z2)*1.1) i.setText('%i: %.1f %.1f %.1f\n%.1f %.1f' % (vtxSourceId2, x2,y2,z2, nx2, ny2)) debugGui[vtxSourceId2] = i geom = Geom(vdata) geom.addPrimitive(prim) node = GeomNode('gnode') node.addGeom(geom) nodePath = self.attachNewNode(node) return nodePath
def make_base(self, a, b): # get data data = self.subdata[a][b] # set vertex data vdata = GeomVertexData('plane', GeomVertexFormat.getV3n3c4t2(), Geom.UHStatic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') color = GeomVertexWriter(vdata, 'color') uv = GeomVertexWriter(vdata, 'texcoord') # set vertices number = 0 for x in range(0, len(data) - 1): for y in range(0, len(data[x]) - 1): # get vertex data v1 = Vec3(x, y, data[x][y]['h']) v2 = Vec3(x + 1, y, data[x+1][y]['h']) v3 = Vec3(x + 1, y + 1, data[x+1][y+1]['h']) v4 = Vec3(x, y + 1, data[x][y+1]['h']) n = (0, 0, 1) # normal # assign vertex colors + alpha option = 1 # black if option == 1: c = 0 c1 = [c, c, c, 1] c2 = [c, c, c, 1] c3 = [c, c, c, 1] c4 = [c, c, c, 1] # option2: color vertices if option == 2: alpha = 1.0 c1 = [data[x][y]['c'][0], data[x][y]['c'][1], data[x][y]['c'][2], alpha] c2 = [data[x+1][y]['c'][0], data[x+1][y]['c'][1], data[x+1][y]['c'][2], alpha] c3 = [data[x+1][y+1]['c'][0], data[x+1][y+1]['c'][1], data[x+1][y+1]['c'][2], alpha] c4 = [data[x][y+1]['c'][0], data[x][y+1]['c'][1], data[x][y+1]['c'][2], alpha] if option == 3: c1 = self.color_vertex(v1) c2 = self.color_vertex(v2) c3 = self.color_vertex(v3) c4 = self.color_vertex(v4) vertex.addData3f(v1) normal.addData3f(*n) color.addData4f(*c1) uv.addData2f(0,0) vertex.addData3f(v2) normal.addData3f(*n) color.addData4f(*c2) uv.addData2f(1,0) vertex.addData3f(v3) normal.addData3f(*n) color.addData4f(*c3) uv.addData2f(1,1) vertex.addData3f(v1) normal.addData3f(*n) color.addData4f(*c1) uv.addData2f(0,0) vertex.addData3f(v3) normal.addData3f(*n) color.addData4f(*c3) uv.addData2f(1,1) vertex.addData3f(v4) normal.addData3f(*n) color.addData4f(*c4) uv.addData2f(0,1) # # add vertex h # vertex.addData3f(v1) # # normal.addData3f(*n) # vertex.addData3f(v2) # # normal.addData3f(*n) # vertex.addData3f(v3) # # normal.addData3f(*n) # vertex.addData3f(v1) # # normal.addData3f(*n) # vertex.addData3f(v3) # # normal.addData3f(*n) # vertex.addData3f(v4) # # normal.addData3f(*n) # # add vertex color # color.addData4f(*c1) # color.addData4f(*c2) # color.addData4f(*c3) # color.addData4f(*c1) # color.addData4f(*c3) # color.addData4f(*c4) # iterate number = number + 2 # add triangles prim = GeomTriangles(Geom.UHStatic) for n in range(number): prim.addVertices((n * 3) + 2, (n * 3) + 0, (n * 3) + 1) prim.closePrimitive() # make geom geom = Geom(vdata) geom.addPrimitive(prim) # make geom node node = GeomNode("base" + "_" + str(a) + "_" + str(b)) node.addGeom(geom) # make mesh nodePath mesh = NodePath(node) # set render order mesh.setBin("", 1) # locate mesh mesh.setPos(self.divsep * (a * int(len(self.data[a]) / self.div)), self.divsep * (b * int(len(self.data[b]) / self.div)), 0) # reparent mesh mesh.reparentTo(self.root) # return mesh return mesh
class NavMesh(object): notify = directNotify.newCategory("NavMesh") def __init__(self, filepath=None, filename=None): if filename is not None: self._initFromFilename(filepath, filename) def initFromPolyData(self, polyToVerts, vertToPolys, polyToAngles, vertexCoords, environmentHash): ''' Initialize the mesh from a set of polygons. polyToVerts: Dictionary mapping a polygon ID to a set of N vertex IDs vertToPolys: Dictionary mapping a vertex ID to a set of poly IDs (of every poly that includes it) polyToAngles: Dictionary mapping a polygon ID to a set of N angles (in vertex order) vertexCoords: Dictionary mapping a vertex ID to the coordinates of the vertex in worldspace environmentHash: Hash value derived from the same collision geometry as the other arguments. See AreaMapper.getEnvironmentHash(). ''' self.polyToVerts = polyToVerts self.vertToPolys = vertToPolys self.polyToAngles = polyToAngles self.vertexCoords = vertexCoords self.environmentHash = environmentHash self.connectionLookup = {} self.connections = [] self._discoverInitialConnectivity() self.optimizeMesh() def visualize(self, parentNodePath, highlightVerts=[], pathVerts=[], visitedVerts=[]): ''' XXX Should move this into a product-specific class. ''' gFormat = GeomVertexFormat.getV3cp() self.visVertexData = GeomVertexData("OMGVERTEXDATA2", gFormat, Geom.UHDynamic) self.visVertexWriter = GeomVertexWriter(self.visVertexData, "vertex") self.visVertexColorWriter = GeomVertexWriter(self.visVertexData, "color") vertToWriterIndex = {} currIndex = 0 for v in self.vertexCoords.keys(): vertToWriterIndex[v] = currIndex x = self.vertexCoords[v][0] y = self.vertexCoords[v][1] z = self.vertexCoords[v][2] self.visVertexWriter.addData3f(x, y, z + 0.5) if v in highlightVerts: self.visVertexColorWriter.addData4f(1.0, 0.0, 0.0, 1.0) elif v in visitedVerts: self.visVertexColorWriter.addData4f(0.0, 0.0, 1.0, 1.0) else: self.visVertexColorWriter.addData4f(1.0, 1.0, 0.0, 1.0) currIndex += 1 pathOffsetIntoIndex = currIndex for v in pathVerts: self.visVertexWriter.addData3f(v[0], v[1], v[2] + 0.5) self.visVertexColorWriter.addData4f(0.0, 1.0, 0.0, 1.0) currIndex += 1 lines = GeomLinestrips(Geom.UHStatic) for p in self.polyToVerts.keys(): for v in self.polyToVerts[p]: lines.addVertex(vertToWriterIndex[v]) lines.addVertex(vertToWriterIndex[self.polyToVerts[p][0]]) lines.closePrimitive() if len(pathVerts) > 0: for i in xrange(len(pathVerts)): lines.addVertex(pathOffsetIntoIndex + i) lines.closePrimitive() self.visGeom = Geom(self.visVertexData) self.visGeom.addPrimitive(lines) self.visGN = GeomNode("NavMeshVis") self.visGN.addGeom(self.visGeom) self.visNodePath = parentNodePath.attachNewNode(self.visGN) self.visNodePath.setTwoSided(True) def _discoverInitialConnectivity(self): print "Building initial connectivity graph..." for pId in self.polyToVerts.keys(): verts = self.polyToVerts[pId] numVerts = len(verts) candidates = [] neighborPolys = [] for v in verts: candidates += [ p for p in self.vertToPolys[v] if (p not in candidates) and (p != pId) ] for vNum in xrange(numVerts): neighbor = [p for p in candidates if ((verts[vNum] in self.polyToVerts[p]) and \ (verts[(vNum+1)%numVerts] in self.polyToVerts[p]))] if len(neighbor) == 0: neighborPolys.append(None) elif len(neighbor) == 1: neighborPolys.append(neighbor[0]) else: raise "Two neighbors found for the same edge?!?!" self.connectionLookup[pId] = neighborPolys # --------- Begin stitching code --------- def _attemptToMergePolys(self, polyA, polyB): newVerts = [] newAngles = [] newConnections = [] vertsA = self.polyToVerts[polyA] vertsB = self.polyToVerts[polyB] lenA = len(vertsA) lenB = len(vertsB) anglesA = self.polyToAngles[polyA] anglesB = self.polyToAngles[polyB] sharedVerts = [v for v in vertsA if (v in vertsB)] locA = 0 while vertsA[locA] not in sharedVerts: locA += 1 while vertsA[locA] in sharedVerts: locA = (locA - 1) % lenA locA = (locA + 1) % lenA CCWmost = vertsA[locA] CCWmostLocA = locA while vertsA[locA] in sharedVerts: locA = (locA + 1) % lenA locA = (locA - 1) % lenA CWmost = vertsA[locA] CWmostLocA = locA # Convexity Check. # Verify that removing the edge preserves convexity and bail out if not. locA = 0 locB = 0 while vertsA[locA] != CCWmost: locA += 1 while vertsB[locB] != CCWmost: locB += 1 CCWmostAngleSum = anglesA[locA] + anglesB[locB] CCWmostLocB = locB if CCWmostAngleSum > 180: return False locA = 0 locB = 0 while vertsA[locA] != CWmost: locA += 1 while vertsB[locB] != CWmost: locB += 1 CWmostAngleSum = anglesA[locA] + anglesB[locB] if CWmostAngleSum > 180: return False # We've found the CW-most vert of the shared edge. # Now walk A clockwise until we hit the CCW-most vert of the shared edge. newVerts.append(CWmost) newAngles.append(CWmostAngleSum) newConnections.append(self.connectionLookup[polyA][locA]) locA = (locA + 1) % lenA while vertsA[locA] != CCWmost: newVerts.append(vertsA[locA]) newAngles.append(anglesA[locA]) newConnections.append(self.connectionLookup[polyA][locA]) locA = (locA + 1) % lenA # Now we've hit the CCW-most vert of the shared edge. # Walk B clockwise until we get back to the CW-most vert of the shared edge. locB = CCWmostLocB newVerts.append(CCWmost) newAngles.append(CCWmostAngleSum) neighbor = self.connectionLookup[polyB][locB] newConnections.append(neighbor) if neighbor is not None: for i in xrange(len(self.connectionLookup[neighbor])): if self.connectionLookup[neighbor][i] == polyB: self.connectionLookup[neighbor][i] = polyA locB = (locB + 1) % lenB while vertsB[locB] != CWmost: newVerts.append(vertsB[locB]) newAngles.append(anglesB[locB]) neighbor = self.connectionLookup[polyB][locB] newConnections.append(neighbor) if neighbor is not None: for i in xrange(len(self.connectionLookup[neighbor])): if self.connectionLookup[neighbor][i] == polyB: self.connectionLookup[neighbor][i] = polyA locB = (locB + 1) % lenB # We've added every vertex, its proper angle, and connectivity info # to the new polygon. Now replace A with the new guy and remove B. self.polyToVerts[polyA] = newVerts self.polyToAngles[polyA] = newAngles self.connectionLookup[polyA] = newConnections # Make sure we have vertex->poly pointers for all the new verts we added to A. for v in newVerts: if polyA not in self.vertToPolys[v]: self.vertToPolys[v].append(polyA) # Clean up all of B's old vertices. for v in vertsB: self.vertToPolys[v].remove(polyB) if len(self.vertToPolys[v]) == 0: # No one's using this vertex anymore, remove it del self.vertToPolys[v] del self.vertexCoords[v] del self.polyToVerts[polyB] del self.polyToAngles[polyB] del self.connectionLookup[polyB] return True def _attemptToGrowPoly(self, pId): for neighbor in self.connectionLookup.get(pId, []): if (neighbor is not None) and self._attemptToMergePolys( pId, neighbor): return True return False def _growEachPolyOnce(self): grewAtLeastOne = False for pId in self.connectionLookup.keys(): if self._attemptToGrowPoly(pId): grewAtLeastOne = True return grewAtLeastOne def optimizeMesh(self): ''' Takes a mesh that is already functionally complete and optimizes it for better performance. Reduces poly count and cuts out redundant vertices. Also compacts the polygon IDs into a contiguous range from 0 to N. No need to do the same for vertex IDs yet. ''' '''print "Stitching polygons: %s -> " % (len(self.polyToVerts)), orig = len(self.polyToVerts) numPasses = 1 while self._growEachPolyOnce(): print "%s -> " % (len(self.polyToVerts)), numPasses += 1 print "Done!\nPoly count reduced to %0.1f%% of original." % (len(self.polyToVerts)/float(orig)*100.0)''' self._pruneExtraVerts() self._compactPolyIds() self.numNodes = len(self.connections) biggest = 0 biggestPoly = -1 for p in self.polyToVerts: if len(self.polyToVerts[p]) > biggest: biggest = len(self.polyToVerts[p]) biggestPoly = p print "Most verts in a single poly: ", biggest assert biggest < 256 def _cleanPoly(self, polyId): verts = self.polyToVerts[polyId] angles = self.polyToAngles[polyId] neighbors = self.connectionLookup[polyId] numVerts = len(verts) newVerts = [] newAngles = [] newNeighbors = [] for i in xrange(numVerts): if (angles[i] != 180) or \ (len(self.vertToPolys.get(verts[i],[])) > 2) or \ (neighbors[i] != neighbors[(i-1)%numVerts]): # Keep vertex newVerts.append(verts[i]) newAngles.append(angles[i]) newNeighbors.append(neighbors[i]) else: # Remove vertex, this will happen twice so pop it self.vertToPolys.pop(verts[i], None) self.vertexCoords.pop(verts[i], None) if len(verts) != len(newVerts): self.polyToVerts[polyId] = newVerts self.polyToAngles[polyId] = newAngles self.connectionLookup[polyId] = newNeighbors assert len(newVerts) < 256 def _pruneExtraVerts(self): print "Pruning extra vertices..." print "Starting verts: %s" % len(self.vertToPolys) for polyId in self.connectionLookup.keys(): self._cleanPoly(polyId) print "Ending verts: %s" % len(self.vertToPolys) def _compactPolyIds(self): polyList = self.polyToVerts.keys() polyList.sort() oldToNewId = {None: None} newPolyToVerts = {} newPolyToAngles = {} self.connections = [] currId = 0 for oldId in polyList: oldToNewId[oldId] = currId self.connections.append([]) currId += 1 for oldId in polyList: newPolyToVerts[oldToNewId[oldId]] = self.polyToVerts[oldId] newPolyToAngles[oldToNewId[oldId]] = self.polyToAngles[oldId] #self.connections[oldToNewId[oldId]] = [] for edgeNum in xrange(len(self.connectionLookup[oldId])): self.connections[oldToNewId[oldId]].append( oldToNewId[self.connectionLookup[oldId][edgeNum]]) self.polyToVerts = newPolyToVerts self.polyToAngles = newPolyToAngles del self.connectionLookup # --------- Begin pathfinding code --------- def _findCentroid(self, polyId): verts = self.polyToVerts[polyId] numVerts = len(verts) x = 0 y = 0 z = 0 for v in verts: x += self.vertexCoords[v][0] y += self.vertexCoords[v][1] z += self.vertexCoords[v][2] x /= numVerts y /= numVerts z /= numVerts return (x, y, z) ## def _estimateDistanceBetweenPolys(self, polyA, polyB): ## centroidA = self._findCentroid(polyA) ## centroidB = self._findCentroid(polyB) ## dx = centroidA[0] - centroidB[0] ## dy = centroidA[1] - centroidB[1] ## dz = centroidA[2] - centroidB[2] ## return math.sqrt(dx*dx + dy*dy + dz*dz) def _walkToNeighbor(self, currPoly, neighborPoly): currVerts = self.polyToVerts[currPoly] neighborVerts = self.polyToVerts[neighborPoly] lenCurr = len(currVerts) sharedVerts = [v for v in currVerts if (v in neighborVerts)] loc = 0 while currVerts[loc] not in sharedVerts: loc += 1 while currVerts[loc] in sharedVerts: loc = (loc - 1) % lenCurr loc = (loc + 1) % lenCurr CCWmost = currVerts[loc] CCWmostLoc = loc while currVerts[loc] in sharedVerts: loc = (loc + 1) % lenCurr loc = (loc - 1) % lenCurr CWmost = currVerts[loc] CCWmostCoords = self.vertexCoords[CCWmost] CWmostCoords = self.vertexCoords[CWmost] # For now, walk to the midpoint of the connecting edge departingEdge = CCWmostLoc # Don't need this with goal->start search neighborsEdge = 0 while self.connections[neighborPoly][neighborsEdge] != currPoly: neighborsEdge += 1 return (neighborsEdge, ((CWmostCoords[0] + CCWmostCoords[0]) / 2.0, (CWmostCoords[1] + CCWmostCoords[1]) / 2.0, (CWmostCoords[2] + CCWmostCoords[2]) / 2.0)) ## def _remakePath(self,walkBack,currNode): ## if currNode in walkBack: ## p = self._remakePath(walkBack,walkBack[currNode]) ## return p + [currNode,] ## return [currNode,] ## def findRoute(self, startNode, goalNode): ## ''' ## So much love for A*. ## ''' ## nodeToF = {} ## nodeToG = {} ## nodeToH = {} ## walkBack = {} ## #nodeToEntryPoint = {} ## self.nodeToEntryPoint[startNode] = self._findCentroid(startNode) ## nodeToG[startNode] = 0 ## nodeToH[startNode] = self._estimateDistanceBetweenPolys(startNode,goalNode) ## nodeToF[startNode] = nodeToG[startNode] + nodeToH[startNode] ## closedSet = {} ## openSet = {} ## openQueue = PriQueue() # Priority = F score ## openSet[startNode] = 1 ## openQueue.push((nodeToF[startNode],startNode)) ## goalPoint = self._findCentroid(goalNode) ## while len(openSet) > 0: ## f,currNode = openQueue.pop(0) ## del openSet[currNode] ## self.aStarWasHere[currNode] = 1 ## if currNode == goalNode: ## return self._remakePath(walkBack,currNode) ## closedSet[currNode] = 1 ## currPoint = self.nodeToEntryPoint[currNode] ## for neighbor in self.connections[currNode]: ## if (neighbor is not None) and (neighbor not in closedSet): ## departingEdge,newEntryPoint = self._walkToNeighbor(currNode,currPoint,neighbor) ## newG = nodeToG[currNode] + math.sqrt((newEntryPoint[0] - currPoint[0])**2 + \ ## (newEntryPoint[1] - currPoint[1])**2 + \ ## (newEntryPoint[2] - currPoint[2])**2) ## gotHereFasterThanBefore = False ## if neighbor not in openSet: ## openSet[neighbor] = 1 ## gotHereFasterThanBefore = True ## elif newG < nodeToG[neighbor]: ## openQueue.remove((nodeToF[neighbor],neighbor)) ## gotHereFasterThanBefore = True ## if gotHereFasterThanBefore: ## walkBack[neighbor] = currNode ## self.nodeToEntryPoint[neighbor] = newEntryPoint ## nodeToH[neighbor] = math.sqrt((goalPoint[0] - newEntryPoint[0])**2 + \ ## (goalPoint[1] - newEntryPoint[1])**2 + \ ## (goalPoint[2] - newEntryPoint[2])**2) ## nodeToG[neighbor] = newG ## nodeToF[neighbor] = nodeToG[neighbor] + nodeToH[neighbor] ## openQueue.push((nodeToF[neighbor],neighbor)) ## raise "No path found! D:" def _findAllRoutesToGoal(self, goalNode): ''' Find the shortest path from ALL start nodes to the given goal node. (Djikstra) After running, self.pathData[startNode][goalNode] == outgoing edge from startNode to the next node for the given value of goalNode and ALL values of startNode. ''' nodeToG = {} walkBack = {} nodeDeparturePoint = {} nodeDeparturePoint[goalNode] = self._findCentroid(goalNode) nodeToG[goalNode] = 0 closedSet = {} openSet = {} openQueue = PriQueue() openSet[goalNode] = 1 openQueue.push((nodeToG[goalNode], goalNode)) walkBack[goalNode] = (0, goalNode) while len(openSet) > 0: f, currNode = openQueue.pop(0) del openSet[currNode] closedSet[currNode] = 1 currPoint = nodeDeparturePoint[currNode] for neighbor in self.connections[currNode]: if (neighbor is not None) and (neighbor not in closedSet): neighborsEdge, newPoint = self._walkToNeighbor( currNode, neighbor) newG = nodeToG[currNode] + math.sqrt((newPoint[0] - currPoint[0])**2 + \ (newPoint[1] - currPoint[1])**2 + \ (newPoint[2] - currPoint[2])**2) gotHereFasterThanBefore = False if neighbor not in openSet: openSet[neighbor] = 1 gotHereFasterThanBefore = True elif newG < nodeToG[neighbor]: openQueue.remove((nodeToG[neighbor], neighbor)) gotHereFasterThanBefore = True if gotHereFasterThanBefore: walkBack[neighbor] = (neighborsEdge, currNode) nodeDeparturePoint[neighbor] = newPoint nodeToG[neighbor] = newG openQueue.push((nodeToG[neighbor], neighbor)) for startNode in xrange(len(self.connections)): departingEdge = walkBack[startNode][0] assert self.pathData[startNode][goalNode] is None self.pathData[startNode][goalNode] = departingEdge def generatePathData(self, rowRange=None): ''' Entry point for path preprocessing. Solves all pairs shortest path for this mesh. Stores the result in self.pathData. SLOW. Expect 8-10 minutes on Port Royal alone. Currently runs Djikstra on every possible start node. There are faster approaches for APSP, but... ''' if rowRange is None: rowRange = (0, self.numNodes) self.initPathData() for goalNode in xrange(rowRange[0], rowRange[1]): self._findAllRoutesToGoal(goalNode) def createPathTable(self): ''' Takes a 2D array self.pathData and changes it in place. Each row is changed into a run-length encoded string. Then, feeds the data into a new PathTable instance. ''' for row in self.pathData: for val in row: if val == None: raise "Incomplete path data!" shortestPathLookup = self.pathData self.pathData = [] # Run-Length Encode the whole thing! for start in xrange(self.numNodes): row = [] lastVal = None nodesInRow = 0 for goal in xrange(self.numNodes): val = shortestPathLookup[start][goal] if val != lastVal: row.append([goal, val]) lastVal = val nodesInRow += 1 else: nodesInRow += 1 assert nodesInRow == self.numNodes stringsRow = [] # Convert row to a bytestring to save space for item in row: assert item[0] < 65536 assert item[1] < 256 stringsRow.append( chr(item[0] / 256) + chr(item[0] % 256) + chr(item[1])) assert len(stringsRow[-1]) == 3 rowString = string.join(stringsRow, "") self.pathData.append(rowString) self.pathTable = PathTable(self.pathData, self.connections) def printPathData(self): ''' Outputs the pickled path table to stdout. ''' import sys sys.stdout.write(pickle.dumps(self.pathData, protocol=0)) def initPathData(self): self.pathData = [] for i in xrange(self.numNodes): self.pathData.append([ None, ] * self.numNodes) def addPaths(self, partialData): for i in xrange(len(partialData)): for j in xrange(len(partialData[i])): if partialData[i][j] is not None: assert self.pathData[i][j] is None self.pathData[i][j] = partialData[i][j] ## def pathTableLookup(self, startNode, goalNode): ## ''' ## Look up the equivalent of pathData[goalNode][startNode] in our run-length encoded data. ## ''' ## if startNode >= self.numNodes or goalNode >= self.numNodes: ## raise "Invalid node ID. Must be less than self.numNodes (%s)." % self.numNodes ## str = self.pathData[startNode] ## pos = 0 ## while (pos < len(str)) and (256*ord(str[pos]) + ord(str[pos+1]) <= goalNode): ## #print pos, ": ",256*ord(str[pos]) + ord(str[pos+1]) ## pos += 3 ## pos -= 3 ## return ord(str[pos+2]) def findRoute(self, startNode, goalNode): ''' Returns the node-by-node route from startNode to goalNode. ''' return self.pathTable.findRoute(startNode, goalNode) def makeNodeLocator(self, environment): meshNode = CollisionNode("NavMeshNodeLocator") meshNode.setFromCollideMask(BitMask32.allOff()) meshNode.setIntoCollideMask(OTPGlobals.PathFindingBitmask) self.polyHashToPID = {} for pId in self.polyToAngles: vertCount = 0 corners = [] for angle in self.polyToAngles[pId]: if angle != 180: # It's a corner corners.append(vertCount) vertCount += 1 # XXX this code only works for square nodes at present # Unfortunately we can only make triangle or square CollisionPolygons on the fly assert len(corners) == 4 #import pdb #pdb.set_trace() verts = [] for vert in corners: verts.append( (self.vertexCoords[self.polyToVerts[pId][vert]][0], self.vertexCoords[self.polyToVerts[pId][vert]][1], 0)) #import pdb #pdb.set_trace() poly = CollisionPolygon(verts[0], verts[1], verts[2], verts[3]) assert poly not in self.polyHashToPID self.polyHashToPID[poly] = pId meshNode.addSolid(poly) ray = CollisionRay() ray.setDirection(0, 0, -1) ray.setOrigin(0, 0, 0) rayNode = CollisionNode("NavMeshRay") rayNode.setFromCollideMask(OTPGlobals.PathFindingBitmask) rayNode.setIntoCollideMask(BitMask32.allOff()) rayNode.addSolid(ray) self.meshNodePath = environment.attachNewNode(meshNode) self.rayNodePath = environment.attachNewNode(rayNode) self.meshNodePath.setTwoSided(True) self.chq = CollisionHandlerQueue() self.traverser = CollisionTraverser() self.traverser.addCollider(self.rayNodePath, self.chq) def findNodeFromPos(self, environment, x, y): self.rayNodePath.setPos(environment, x, y, 50000) self.chq.clearEntries() self.traverser.traverse(self.meshNodePath) if self.chq.getNumEntries() != 1: self.notify.warning("No node found at position: %s, %s in %s" % (x, y, environment)) return 0 e = self.chq.getEntry(0) assert e.hasInto() if not e.hasInto(): self.notify.warning("No into found for collision %s" % (e)) pId = self.polyHashToPID[e.getInto()] return pId # --------- Begin long-term storage code --------- def writeToFile(self, filename, storePathTable=True): ''' Output the contents of this mesh to the file specified. Saving to a file lets us avoid doing expensive precomputation every time a mesh instance is required. ''' if self.environmentHash is None: raise "Attempted write to file without valid environment hash!" if storePathTable and not self.pathData: raise "Attempted to write empty pathData. Call NavMesh.generatePathTable() first!" f = open(filename, 'wb') if storePathTable: pickle.dump([ self.environmentHash, self.polyToVerts, self.polyToAngles, self.vertexCoords, self.connections, self.pathData ], f, protocol=2) f.close() self.pathData = None else: pickle.dump([ self.environmentHash, self.polyToVerts, self.polyToAngles, self.vertexCoords, self.connections, None ], f, protocol=2) f.close() print "Successfully wrote to file %s." % filename def _initFromString(self, str): contents = pickle.loads(str) self.environmentHash = contents[0] self.polyToVerts = contents[1] self.polyToAngles = contents[2] self.vertexCoords = contents[3] self.connections = contents[4] self.pathData = contents[5] if self.pathData is not None: self.pathTable = PathTable(self.pathData, self.connections) self.pathData = None self.numNodes = len(self.connections) def _initFromFilename(self, filepath, filename): vfs = VirtualFileSystem.getGlobalPtr() filename = Filename(filename) searchPath = DSearchPath() #searchPath.appendDirectory(Filename('.')) #searchPath.appendDirectory(Filename('etc')) #searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars('~'))) #searchPath.appendDirectory(Filename.fromOsSpecific(os.path.expandvars('$HOME'))) searchPath.appendDirectory( Filename.fromOsSpecific(os.path.expandvars(filepath))) found = vfs.resolveFilename(filename, searchPath) if not found: raise IOError, "File not found!" str = vfs.readFile(filename, 1) self._initFromString(str) def checkHash(self, envHash): ''' "Does this mesh represent the environment I think it does?" If this check fails, the mesh is out of date (or being used with the wrong environment). In either case, whoever generated this instance should discard it and create a new mesh from scratch. ''' return envHash == self.environmentHash
def __init__(self,inner,outer,sectors): super(RingNode,self).__init__('ring') self.inner = inner self.outer = outer self.sectors = sectors ringgeo = RawGeometry() # inner and outer radii are the true circular limits, so expand a little bit # for the sectored mesh mesh_inner = self.inner * 0.9 mesh_outer = self.outer * 1.1 angular_width = 2.0 * math.pi / self.sectors for sector in range( self.sectors ): start = sector * angular_width end = (sector+1) * angular_width # add a quad x0 = math.sin(start) * mesh_inner x1 = math.sin(start) * mesh_outer x2 = math.sin(end ) * mesh_inner x3 = math.sin(end ) * mesh_outer z0 = math.cos(start) * mesh_inner z1 = math.cos(start) * mesh_outer z2 = math.cos(end ) * mesh_inner z3 = math.cos(end ) * mesh_outer index = len(ringgeo.verts) ringgeo.verts.append( (x0, 0, z0) ) ringgeo.verts.append( (x1, 0, z1) ) ringgeo.verts.append( (x2, 0, z2) ) ringgeo.verts.append( (x3, 0, z3) ) # double-side the faces so they render from either side # top pair... ringgeo.faces.append( (index+0,index+1,index+2) ) ringgeo.faces.append( (index+1,index+3,index+2) ) # bottom pair... ringgeo.faces.append( (index+0,index+2,index+1) ) ringgeo.faces.append( (index+1,index+2,index+3) ) format=GeomVertexFormat.getV3n3() vdata=GeomVertexData('ring', format, Geom.UHDynamic) vertex=GeomVertexWriter(vdata, 'vertex') normal=GeomVertexWriter(vdata, 'normal') for (x,y,z) in ringgeo.verts: vertex.addData3f( x, y, z ) normal.addData3f( 0, 1, 0 ) trilist=GeomTriangles(Geom.UHDynamic) for (a,b,c) in ringgeo.faces: trilist.addVertex(a) trilist.addVertex(b) trilist.addVertex(c) trilist.closePrimitive() ring = Geom(vdata) ring.addPrimitive( trilist ) self.addGeom( ring )