def __init__(self, segments = 32, *args, **keywordArgs): Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? # TODO: should have separate vertex per angled face so they can have face-specific normals self.segments = segments angleStep = 2.0 * pi / self.segments vertices = [(0.0, 0.5, 0.0)] vertexNormals = [(0.0, 1.0, 0.0)] textureCoords = [(1.0, 1.0)] for increment in range(0, self.segments): angle = increment * angleStep vertex = (sin(angle) * 0.5, -0.5, cos(angle) * 0.5) vertices += [vertex] vertexNormals += [(vertex[0] / .7071, 0.0, vertex[2] / .7071)] textureCoords += [(0.1, 0.1)] vertices += vertices[1:self.segments + 1] vertices += [(0.0, -0.5, 0.0)] vertexNormals += [(0.0, -1.0, 0.0)] * (self.segments + 1) textureCoords += textureCoords[1:self.segments + 1] textureCoords += [(0.0, 0.0)] self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices)) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLE_FAN, range(0, self.segments + 1) + [1, 0]) self.geometry().addPrimitiveSet(faceSet) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLE_FAN, [self.segments * 2 + 1] + range(self.segments + 1, self.segments * 2 + 1) + [self.segments + 1, self.segments * 2 + 1]) self.geometry().addPrimitiveSet(faceSet) self.geometry().setNormalArray(Shape.vectorArrayFromList(vertexNormals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(textureCoords))
def setPoints(self, pathPoints): threeDPathPoints = [] for pathPoint in pathPoints: if len(pathPoint) == 2: threeDPathPoints += [(pathPoint[0], pathPoint[1], 0.0)] else: threeDPathPoints += [pathPoint] pathPoints = threeDPathPoints if pathPoints != self._pathPoints: while self.geometry().getNumPrimitiveSets() > 0: self.geometry().removePrimitiveSet(0) self._pathPoints = pathPoints vertices = [] pointVertices = [] textureCoords = [] pointCoords = [] prevPoint = None pathLength = 0.0 tweak = -0.0001 * random.random() for pathPoint in self._pathPoints: if prevPoint != None: pathLength += sqrt((pathPoint[0] - prevPoint[0])**2 + (pathPoint[1] - prevPoint[1])**2 + (pathPoint[2] - prevPoint[2])**2) vertices += [(pathPoint[0], pathPoint[1], pathPoint[2] + tweak) ] textureCoords += [(pathLength, pathLength)] if pathPoint != self._pathPoints[ 0] and pathPoint != self._pathPoints[-1]: tweak *= -1.0 vertices += [(pathPoint[0], pathPoint[1], pathPoint[2] + tweak)] textureCoords += [(pathLength, pathLength)] pointVertices += [ (pathPoint[0], pathPoint[1], pathPoint[2] - 0.0001) ] # always beyond tweak pointCoords += [(pathLength, pathLength)] prevPoint = pathPoint self.geometry().setVertexArray( Shape.vectorArrayFromList(vertices + pointVertices)) self.geometry().addPrimitiveSet( Shape.primitiveSetFromList(osg.PrimitiveSet.LINES, range(len(vertices)))) self.geometry().addPrimitiveSet( Shape.primitiveSetFromList( osg.PrimitiveSet.POINTS, range(len(vertices), len(vertices) + len(self._pathPoints)))) self.geometry().setNormalArray( Shape.vectorArrayFromList([(0.0, 0.0, 0.0)])) self.geometry().setNormalBinding(osg.Geometry.BIND_OVERALL) self.geometry().setTexCoordArray( 0, Shape.vectorArrayFromList(textureCoords + pointCoords)) self.geometry().dirtyDisplayList()
def __init__(self, *args, **keywordArgs): Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? steps = 32 angleStep = 2.0 * pi / steps topVertices = [] bottomVertices = [] sideNormals = [] for step in range(0, steps): angle = step * angleStep x, z = (sin(angle) * 0.5, cos(angle) * 0.5) topVertices += [(x, 0.5, z)] bottomVertices += [(x, -0.5, z)] sideNormals += [(x / 0.5, 0.0, z / 0.5)] vertices = [(0.0, 0.5, 0.0)] + topVertices vertexNormals = [(0.0, 1.0, 0.0)] * (steps + 1) textureCoords = [(1.0, 1.0)] + [(0.9, 0.9)] * steps for step in range(0, steps): vertices += [topVertices[step], bottomVertices[step]] vertexNormals += [sideNormals[step], sideNormals[step]] textureCoords += [(0.9, 0.9), (0.1, 0.1)] vertices += bottomVertices + [(0.0, -0.5, 0.0)] vertexNormals += [(0.0, -1.0, 0.0)] * (steps + 1) textureCoords += [(0.1, 0.1)] * steps + [(0.0, 0.0)] self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices)) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLE_FAN, range(0, steps + 1) + [1, 0]) self.geometry().addPrimitiveSet(faceSet) faceSet = Shape.primitiveSetFromList( osg.PrimitiveSet.QUAD_STRIP, range(steps + 1, 3 * steps + 1) + [steps + 1, steps + 2]) self.geometry().addPrimitiveSet(faceSet) faceSet = Shape.primitiveSetFromList( osg.PrimitiveSet.TRIANGLE_FAN, [4 * steps + 1] + range(3 * steps + 1, 4 * steps + 1) + [3 * steps + 1, 4 * steps + 1]) self.geometry().addPrimitiveSet(faceSet) self.geometry().setNormalArray( Shape.vectorArrayFromList(vertexNormals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) self.geometry().setTexCoordArray( 0, Shape.vectorArrayFromList(textureCoords))
def setPoints(self, pathPoints): threeDPathPoints = [] for pathPoint in pathPoints: if len(pathPoint) == 2: threeDPathPoints += [(pathPoint[0], pathPoint[1], 0.0)] else: threeDPathPoints += [pathPoint] pathPoints = threeDPathPoints if pathPoints != self._pathPoints: while self.geometry().getNumPrimitiveSets() > 0: self.geometry().removePrimitiveSet(0) self._pathPoints = pathPoints vertices = [] pointVertices = [] textureCoords = [] pointCoords = [] prevPoint = None pathLength = 0.0 tweak = -0.0001 * random.random() for pathPoint in self._pathPoints: if prevPoint != None: pathLength += sqrt((pathPoint[0] - prevPoint[0]) ** 2 + (pathPoint[1] - prevPoint[1]) ** 2 + (pathPoint[2] - prevPoint[2]) ** 2) vertices += [(pathPoint[0], pathPoint[1], pathPoint[2] + tweak)] textureCoords += [(pathLength, pathLength)] if pathPoint != self._pathPoints[0] and pathPoint != self._pathPoints[-1]: tweak *= -1.0 vertices += [(pathPoint[0], pathPoint[1], pathPoint[2] + tweak)] textureCoords += [(pathLength, pathLength)] pointVertices += [(pathPoint[0], pathPoint[1], pathPoint[2] - 0.0001)] # always beyond tweak pointCoords += [(pathLength, pathLength)] prevPoint = pathPoint self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices + pointVertices)) self.geometry().addPrimitiveSet(Shape.primitiveSetFromList(osg.PrimitiveSet.LINES, range(len(vertices)))) self.geometry().addPrimitiveSet(Shape.primitiveSetFromList(osg.PrimitiveSet.POINTS, range(len(vertices), len(vertices) + len(self._pathPoints)))) self.geometry().setNormalArray(Shape.vectorArrayFromList([(0.0, 0.0, 0.0)])) self.geometry().setNormalBinding(osg.Geometry.BIND_OVERALL) self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(textureCoords + pointCoords)) self.geometry().dirtyDisplayList()
def __init__(self, segments=32, *args, **keywordArgs): Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? # TODO: should have separate vertex per angled face so they can have face-specific normals self.segments = segments angleStep = 2.0 * pi / self.segments vertices = [(0.0, 0.5, 0.0)] vertexNormals = [(0.0, 1.0, 0.0)] textureCoords = [(1.0, 1.0)] for increment in range(0, self.segments): angle = increment * angleStep vertex = (sin(angle) * 0.5, -0.5, cos(angle) * 0.5) vertices += [vertex] vertexNormals += [(vertex[0] / .7071, 0.0, vertex[2] / .7071)] textureCoords += [(0.1, 0.1)] vertices += vertices[1:self.segments + 1] vertices += [(0.0, -0.5, 0.0)] vertexNormals += [(0.0, -1.0, 0.0)] * (self.segments + 1) textureCoords += textureCoords[1:self.segments + 1] textureCoords += [(0.0, 0.0)] self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices)) faceSet = Shape.primitiveSetFromList( osg.PrimitiveSet.TRIANGLE_FAN, range(0, self.segments + 1) + [1, 0]) self.geometry().addPrimitiveSet(faceSet) faceSet = Shape.primitiveSetFromList( osg.PrimitiveSet.TRIANGLE_FAN, [self.segments * 2 + 1] + range(self.segments + 1, self.segments * 2 + 1) + [self.segments + 1, self.segments * 2 + 1]) self.geometry().addPrimitiveSet(faceSet) self.geometry().setNormalArray( Shape.vectorArrayFromList(vertexNormals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) self.geometry().setTexCoordArray( 0, Shape.vectorArrayFromList(textureCoords))
def __init__(self, *args, **keywordArgs): Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? steps = 32 angleStep = 2.0 * pi / steps topVertices = [] bottomVertices = [] sideNormals = [] for step in range(0, steps): angle = step * angleStep x, z = (sin(angle) * 0.5, cos(angle) * 0.5) topVertices += [(x, 0.5, z)] bottomVertices += [(x, -0.5, z)] sideNormals += [(x / 0.5, 0.0, z / 0.5)] vertices = [(0.0, 0.5, 0.0)] + topVertices vertexNormals = [(0.0, 1.0, 0.0)] * (steps + 1) textureCoords = [(1.0, 1.0)] + [(0.9, 0.9)] * steps for step in range(0, steps): vertices += [topVertices[step], bottomVertices[step]] vertexNormals += [sideNormals[step], sideNormals[step]] textureCoords += [(0.9, 0.9), (0.1, 0.1)] vertices += bottomVertices + [(0.0, -0.5, 0.0)] vertexNormals += [(0.0, -1.0, 0.0)] * (steps + 1) textureCoords += [(0.1, 0.1)] * steps + [(0.0, 0.0)] self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices)) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLE_FAN, range(0, steps + 1) + [1, 0]) self.geometry().addPrimitiveSet(faceSet) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.QUAD_STRIP, range(steps + 1, 3 * steps + 1) + [steps + 1, steps + 2]) self.geometry().addPrimitiveSet(faceSet) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLE_FAN, [4 * steps + 1] + range(3 * steps + 1, 4 * steps + 1) + [3 * steps + 1, 4 * steps + 1]) self.geometry().addPrimitiveSet(faceSet) self.geometry().setNormalArray(Shape.vectorArrayFromList(vertexNormals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(textureCoords))
def __init__(self, *args, **keywordArgs): UnitShape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? baseVertices = [(-0.5, -0.5, -0.5), (-0.5, -0.5, 0.5), (-0.5, 0.5, -0.5), (-0.5, 0.5, 0.5), ( 0.5, -0.5, -0.5), ( 0.5, -0.5, 0.5), ( 0.5, 0.5, -0.5), ( 0.5, 0.5, 0.5)] vertices = [] faceNormals = [] texCoords = [] for (v0, v1, v2, v3, normal) in [(0, 1, 3, 2, (-1.0, 0.0, 0.0)), (2, 3, 7, 6, (0.0, 1.0, 0.0)), (6, 7, 5, 4, (1.0, 0.0, 0.0)), (4, 5, 1, 0, (0.0, -1.0, 0.0)), (3, 1, 5, 7, (0.0, 0.0, 1.0)), (0, 2, 6, 4, (0.0, 0.0, -1.0))]: vertices += [baseVertices[v0], baseVertices[v1], baseVertices[v2], baseVertices[v3]] faceNormals += [normal] texCoords += [(0, 1), (0, 0), (1, 0), (1, 1)] faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.QUADS, [len(vertices) - 4, len(vertices) - 3, len(vertices) - 2, len(vertices) - 1]) self.geometry().addPrimitiveSet(faceSet) self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices)) self.geometry().setNormalArray(Shape.vectorArrayFromList(faceNormals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_PRIMITIVE_SET) self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(texCoords))
def __init__(self, capiness=0.5, interiorIncludesCaps=False, *args, **keywordArgs): """ Create a new capsule shape. The 'capiness' parameter controls how much of the shape is made up of the caps. A 1.0 value would be all caps and effectively be a sphere. A 0.0 value would be no caps and effectively be a cylinder. The interiorIncludesCaps parameter controls whether nested shapes should extend up into the caps or should be restrained to the cylinder portion of the capsule.""" Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? # TODO: fix seams caused by texture coords self.capiness = capiness self.interiorIncludesCaps = interiorIncludesCaps steps = 32 # must be multiple of four angleIncrement = 2.0 * pi / steps capSteps = steps / 4 azimuthIncrement = pi / 2.0 / capSteps topVertices = [] topTexCoords = [] bottomVertices = [] bottomTexCoords = [] for azimuthStep in range(0, capSteps): topAzimuth = pi / 2.0 - (azimuthStep + 1) * azimuthIncrement topY, topMag = (sin(topAzimuth) * (capiness / 2.0), cos(topAzimuth) * 0.5) bottomAzimuth = -azimuthStep * azimuthIncrement bottomY, bottomMag = (sin(bottomAzimuth) * (capiness / 2.0), cos(bottomAzimuth) * 0.5) for step in range(0, steps): angle = pi + step * angleIncrement topVertices += [ (sin(angle) * topMag, topY + (0.5 * (1.0 - capiness)), cos(angle) * topMag) ] topTexCoords += [(float(step) / steps, topVertices[-1][1] + 0.5)] bottomVertices += [(sin(angle) * bottomMag, -(0.5 * (1.0 - capiness)) + bottomY, cos(angle) * bottomMag)] bottomTexCoords += [(float(step) / steps, bottomVertices[-1][1] + 0.5)] vertices = [(0.0, 0.5, 0.0) ] + topVertices + bottomVertices + [(0.0, -0.5, 0.0)] self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices)) normals = [] for vertex in vertices: normals += [(vertex[0] / 2.0, vertex[1] / 2.0, vertex[2] / 2.0)] self.geometry().setNormalArray(Shape.vectorArrayFromList(normals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) texCoords = [(0.0, 1.0)] + topTexCoords + bottomTexCoords + [(0.0, 0.0) ] self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(texCoords)) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLE_FAN, range(0, steps + 1) + [1, 0]) self.geometry().addPrimitiveSet(faceSet) for stripNum in range(0, 2 * capSteps - 1): vertexIndices = [] baseIndex = 1 + stripNum * steps for step in range(steps) + [0]: vertexIndices += [baseIndex + step, baseIndex + steps + step] faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.QUAD_STRIP, vertexIndices) self.geometry().addPrimitiveSet(faceSet) bottomFanBaseIndex = len(vertices) - steps - 1 faceSet = Shape.primitiveSetFromList( osg.PrimitiveSet.TRIANGLE_FAN, [len(vertices) - 1] + range(bottomFanBaseIndex, bottomFanBaseIndex + steps) + [bottomFanBaseIndex, len(vertices) - 1]) self.geometry().addPrimitiveSet(faceSet)
def __init__(self, holeSize = 1.0 / 3.0, startAngle = 0.0, endAngle = 2 * pi, *args, **keywordArgs): Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? self.holeSize = holeSize self.startAngle = startAngle self.endAngle = endAngle self._bounds = ((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)) steps = 32 ringIncrement = (endAngle - startAngle) / steps segmentIncrement = 2 * pi / steps # Duplicate vertices are created at the seams to avoid texture problems so steps + 1 segments and steps + 1 vertices per segment are created. segmentRadius = (1.0 - holeSize) / 4.0 ringRadius = 0.5 - segmentRadius vertices = [] normals = [] texCoords = [] xs = [] ys = [] zs = [] for ringStep in range(0, steps + 1): ringAngle = startAngle + ringStep * ringIncrement segmentCenter = (cos(ringAngle) * ringRadius, sin(ringAngle) * ringRadius, 0.0) for segmentStep in range(0, steps + 1): segmentAngle = segmentStep * segmentIncrement segmentMag = cos(segmentAngle) * segmentRadius x, y, z, zNormal = (cos(ringAngle) * (ringRadius + segmentMag), sin(ringAngle) * (ringRadius + segmentMag), sin(segmentAngle) * 0.5, sin(segmentAngle) * segmentRadius) vertices += [(x, y, z)] normal = (x - segmentCenter[0], y - segmentCenter[1], zNormal - segmentCenter[2]) normalMag = sqrt(normal[0] ** 2 + normal[1] ** 2 + normal[2] ** 2) normals += [(normal[0] / normalMag, normal[1] / normalMag, normal[2] / normalMag)] texCoords += [(float(ringStep) / steps, float(segmentStep) / steps)] xs += [x] ys += [y] zs += [z] minX, maxX = (min(xs), max(xs)) midX, sizeX = ((minX + maxX) / 2.0, maxX - minX) minY, maxY = (min(ys), max(ys)) midY, sizeY = ((minY + maxY) / 2.0, maxY - minY) minZ, maxZ = (min(zs), max(zs)) midZ = (minZ + maxZ) / 2.0 self._bounds = ((minX, minY, minZ), (maxX, maxY, maxZ)) scale = 1.0 / max(sizeX, sizeY) # size in Z will always be 1.0 newVertices = [] for vertex in vertices: newVertices += [((vertex[0] - midX) * scale, (vertex[1] - midY) * scale, (vertex[2] - midZ) * scale)] self.geometry().setVertexArray(Shape.vectorArrayFromList(newVertices)) self.ringCenter = (-midX, -midY, -midZ) self.ringSize = 1.0 / scale self.geometry().setNormalArray(Shape.vectorArrayFromList(normals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(texCoords)) for ringStep in range(0, steps): baseIndex = ringStep * (steps + 1) vertexIndices = [] for segmentStep in range(0, steps + 1): vertexIndices += [baseIndex + segmentStep, baseIndex + steps + 1 + segmentStep] faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.QUAD_STRIP, vertexIndices) self.geometry().addPrimitiveSet(faceSet)
def _tessellate(cls): # Code inspired by Chapter 2 of the OpenGL Red Book. if not any(Ball._vertices): # Start with an icosahedron X = .525731112119133606 * 0.5 Z = .850650808352039932 * 0.5 newVertices = [(-X, 0.0, Z), (X, 0.0, Z), (-X, 0.0, -Z), (X, 0.0, -Z), (0.0, Z, X), (0.0, Z, -X), (0.0, -Z, X), (0.0, -Z, -X), (Z, X, 0.0), (-Z, X, 0.0), (Z, -X, 0.0), (-Z, -X, 0.0)] newFaces = [(0,4,1), (0,9,4), (9,5,4), (4,5,8), (4,8,1), (8,10,1), (8,3,10), (5,3,8), (5,2,3), (2,7,3), (7,10,3), (7,6,10), (7,11,6), (11,0,6), (0,1,6), (6,1,10), (9,0,11), (9,11,2), (9,2,5), (7,2,11)] else: # Subdivide each triangular face into four triangular sub-faces by finding the midpoint of each side. # New vertices will be added to a copy of the existing list and a completely new set of faces will be produced. newVertices = list(Ball._vertices[-1]) newFaces = [] for face in Ball._faces[-1]: index0 = face[0] vertex0 = newVertices[index0] index1 = face[1] vertex1 = newVertices[index1] index2 = face[2] vertex2 = newVertices[index2] # Add a new vertex between vertex 0 and vertex 1. vertex3 = (vertex0[0] + vertex1[0], vertex0[1] + vertex1[1], vertex0[2] + vertex1[2]) mag = sqrt(vertex3[0] ** 2 + vertex3[1] ** 2 + vertex3[2] ** 2) * 2.0 vertex3 = (vertex3[0] / mag, vertex3[1] / mag, vertex3[2] / mag) try: index3 = newVertices.index(vertex3) except: newVertices += [vertex3] index3 = len(newVertices) - 1 # Add a new vertex between vertex 1 and vertex 2. vertex4 = (vertex1[0] + vertex2[0], vertex1[1] + vertex2[1], vertex1[2] + vertex2[2]) mag = sqrt(vertex4[0] ** 2 + vertex4[1] ** 2 + vertex4[2] ** 2) * 2.0 vertex4 = (vertex4[0] / mag, vertex4[1] / mag, vertex4[2] / mag) try: index4 = newVertices.index(vertex4) except: newVertices += [vertex4] index4 = len(newVertices) - 1 # Add a new vertex between vertex 0 and vertex 2. vertex5 = (vertex0[0] + vertex2[0], vertex0[1] + vertex2[1], vertex0[2] + vertex2[2]) mag = sqrt(vertex5[0] ** 2 + vertex5[1] ** 2 + vertex5[2] ** 2) * 2.0 vertex5 = (vertex5[0] / mag, vertex5[1] / mag, vertex5[2] / mag) try: index5 = newVertices.index(vertex5) except: newVertices += [vertex5] index5 = len(newVertices) - 1 # Add the four new faces. newFaces += [(index0, index3, index5), (index3, index1, index4), (index3, index4, index5), (index5, index4, index2)] Ball._vertices += [newVertices] Ball._vertexArray += [Shape.vectorArrayFromList(newVertices)] normals = [] texCoords = [] for vertex in newVertices: normals += [(vertex[0] * 2.0, vertex[1] * 2.0, vertex[2] * 2.0)] texCoords += [(vertex[0] + 0.5, vertex[2] + 0.5)] #[(atan2(vertex[2], vertex[0]) / pi / 2.0 + 0.5, atan2(vertex[2], vertex[1]) / pi / 2.0 + 0.5)] Ball._normalArray += [Shape.vectorArrayFromList(normals)] Ball._texCoordArray += [Shape.vectorArrayFromList(texCoords)] Ball._faces += [newFaces] faceVertices = [] for face in newFaces: faceVertices += face Ball._faceSet += [Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLES, faceVertices)]
def __init__(self, capiness=0.5, interiorIncludesCaps=False, *args, **keywordArgs): """ Create a new capsule shape. The 'capiness' parameter controls how much of the shape is made up of the caps. A 1.0 value would be all caps and effectively be a sphere. A 0.0 value would be no caps and effectively be a cylinder. The interiorIncludesCaps parameter controls whether nested shapes should extend up into the caps or should be restrained to the cylinder portion of the capsule.""" Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? # TODO: fix seams caused by texture coords self.capiness = capiness self.interiorIncludesCaps = interiorIncludesCaps steps = 32 # must be multiple of four angleIncrement = 2.0 * pi / steps capSteps = steps / 4 azimuthIncrement = pi / 2.0 / capSteps topVertices = [] topTexCoords = [] bottomVertices = [] bottomTexCoords = [] for azimuthStep in range(0, capSteps): topAzimuth = pi / 2.0 - (azimuthStep + 1) * azimuthIncrement topY, topMag = (sin(topAzimuth) * (capiness / 2.0), cos(topAzimuth) * 0.5) bottomAzimuth = -azimuthStep * azimuthIncrement bottomY, bottomMag = (sin(bottomAzimuth) * (capiness / 2.0), cos(bottomAzimuth) * 0.5) for step in range(0, steps): angle = pi + step * angleIncrement topVertices += [(sin(angle) * topMag, topY + (0.5 * (1.0 - capiness)), cos(angle) * topMag)] topTexCoords += [(float(step) / steps, topVertices[-1][1] + 0.5)] bottomVertices += [ (sin(angle) * bottomMag, -(0.5 * (1.0 - capiness)) + bottomY, cos(angle) * bottomMag) ] bottomTexCoords += [(float(step) / steps, bottomVertices[-1][1] + 0.5)] vertices = [(0.0, 0.5, 0.0)] + topVertices + bottomVertices + [(0.0, -0.5, 0.0)] self.geometry().setVertexArray(Shape.vectorArrayFromList(vertices)) normals = [] for vertex in vertices: normals += [(vertex[0] / 2.0, vertex[1] / 2.0, vertex[2] / 2.0)] self.geometry().setNormalArray(Shape.vectorArrayFromList(normals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) texCoords = [(0.0, 1.0)] + topTexCoords + bottomTexCoords + [(0.0, 0.0)] self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(texCoords)) faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.TRIANGLE_FAN, range(0, steps + 1) + [1, 0]) self.geometry().addPrimitiveSet(faceSet) for stripNum in range(0, 2 * capSteps - 1): vertexIndices = [] baseIndex = 1 + stripNum * steps for step in range(steps) + [0]: vertexIndices += [baseIndex + step, baseIndex + steps + step] faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.QUAD_STRIP, vertexIndices) self.geometry().addPrimitiveSet(faceSet) bottomFanBaseIndex = len(vertices) - steps - 1 faceSet = Shape.primitiveSetFromList( osg.PrimitiveSet.TRIANGLE_FAN, [len(vertices) - 1] + range(bottomFanBaseIndex, bottomFanBaseIndex + steps) + [bottomFanBaseIndex, len(vertices) - 1], ) self.geometry().addPrimitiveSet(faceSet)
def __init__(self, holeSize=1.0 / 3.0, startAngle=0.0, endAngle=2 * pi, *args, **keywordArgs): Shape.__init__(self, *args, **keywordArgs) # TODO: use VBO's so all instances share the same data? self.holeSize = holeSize self.startAngle = startAngle self.endAngle = endAngle self._bounds = ((-0.5, -0.5, -0.5), (0.5, 0.5, 0.5)) steps = 32 ringIncrement = (endAngle - startAngle) / steps segmentIncrement = 2 * pi / steps # Duplicate vertices are created at the seams to avoid texture problems so steps + 1 segments and steps + 1 vertices per segment are created. segmentRadius = (1.0 - holeSize) / 4.0 ringRadius = 0.5 - segmentRadius vertices = [] normals = [] texCoords = [] xs = [] ys = [] zs = [] for ringStep in range(0, steps + 1): ringAngle = startAngle + ringStep * ringIncrement segmentCenter = (cos(ringAngle) * ringRadius, sin(ringAngle) * ringRadius, 0.0) for segmentStep in range(0, steps + 1): segmentAngle = segmentStep * segmentIncrement segmentMag = cos(segmentAngle) * segmentRadius x, y, z, zNormal = (cos(ringAngle) * (ringRadius + segmentMag), sin(ringAngle) * (ringRadius + segmentMag), sin(segmentAngle) * 0.5, sin(segmentAngle) * segmentRadius) vertices += [(x, y, z)] normal = (x - segmentCenter[0], y - segmentCenter[1], zNormal - segmentCenter[2]) normalMag = sqrt(normal[0]**2 + normal[1]**2 + normal[2]**2) normals += [(normal[0] / normalMag, normal[1] / normalMag, normal[2] / normalMag)] texCoords += [(float(ringStep) / steps, float(segmentStep) / steps)] xs += [x] ys += [y] zs += [z] minX, maxX = (min(xs), max(xs)) midX, sizeX = ((minX + maxX) / 2.0, maxX - minX) minY, maxY = (min(ys), max(ys)) midY, sizeY = ((minY + maxY) / 2.0, maxY - minY) minZ, maxZ = (min(zs), max(zs)) midZ = (minZ + maxZ) / 2.0 self._bounds = ((minX, minY, minZ), (maxX, maxY, maxZ)) scale = 1.0 / max(sizeX, sizeY) # size in Z will always be 1.0 newVertices = [] for vertex in vertices: newVertices += [ ((vertex[0] - midX) * scale, (vertex[1] - midY) * scale, (vertex[2] - midZ) * scale) ] self.geometry().setVertexArray(Shape.vectorArrayFromList(newVertices)) self.ringCenter = (-midX, -midY, -midZ) self.ringSize = 1.0 / scale self.geometry().setNormalArray(Shape.vectorArrayFromList(normals)) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) self.geometry().setTexCoordArray(0, Shape.vectorArrayFromList(texCoords)) for ringStep in range(0, steps): baseIndex = ringStep * (steps + 1) vertexIndices = [] for segmentStep in range(0, steps + 1): vertexIndices += [ baseIndex + segmentStep, baseIndex + steps + 1 + segmentStep ] faceSet = Shape.primitiveSetFromList(osg.PrimitiveSet.QUAD_STRIP, vertexIndices) self.geometry().addPrimitiveSet(faceSet)