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, tessellation = 3, *args, **keywordArgs): Shape.__init__(self, *args, **keywordArgs) self.tessellation = tessellation vertices, normals, texCoords, faceSet = Ball._geometryAtTessellation(tessellation) self.geometry().setVertexArray(vertices) self.geometry().setNormalArray(normals) self.geometry().setNormalBinding(osg.Geometry.BIND_PER_VERTEX) self.geometry().setTexCoordArray(0, texCoords) self.geometry().addPrimitiveSet(faceSet)
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, 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, 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 __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)