def build_normalPerVertex( vertices, creaseAngle, vertexArray=None ): '''Create a normal vector using creaseAngle to determine smoothing Note: the semantics of normalPerVertex requires using expanded (i.e. tessellated) values, as the generated normals are *not* supposed to be applied to each vertex, but instead to each *use* of each vertex (i.e. each triangle's ref to the vertex has a potentially different normal) vertices -- list of vertex objects in rendering order (triangles) creaseAngle -- radian angle above which faces do not smooth. vertexArray -- x*3*3 array of coordinates expanded into a flat data-array, if not provided, generated from vertices ''' if vertexArray is None: vertexArray = array([vertex.point for vertex in vertices],'f') faceNormals = triangleutilities.normalPerFace( vertexArray ) vertexNormals = repeat(faceNormals,[3]*len(faceNormals),0) faceNormals = array(vertexNormals[:]) items = {} for index in range( len( vertices)): try: items.setdefault( vertices[index].coordIndex, []).append( index ) except TypeError, err: print vertices[index] print type(vertices[index].coordIndex),vertices[index].coordIndex raise
def build_normalPerVertex(vertices, creaseAngle, vertexArray=None): '''Create a normal vector using creaseAngle to determine smoothing Note: the semantics of normalPerVertex requires using expanded (i.e. tessellated) values, as the generated normals are *not* supposed to be applied to each vertex, but instead to each *use* of each vertex (i.e. each triangle's ref to the vertex has a potentially different normal) vertices -- list of vertex objects in rendering order (triangles) creaseAngle -- radian angle above which faces do not smooth. vertexArray -- x*3*3 array of coordinates expanded into a flat data-array, if not provided, generated from vertices ''' if vertexArray is None: vertexArray = array([vertex.point for vertex in vertices], 'f') faceNormals = triangleutilities.normalPerFace(vertexArray) vertexNormals = repeat(faceNormals, [3] * len(faceNormals), 0) faceNormals = array(vertexNormals[:]) items = {} for index in range(len(vertices)): try: items.setdefault(vertices[index].coordIndex, []).append(index) except TypeError, err: print vertices[index] print type(vertices[index].coordIndex), vertices[index].coordIndex raise
def __init__(self, points, normals=None, ccw=1): """Initialize the EdgeSet points -- n*3 array of points, n%3 == 0, where each set of three points defines a single triangle in ccw winding normals -- optional array of per-triangle normals, will be calculated if necessary ccw -- boolean indicating whether counter-clock-wise winding is to be used (normal OpenGL/VRML winding) if false, then use clockwise winding (Note that this has never been tested, as I don't have any cw geometry around to test with, and haven't felt energetic enough to work around the standard tools to make any) """ self.volumes = weakref.WeakKeyDictionary() self.ccw = ccw self.points = points self.normals = triangleutilities.normalPerFace(points, ccw=ccw) self.points_to_edges()
def __init__( self, points, normals=None, ccw = 1 ): """Initialize the EdgeSet points -- n*3 array of points, n%3 == 0, where each set of three points defines a single triangle in ccw winding normals -- optional array of per-triangle normals, will be calculated if necessary ccw -- boolean indicating whether counter-clock-wise winding is to be used (normal OpenGL/VRML winding) if false, then use clockwise winding (Note that this has never been tested, as I don't have any cw geometry around to test with, and haven't felt energetic enough to work around the standard tools to make any) """ self.volumes = weakref.WeakKeyDictionary() self.ccw = ccw self.points = points self.normals = triangleutilities.normalPerFace( points, ccw=ccw ) self.points_to_edges()
def build_normalPerVertex(vertices, creaseAngle, vertexArray=None): '''Create a normal vector using creaseAngle to determine smoothing Note: the semantics of normalPerVertex requires using expanded (i.e. tessellated) values, as the generated normals are *not* supposed to be applied to each vertex, but instead to each *use* of each vertex (i.e. each triangle's ref to the vertex has a potentially different normal) vertices -- list of vertex objects in rendering order (triangles) creaseAngle -- radian angle above which faces do not smooth. vertexArray -- x*3*3 array of coordinates expanded into a flat data-array, if not provided, generated from vertices ''' if vertexArray is None: vertexArray = array([vertex.point for vertex in vertices], 'f') faceNormals = triangleutilities.normalPerFace(vertexArray) vertexNormals = repeat(faceNormals, [3] * len(faceNormals), 0) faceNormals = array(vertexNormals[:]) items = {} for index in range(len(vertices)): try: items.setdefault(vertices[index].coordIndex, []).append(index) except TypeError as err: print vertices[index] print type(vertices[index].coordIndex), vertices[index].coordIndex raise # verticies. We use ones instead of zeros because each face # contributes to its own corner. Note: will be promoted to float # during the final division counts = ones((len(vertexNormals), ), 'f') for vertexSet in items.values(): # For each primary user (triangle corner) for index in range(len(vertexSet)): primaryNormal = faceNormals[vertexSet[index]] # check to see if any of the remaining triangles should # be blended with this one for innerindex in range(index + 1, len(vertexSet)): secondaryNormal = faceNormals[vertexSet[innerindex]] # if angle < creaseAngle... should calculate # cos(creaseAngle) instead of using arccos each time try: angle = arccos(dot(primaryNormal, secondaryNormal)) except ValueError as err: # arccos of equal vectors goes kablooie angle = 0 if angle < creaseAngle: #add to each other's cummulative total (in place) add(vertexNormals[vertexSet[index]], secondaryNormal, vertexNormals[vertexSet[index]]) # add in place add(vertexNormals[vertexSet[innerindex]], primaryNormal, vertexNormals[vertexSet[innerindex]]) # add in place # and increment the element counts counts[vertexSet[index]] = counts[vertexSet[index]] + 1 counts[vertexSet[innerindex]] = counts[ vertexSet[innerindex]] + 1 # reshape counts to allow for in-place division... counts.shape = (-1, 1) # divide in place, completing the averaging (and thereby hopefully # re-normalising the Normal vectors) divide(vertexNormals, counts, vertexNormals) return vertexNormals
def compile( self, visible=1, lit=1, textured=1, transparent=0, mode=None, ): """Compile to an opaque textured display-list""" dl = displaylist.DisplayList() dl.start() try: if (not self.target.normal) or ( self.target.normal and not len(self.target.normal.vector)): # need to generate per-face or per-vertex-use vectors, # require tessellation! vertices = self.tessellate() if not vertices: return None if self.target.normalPerVertex: normalArray = build_normalPerVertex( vertices, self.target.creaseAngle) normalStep = 1 else: normalArray = triangleutilities.normalPerFace(vertexArray) normalArray = repeat(normalArray, [3] * len(normalArray), 0) normalStep = 3 glBegin(GL_TRIANGLES) if self.target.DEBUG_DRAW_NORMALS: normalValues = [] try: normalIndex = -1 for vIndex in xrange(len(vertices)): vertex = vertices[vIndex] if vIndex % normalStep == 0: normalIndex += 1 glNormal3dv(normalArray[normalIndex]) if vertex.color is not None: glColor3dv(vertex.color) if vertex.textureCoordinate is not None: glTexCoord2dv(vertex.textureCoordinate) glVertex3dv(vertex.point) if self.target.DEBUG_DRAW_NORMALS: normalValues.append( (vertex.point, vertex.point + normalArray[normalIndex])) finally: glEnd() if self.target.DEBUG_DRAW_NORMALS: glBegin(GL_LINES) try: for (v, n) in normalValues: glColor3f(1, 0, 0) glVertex3dv(v) glColor3f(0, 1, 0) glVertex3dv(n) finally: glEnd() else: # already has normals, can render without tessellation for polygon in self.polygons(): if len(polygon) == 3: glBegin(GL_TRIANGLES) elif len(polygon) == 4: glBegin(GL_QUADS) elif len(polygon) < 3: continue else: glBegin(GL_POLYGON) try: for vertex in polygon: if vertex.normal is not None: glNormal3dv(vertex.normal) if vertex.color is not None: glColor3dv(vertex.color) if vertex.textureCoordinate is not None: glTexCoord2dv(vertex.textureCoordinate) glVertex3dv(vertex.point) finally: glEnd() return DisplayListRenderer(dl) finally: dl.end()
def compile( self, visible=1, lit=1, textured=1, transparent=0, mode=None, ): """Compile the rendering structures for an ArrayGeometry version of IFS XXX Should redo to cache like so... cache tessellated triangle indices if any indices change, need to re-calculate everything coord -> [ pointIndices ], [ calcualtedNormals ] normal -> [ normalIndices ] when points change, just re-calculate: expanded-normals (if we are calculating normals) expanded-points when normals change (explicit normal/indices) expanded-normals fully-expanded normal, texCooord, and color """ ### XXX should store normals regardless of "lit" field and discard lit # XXX check to see if we are all using the same indices, # if so, we can possibly use IndexedPolygons instead # of IndexedFaceSet for rendering... vertices = self.tessellate() # vertices is now a list of vertices such that # every three vertices represents a single triangle # good time to build normals if required... vertexArray = array([vertex.point for vertex in vertices], 'f') if len(vertexArray) == 0: return DUMMY_RENDER else: if (not self.target.normal) or (not len( self.target.normal.vector)): # need to calculate normals if self.target.normalPerVertex: normalArray = build_normalPerVertex( vertices, self.target.creaseAngle, vertexArray) else: normalArray = triangleutilities.normalPerFace(vertexArray) normalArray = repeat(normalArray, [3] * len(normalArray), 0) else: normalArray = [] for vertex in vertices: if vertex.normal is not None: normalArray.append(vertex.normal) elif normalArray: normalArray.append(normalArray[-1]) else: normalArray.append((0, 0, 1)) normalArray = array(normalArray, 'f') if self.target.color and len(self.target.color.color): try: colorArray = array([vertex.color for vertex in vertices], 'f') except TypeError: colorArray = None log.warn( """%s tessellation appears to have created invalid color for tesselated vertex""", self.target) else: colorArray = None if self.target.texCoord and len(self.target.texCoord.point): textureCoordinateArray = array( [vertex.textureCoordinate for vertex in vertices], 'f') else: textureCoordinateArray = None log.debug( 'Arrays: \nvertex -- %s\nnormal -- %s', vertexArray, normalArray, ) ag = arraygeometry.ArrayGeometry( vertexArray, colorArray, normalArray, textureCoordinateArray, objectType=GL_TRIANGLES, ccw=self.target.ccw, solid=self.target.solid, ) return ag
def compile( self, visible = 1, lit = 1, textured = 1, transparent = 0, mode=None, ): """Compile to an opaque textured display-list""" dl = displaylist.DisplayList() dl.start() try: if (not self.target.normal) or (self.target.normal and not len(self.target.normal.vector)): # need to generate per-face or per-vertex-use vectors, # require tessellation! vertices = self.tessellate() if not vertices: return None if self.target.normalPerVertex: normalArray = build_normalPerVertex( vertices, self.target.creaseAngle ) normalStep = 1 else: normalArray = triangleutilities.normalPerFace( vertexArray) normalArray = repeat( normalArray,[3]*len(normalArray),0) normalStep = 3 glBegin( GL_TRIANGLES ) if self.target.DEBUG_DRAW_NORMALS: normalValues = [] try: normalIndex = -1 for vIndex in xrange(len(vertices)): vertex = vertices[vIndex] if vIndex % normalStep == 0: normalIndex += 1 glNormal3dv( normalArray[normalIndex] ) if vertex.color is not None: glColor3dv( vertex.color ) if vertex.textureCoordinate is not None: glTexCoord2dv( vertex.textureCoordinate ) glVertex3dv( vertex.point ) if self.target.DEBUG_DRAW_NORMALS: normalValues.append( (vertex.point, vertex.point+normalArray[normalIndex]) ) finally: glEnd() if self.target.DEBUG_DRAW_NORMALS: glBegin( GL_LINES ) try: for (v,n) in normalValues: glColor3f( 1,0,0) glVertex3dv( v ) glColor3f( 0,1,0) glVertex3dv( n ) finally: glEnd() else: # already has normals, can render without tessellation for polygon in self.polygons(): if len(polygon) == 3: glBegin( GL_TRIANGLES ) elif len(polygon) == 4: glBegin( GL_QUADS ) elif len(polygon) < 3: continue else: glBegin( GL_POLYGON ) try: for vertex in polygon: if vertex.normal is not None: glNormal3dv( vertex.normal ) if vertex.color is not None: glColor3dv( vertex.color ) if vertex.textureCoordinate is not None: glTexCoord2dv( vertex.textureCoordinate ) glVertex3dv( vertex.point ) finally: glEnd() return DisplayListRenderer( dl ) finally: dl.end()
def compile( self, visible = 1, lit = 1, textured = 1, transparent = 0, mode=None, ): """Compile the rendering structures for an ArrayGeometry version of IFS XXX Should redo to cache like so... cache tessellated triangle indices if any indices change, need to re-calculate everything coord -> [ pointIndices ], [ calcualtedNormals ] normal -> [ normalIndices ] when points change, just re-calculate: expanded-normals (if we are calculating normals) expanded-points when normals change (explicit normal/indices) expanded-normals fully-expanded normal, texCooord, and color """ ### XXX should store normals regardless of "lit" field and discard lit # XXX check to see if we are all using the same indices, # if so, we can possibly use IndexedPolygons instead # of IndexedFaceSet for rendering... vertices = self.tessellate() # vertices is now a list of vertices such that # every three vertices represents a single triangle # good time to build normals if required... vertexArray = array([vertex.point for vertex in vertices],'f') if len(vertexArray) == 0: return DUMMY_RENDER else: if (not self.target.normal) or (not len(self.target.normal.vector)): # need to calculate normals if self.target.normalPerVertex: normalArray = build_normalPerVertex( vertices, self.target.creaseAngle, vertexArray ) else: normalArray = triangleutilities.normalPerFace( vertexArray) normalArray = repeat( normalArray,[3]*len(normalArray), 0) else: normalArray = [] for vertex in vertices: if vertex.normal is not None: normalArray.append( vertex.normal ) elif normalArray: normalArray.append( normalArray[-1] ) else: normalArray.append( (0,0,1)) normalArray = array(normalArray,'f') if self.target.color and len(self.target.color.color): try: colorArray = array([vertex.color for vertex in vertices],'f') except TypeError: colorArray = None log.warn("""%s tessellation appears to have created invalid color for tesselated vertex""",self.target) else: colorArray = None if self.target.texCoord and len(self.target.texCoord.point): textureCoordinateArray = array([vertex.textureCoordinate for vertex in vertices],'f') else: textureCoordinateArray = None log.debug( 'Arrays: \nvertex -- %s\nnormal -- %s', vertexArray, normalArray, ) ag = arraygeometry.ArrayGeometry( vertexArray, colorArray, normalArray, textureCoordinateArray, objectType= GL_TRIANGLES, ccw = self.target.ccw, solid = self.target.solid, ) return ag