def _computeVertices(self, positions, colors, offset=False, chunkPosition=(0, 0)): colors = numpy.asarray(colors, dtype=numpy.uint8) if len(colors.shape) > 1: colors = colors[:, None, None, :] else: colors = colors[None, None, None, :] cx, cz = chunkPosition x = cx << 4 z = cz << 4 bounds = self.chunkUpdate.updateTask.worldScene.bounds if bounds: positions = [p for p in positions if p in bounds] vertexBuffer = QuadVertexArrayBuffer(len(positions) * 6, lights=False, textures=False) vertexBuffer.buffer.shape = (len(positions), 6) + vertexBuffer.buffer.shape[-2:] if len(positions): positions = numpy.array(positions, dtype=float) positions[:, (0, 2)] -= (x, z) if offset: positions -= (0.5, 0.0, 0.5) vertexBuffer.rgba[:] = colors vertexBuffer.vertex[:] = positions[:, numpy.newaxis, numpy.newaxis, :] vertexBuffer.vertex[:] += standardCubeTemplates[_XYZ] vertexBuffer.buffer.shape = (len(positions) * 6, ) + vertexBuffer.buffer.shape[-2:] return vertexBuffer
def makeChunkVertices(self, chunk, _limitBox): neighbors = self.chunkUpdate.neighboringChunks def getpop(face): ch = neighbors.get(face) if ch: return getattr(ch, "TerrainPopulated", True) else: return True pop = getattr(chunk, "TerrainPopulated", True) yield if pop: return visibleFaces = [ getpop(faces.FaceXIncreasing), getpop(faces.FaceXDecreasing), True, True, getpop(faces.FaceZIncreasing), getpop(faces.FaceZDecreasing), ] visibleFaces = numpy.array(visibleFaces, dtype='bool') verts = self.vertexTemplate[visibleFaces] buffer = QuadVertexArrayBuffer(0, textures=False, lights=False) buffer.buffer = verts self.sceneNode = VertexNode(buffer) yield
def _computeVertices(self, positions, colors, offset=False, chunkPosition=(0, 0)): cx, cz = chunkPosition x = cx << 4 z = cz << 4 bounds = self.chunkUpdate.updateTask.worldScene.bounds if bounds: positions = [p for p in positions if p in bounds] vertexBuffer = QuadVertexArrayBuffer(len(positions) * 6, lights=False, textures=False) vertexBuffer.buffer.shape = (len(positions), 6) + vertexBuffer.buffer.shape[-2:] if len(positions): positions = numpy.array(positions, dtype=float) positions[:, (0, 2)] -= (x, z) if offset: positions -= 0.5 vertexBuffer.rgba[:] = colors vertexBuffer.vertex[:] = positions[:, numpy.newaxis, numpy.newaxis, :] vertexBuffer.vertex[:] += standardCubeTemplates[_XYZ] vertexBuffer.buffer.shape = (len(positions) * 6, ) + vertexBuffer.buffer.shape[-2:] return vertexBuffer
def __init__(self, small=False): super(CompassNode, self).__init__() self.small = small v = QuadVertexArrayBuffer(1, textures=True) v.vertex[..., :2] = makeQuad(-.1, -.1, 0.2, 0.2) v.texcoord[:] = makeQuad(0, 0, 1, 1) v.rgba[:] = 0xff self.vertexNode = VertexNode([v]) self.pitchState = Rotate(0, (1., 0., 0.)) self.yawState = Rotate(0, (0., 0., 1.)) self.addState(Identity()) self.addState(Translate((0.9, 0.1, 0.0))) self.addState(self.pitchState) self.addState(self.yawState) self.addState(Disable(GL.GL_DEPTH_TEST)) self.addState(Enable(GL.GL_BLEND, GL.GL_TEXTURE_2D)) if small: filename = "compass_small.png" else: filename = "compass.png" self._tex = loadPNGTexture(filename, minFilter=GL.GL_LINEAR, magFilter=GL.GL_LINEAR) self.textureState = BindTexture(self._tex) self.addState(self.textureState) self.addChild(self.vertexNode)
def entityModelNode(ref, model, modelTex, chunk): modelVerts = numpy.array(model.vertices) modelVerts.shape = modelVerts.shape[0] // 4, 4, modelVerts.shape[1] # scale down modelVerts[..., :3] *= 1 / 16. modelVerts[..., 1] = -modelVerts[..., 1] + 1.5 + 1 / 64. modelVerts[..., 0] = -modelVerts[..., 0] vertexBuffer = QuadVertexArrayBuffer(len(modelVerts), lights=False, textures=True) vertexBuffer.vertex[:] = modelVerts[..., :3] vertexBuffer.texcoord[:] = modelVerts[..., 3:5] node = VertexNode([vertexBuffer]) rotate = Rotate(ref.Rotation[0], (0., 1., 0.)) node.addState(rotate) translate = Translate((ref.Position - (chunk.cx << 4, 0, chunk.cz << 4))) node.addState(translate) bindTexture = BindTexture(modelTex, (1. / model.texWidth, 1. / model.texHeight, 1)) node.addState(bindTexture) return node
def makeChunkVertices(self, chunk, _limitBox): neighbors = self.chunkUpdate.neighboringChunks def getpop(face): ch = neighbors.get(face) if ch: return getattr(ch, "TerrainPopulated", True) else: return True pop = getattr(chunk, "TerrainPopulated", True) yield if pop: return visibleFaces = [ getpop(faces.FaceXIncreasing), getpop(faces.FaceXDecreasing), True, True, getpop(faces.FaceZIncreasing), getpop(faces.FaceZDecreasing), ] visibleFaces = numpy.array(visibleFaces, dtype='bool') verts = self.vertexTemplate[visibleFaces] buffer = QuadVertexArrayBuffer(0, textures=False, lights=False) buffer.buffer = verts self.sceneNode = scenegraph.VertexNode(buffer) yield
def entityModelNode(ref, model, modelTex=None, chunk=None, flip=False): modelVerts = numpy.array(model.vertices) modelVerts.shape = modelVerts.shape[0]//4, 4, modelVerts.shape[1] # scale down modelVerts[..., :3] *= 1/16. modelVerts[..., 1] = -modelVerts[..., 1] + 1.5 + 1/64. modelVerts[..., 0] = -modelVerts[..., 0] vertexBuffer = QuadVertexArrayBuffer(len(modelVerts), lights=False, textures=modelTex is not None) vertexBuffer.vertex[:] = modelVerts[..., :3] if modelTex is not None: vertexBuffer.texcoord[:] = modelVerts[..., 3:5] node = VertexNode([vertexBuffer]) pos = ref.Position if chunk is not None: pos = pos - (chunk.cx << 4, 0, chunk.cz << 4) translate = Translate(pos) node.addState(translate) rotate = Rotate(ref.Rotation[0], (0., 1., 0.)) node.addState(rotate) if modelTex is not None: bindTexture = BindTexture(modelTex, (1./model.texWidth, 1./model.texHeight * (-1 if flip else 1), 1)) node.addState(bindTexture) return node
def entityModelNode(ref, model, modelTex=None, chunk=None, flip=False): modelVerts = numpy.array(model.vertices) modelVerts.shape = modelVerts.shape[0] // 4, 4, modelVerts.shape[1] # scale down modelVerts[..., :3] *= 1 / 16. modelVerts[..., 1] = -modelVerts[..., 1] + 1.5 + 1 / 64. modelVerts[..., 0] = -modelVerts[..., 0] vertexBuffer = QuadVertexArrayBuffer(len(modelVerts), lights=False, textures=modelTex is not None) vertexBuffer.vertex[:] = modelVerts[..., :3] if modelTex is not None: vertexBuffer.texcoord[:] = modelVerts[..., 3:5] node = VertexNode([vertexBuffer]) pos = ref.Position if chunk is not None: pos = pos - (chunk.cx << 4, 0, chunk.cz << 4) translate = Translate(pos) node.addState(translate) rotate = Rotate(ref.Rotation[0], (0., 1., 0.)) node.addState(rotate) if modelTex is not None: bindTexture = BindTexture(modelTex, (1. / model.texWidth, 1. / model.texHeight * (-1 if flip else 1), 1)) node.addState(bindTexture) return node
def makeChunkVertices(self, chunk, limitBox): mapTiles = [] for i, ref in enumerate(chunk.Entities): if ref.id != "ItemFrame": continue if i % 10 == 0: yield if limitBox and ref.Position not in limitBox: continue try: item = ref.Item if item.itemType.internalName != "minecraft:filled_map": continue except KeyError: log.exception( "Error while getting ItemFrame item ID in frame at %s", ref.TilePos) continue mapID = item.Damage mapTex = self.chunkUpdate.updateTask.getMapTexture(mapID) # xxx if mapTex is None: mapTex = missingNoTex # xxxx assumes 1.8 TilePos - fix this in ref?? mapTiles.append((mapTex, ref.TilePos, ref.Facing)) if not len(mapTiles): return nodes = [] for mapTex, (x, y, z), facing in mapTiles: vertexBuffer = QuadVertexArrayBuffer(1, lights=False, textures=True) # chunk is already translated - why? x -= chunk.cx << 4 z -= chunk.cz << 4 vertexBuffer.vertex[:] = x, y, z corners = self.faceCorners[facing] vertexBuffer.vertex[:] += corners texCorners = [(1, 1), (1, 0), (0, 0), (0, 1)] vertexBuffer.texcoord[:] += texCorners vertexNode = VertexNode([vertexBuffer]) if mapTex is not None: bindTexture = BindTexture(mapTex) vertexNode.addState(bindTexture) nodes.append(vertexNode) self.sceneNode = scenenode.Node("itemFrames") for node in nodes: self.sceneNode.addChild(node)
def makeChunkVertices(self, chunk, limitBox): mapTiles = [] for i, ref in enumerate(chunk.Entities): if ref.id != "ItemFrame": continue if i % 10 == 0: yield if limitBox and ref.Position not in limitBox: continue try: item = ref.Item if item.itemType.internalName != "minecraft:filled_map": continue except KeyError: log.exception("Error while getting ItemFrame item ID in frame at %s", ref.TilePos) continue mapID = item.Damage mapTex = self.chunkUpdate.updateTask.getMapTexture(mapID) # xxx if mapTex is None: mapTex = missingNoTex # xxxx assumes 1.8 TilePos - fix this in ref?? mapTiles.append((mapTex, ref.TilePos, ref.Facing)) if not len(mapTiles): return nodes = [] for mapTex, (x, y, z), facing in mapTiles: vertexBuffer = QuadVertexArrayBuffer(1, lights=False, textures=True) # chunk is already translated - why? x -= chunk.cx << 4 z -= chunk.cz << 4 vertexBuffer.vertex[:] = x, y, z corners = self.faceCorners[facing] vertexBuffer.vertex[:] += corners texCorners = [(1, 1), (1, 0), (0, 0), (0, 1)] vertexBuffer.texcoord[:] += texCorners vertexNode = VertexNode([vertexBuffer]) if mapTex is not None: bindTexture = BindTexture(mapTex) vertexNode.addState(bindTexture) nodes.append(vertexNode) self.sceneNode = scenenode.Node("itemFrames") for node in nodes: self.sceneNode.addChild(node)
def getVertexes(mask, color): y, z, x = mask.nonzero() vertexBuffer = QuadVertexArrayBuffer(len(x), textures=False, lights=False) vertexBuffer.vertex[..., 0] = x[:, None] vertexBuffer.vertex[..., 1] = y[:, None] vertexBuffer.vertex[..., 2] = z[:, None] vertexBuffer.vertex[:] += (0, (cy << 4), 0) vertexBuffer.vertex[:] += standardCubeTemplates[faces.FaceYDecreasing, ..., :3] vertexBuffer.rgba[:] = color return vertexBuffer
def makeChunkVertices(self, chunk, limitBox): """ :param chunk: :type chunk: WorldEditorChunk :param limitBox: :return: :raise: """ if not hasattr(chunk, 'HeightMap') or chunk.HeightMap is None: return heightMap = chunk.HeightMap chunkWidth = chunkLength = 16 chunkHeight = chunk.dimension.bounds.height z, x = list(numpy.indices((chunkLength, chunkWidth))) y = (heightMap - 1)[:chunkLength, :chunkWidth] numpy.clip(y, 0, chunkHeight - 1, y) nonZeroHeights = y > 0 x = x[nonZeroHeights] if not len(x): return z = z[nonZeroHeights] y = y[nonZeroHeights] yield vertexBuffer = QuadVertexArrayBuffer(len(x), textures=False, lights=False) vertexBuffer.vertex[..., 0] = x[:, numpy.newaxis] vertexBuffer.vertex[..., 1] = y[:, numpy.newaxis] vertexBuffer.vertex[..., 2] = z[:, numpy.newaxis] vertexBuffer.vertex[:] += standardCubeTemplates[faces.FaceYIncreasing, ..., :3] vertexBuffer.rgba[:] = (0xff, 0x00, 0xff, 0x9f) self.sceneNode = VertexNode(vertexBuffer) yield
def chestEntityModelNode(ref, model, modelTex, chunk, facing, largeX, largeZ): modelVerts = numpy.array(model.vertices) modelVerts.shape = modelVerts.shape[0]//4, 4, modelVerts.shape[1] # scale down modelVerts[..., :3] *= 1/16. # modelVerts[..., 1] = -modelVerts[..., 1] # modelVerts[..., 0] = -modelVerts[..., 0] vertexBuffer = QuadVertexArrayBuffer(len(modelVerts), lights=False, textures=True) vertexBuffer.vertex[:] = modelVerts[..., :3] vertexBuffer.texcoord[:] = modelVerts[..., 3:5] node = VertexNode([vertexBuffer]) rotations = { "north": 180, "east": 270, "south": 0, "west": 90 } decenterState = Translate((-0.5, -0.5, -0.5)) node.addState(decenterState) rotate = Rotate(rotations[facing], (0., 1., 0.)) node.addState(rotate) dx = dz = 0 if largeX and facing == "north": dx = 1. if largeZ and facing == "east": dz = -1. recenterState = Translate((0.5 + dx, 0.5, 0.5 + dz)) node.addState(recenterState) x, y, z = (ref.Position - (chunk.cx << 4, 0, chunk.cz << 4)) scale = Scale((1., -1., -1.)) node.addState(scale) posTranslate = Translate((x, y + 1., z + 1.)) node.addState(posTranslate) bindTexture = BindTexture(modelTex, (1./model.texWidth, 1./model.texHeight, 1)) node.addState(bindTexture) return node
def chestEntityModelNode(ref, model, modelTex, chunk, facing, largeX, largeZ): modelVerts = numpy.array(model.vertices) modelVerts.shape = modelVerts.shape[0] // 4, 4, modelVerts.shape[1] # scale down modelVerts[..., :3] *= 1 / 16. # modelVerts[..., 1] = -modelVerts[..., 1] # modelVerts[..., 0] = -modelVerts[..., 0] vertexBuffer = QuadVertexArrayBuffer(len(modelVerts), lights=False, textures=True) vertexBuffer.vertex[:] = modelVerts[..., :3] vertexBuffer.texcoord[:] = modelVerts[..., 3:5] node = VertexNode([vertexBuffer]) rotations = {"north": 180, "east": 270, "south": 0, "west": 90} decenterState = Translate((-0.5, -0.5, -0.5)) node.addState(decenterState) rotate = Rotate(rotations[facing], (0., 1., 0.)) node.addState(rotate) dx = dz = 0 if largeX and facing == "north": dx = 1. if largeZ and facing == "east": dz = -1. recenterState = Translate((0.5 + dx, 0.5, 0.5 + dz)) node.addState(recenterState) x, y, z = (ref.Position - (chunk.cx << 4, 0, chunk.cz << 4)) scale = Scale((1., -1., -1.)) node.addState(scale) posTranslate = Translate((x, y + 1., z + 1.)) node.addState(posTranslate) bindTexture = BindTexture(modelTex, (1. / model.texWidth, 1. / model.texHeight, 1)) node.addState(bindTexture) return node
def entityModelNode(ref, model, modelTex, chunk): modelVerts = numpy.array(model.vertices) modelVerts.shape = modelVerts.shape[0]//4, 4, modelVerts.shape[1] # scale down modelVerts[..., :3] *= 1/16. modelVerts[..., 1] = -modelVerts[..., 1] + 1.5 + 1/64. modelVerts[..., 0] = -modelVerts[..., 0] vertexBuffer = QuadVertexArrayBuffer(len(modelVerts), lights=False, textures=True) vertexBuffer.vertex[:] = modelVerts[..., :3] vertexBuffer.texcoord[:] = modelVerts[..., 3:5] node = VertexNode([vertexBuffer]) rotateNode = RotateNode(ref.Rotation[0], (0., 1., 0.)) rotateNode.addChild(node) translateNode = TranslateNode((ref.Position - (chunk.cx << 4, 0, chunk.cz << 4))) translateNode.addChild(rotateNode) textureNode = BindTextureNode(modelTex, (1./model.texWidth, 1./model.texHeight, 1)) textureNode.addChild(translateNode) return textureNode
def buildSection(self, sectionMask, cy): vertexArrays = [] for (face, exposedFaceMask) in enumerate(self.exposedBlockMasks(sectionMask)): blockMask = sectionMask[1:-1, 1:-1, 1:-1] & exposedFaceMask vertexBuffer = QuadVertexArrayBuffer.fromBlockMask(face, blockMask, False, False) if not len(vertexBuffer.vertex): continue vertexBuffer.rgb[:] = faceShades[face] vertexBuffer.alpha[:] = 0x77 vertexBuffer.vertex[..., 1] += cy << 4 vertexArrays.append(vertexBuffer) return vertexArrays
def makeChunkVertices(self, chunk, limitBox): """ :param chunk: :type chunk: WorldEditorChunk :param limitBox: :return: :raise: """ dim = chunk.dimension cx, cz = chunk.chunkPosition if not hasattr(chunk, 'HeightMap') or chunk.HeightMap is None: return heightMap = chunk.HeightMap chunkWidth = chunkLength = 16 chunkHeight = chunk.dimension.bounds.height z, x = list(numpy.indices((chunkLength, chunkWidth))) y = (heightMap - 1)[:chunkLength, :chunkWidth] numpy.clip(y, 0, chunkHeight - 1, y) nonZeroHeights = y > 0 heights = y.reshape((16, 16)) x = x[nonZeroHeights] if not len(x): return z = z[nonZeroHeights] y = y[nonZeroHeights] # Get the top block in each column blockResult = dim.getBlocks(x + (cx * 16), y, z + (cz * 16), return_Data=True) topBlocks = blockResult.Blocks topBlockData = blockResult.Data # Get the block above each column top. We'll recolor the top face of the column if a flower or another # transparent block is on top. aboveY = y + 1 numpy.clip(aboveY, 0, chunkHeight - 1, aboveY) blocksAbove = dim.getBlocks(x + (cx * 16), aboveY, z + (cz * 16)).Blocks flatcolors = dim.blocktypes.mapColor[topBlocks, topBlockData][:, numpy.newaxis, :] yield vertexBuffer = QuadVertexArrayBuffer(len(x), textures=False, lights=False) vertexBuffer.vertex[..., 0] = x[:, numpy.newaxis] vertexBuffer.vertex[..., 1] = y[:, numpy.newaxis] vertexBuffer.vertex[..., 2] = z[:, numpy.newaxis] va0 = vertexBuffer.copy() va0.vertex[:] += standardCubeTemplates[faces.FaceYIncreasing, ..., :3] overmask = blocksAbove > 0 colors = dim.blocktypes.mapColor[:, 0][blocksAbove[overmask]][:, numpy.newaxis] flatcolors[overmask] = colors if self.detailLevel == 2: heightfactor = (y / float(chunk.dimension.bounds.height)) * 0.33 + 0.66 flatcolors[..., :3] *= heightfactor[:, numpy.newaxis, numpy.newaxis] # xxx implicit cast from byte to float and back va0.rgb[:] = flatcolors yield if self.detailLevel == 2: self.sceneNode = VertexNode(va0) return # Calculate how deep each column needs to go to be flush with the adjacent column; # If columns extend all the way down, performance suffers due to fill rate. depths = numpy.zeros((chunkWidth, chunkLength), dtype='uint16') depths[1:-1, 1:-1] = reduce(numpy.minimum, (heights[1:-1, :-2], heights[1:-1, 2:], heights[:-2, 1:-1], heights[2:, 1:-1])) depths = depths[nonZeroHeights] yield va1 = vertexBuffer.copy() va1.vertex[..., :3] += standardCubeTemplates[faces.FaceXIncreasing, ..., :3] va1.vertex[:, 0, 1] = depths va1.vertex[:, 0, 1] = depths # stretch to floor va1.vertex[:, (2, 3), 1] -= 0.5 # drop down to prevent intersection pixels numpy.multiply(flatcolors, 0.8, out=flatcolors, casting='unsafe') #flatcolors *= 0.8 va1.rgb[:] = flatcolors grassmask = topBlocks == 2 # color grass sides with dirt's color va1.rgb[grassmask] = dim.blocktypes.mapColor[:, 0][[3]][:, numpy.newaxis] va2 = va1.copy() va1.vertex[:, (1, 2), 0] -= 1.0 # turn diagonally va2.vertex[:, (0, 3), 0] -= 1.0 # turn diagonally nodes = [VertexNode(v) for v in (va1, va2, va0)] self.sceneNode = scenenode.Node() for node in nodes: self.sceneNode.addChild(node)
def makeChunkVertices(self, chunk, limitBox): """ :param chunk: :type chunk: WorldEditorChunk :param limitBox: :return: :raise: """ dim = chunk.dimension cx, cz = chunk.chunkPosition if not hasattr(chunk, 'HeightMap') or chunk.HeightMap is None: return heightMap = chunk.HeightMap chunkWidth = chunkLength = 16 chunkHeight = chunk.dimension.bounds.height z, x = list(numpy.indices((chunkLength, chunkWidth))) y = (heightMap - 1)[:chunkLength, :chunkWidth] numpy.clip(y, 0, chunkHeight - 1, y) nonZeroHeights = y > 0 heights = y.reshape((16, 16)) x = x[nonZeroHeights] if not len(x): return z = z[nonZeroHeights] y = y[nonZeroHeights] # Get the top block in each column blockResult = dim.getBlocks(x + (cx * 16), y, z + (cz * 16), return_Data=True) topBlocks = blockResult.Blocks topBlockData = blockResult.Data # Get the block above each column top. We'll recolor the top face of the column if a flower or another # transparent block is on top. aboveY = y + 1 numpy.clip(aboveY, 0, chunkHeight - 1, aboveY) blocksAbove = dim.getBlocks(x + (cx * 16), aboveY, z + (cz * 16)).Blocks flatcolors = dim.blocktypes.mapColor[topBlocks, topBlockData][:, numpy.newaxis, :] yield vertexBuffer = QuadVertexArrayBuffer(len(x), textures=False, lights=False) vertexBuffer.vertex[..., 0] = x[:, numpy.newaxis] vertexBuffer.vertex[..., 1] = y[:, numpy.newaxis] vertexBuffer.vertex[..., 2] = z[:, numpy.newaxis] va0 = vertexBuffer.copy() va0.vertex[:] += standardCubeTemplates[faces.FaceYIncreasing, ..., :3] overmask = blocksAbove > 0 colors = dim.blocktypes.mapColor[:, 0][blocksAbove[overmask]][:, numpy.newaxis] flatcolors[overmask] = colors if self.detailLevel == 2: heightfactor = (y / float(chunk.dimension.bounds.height)) * 0.33 + 0.66 flatcolors[..., :3] *= heightfactor[:, numpy.newaxis, numpy.newaxis] # xxx implicit cast from byte to float and back va0.rgb[:] = flatcolors yield if self.detailLevel == 2: self.sceneNode = scenegraph.VertexNode(va0) return # Calculate how deep each column needs to go to be flush with the adjacent column; # If columns extend all the way down, performance suffers due to fill rate. depths = numpy.zeros((chunkWidth, chunkLength), dtype='uint16') depths[1:-1, 1:-1] = reduce(numpy.minimum, (heights[1:-1, :-2], heights[1:-1, 2:], heights[:-2, 1:-1], heights[2:, 1:-1])) depths = depths[nonZeroHeights] yield va1 = vertexBuffer.copy() va1.vertex[..., :3] += standardCubeTemplates[faces.FaceXIncreasing, ..., :3] va1.vertex[:, 0, 1] = depths va1.vertex[:, 0, 1] = depths # stretch to floor va1.vertex[:, (2, 3), 1] -= 0.5 # drop down to prevent intersection pixels flatcolors *= 0.8 va1.rgb[:] = flatcolors grassmask = topBlocks == 2 # color grass sides with dirt's color va1.rgb[grassmask] = dim.blocktypes.mapColor[:, 0][[3]][:, numpy.newaxis] va2 = va1.copy() va1.vertex[:, (1, 2), 0] -= 1.0 # turn diagonally va2.vertex[:, (0, 3), 0] -= 1.0 # turn diagonally nodes = [scenegraph.VertexNode(v) for v in (va1, va2, va0)] self.sceneNode = scenegraph.Node() for node in nodes: self.sceneNode.addChild(node)