def render(self) -> None: """Render ViewCube to canvas.""" if not self.init(): return glViewport(*self._get_viewport()) proj = glm.ortho(-2.3, 2.3, -2.3, 2.3, -2.3, 2.3) mat = glm.lookAt( vec3(0.0, -1.0, 0.0), # position vec3(0.0, 0.0, 0.0), # target vec3(0.0, 0.0, 1.0)) # up modelview = mat * glm.mat4_cast(self.parent.rot_quat) glUseProgram(self.parent.shaders['default']) glUniformMatrix4fv(0, 1, GL_FALSE, glm.value_ptr(proj)) glUniformMatrix4fv(1, 1, GL_FALSE, glm.value_ptr(modelview)) glBindVertexArray(self._vao) glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, ctypes.c_void_p(0)) self._render_highlighted() glBindVertexArray(0) glUseProgram(0)
def _do_render(self, **kwargs): if 'objects' not in kwargs.keys(): return instances: List[Generic[EntityTV, AgentTV]] = kwargs['objects'] model: RawModel = instances[0].model glBindVertexArray(model.vao_id) glEnableVertexAttribArray(0) for instance in instances: model: RawModel = instance.model # transformation_matrix = create_transformation_matrix( # instance.position, instance.rotation, instance.scale) self.shader.load_transformation_matrix(instance.transformation_matrix) if isinstance(self.shader, StaticShader): self.shader.load_vertex_color(instance.color) glDrawElements(GL_TRIANGLES, model.vertex_count, GL_UNSIGNED_INT, None) glDisableVertexAttribArray(0) glBindVertexArray(0)
def renderEach(self, mode=GL_TRIANGLES): """ per triangle rendering """ offset = 0 for size in self.sizes: glDrawElements(GL_TRIANGLE_STRIP, size, GL_UNSIGNED_INT, c_void_p(offset)) offset += size * sizeof(c_uint)
def render(self, proj: np.ndarray, view: np.ndarray, _lights: List[Light]) -> bool: """ Virtual function for rendering the object. Args: proj: Camera projection matrix. view: Camera location/view matrix. """ if not self.visible: return True if self._vao == -1: self.build() self._model_matrix = np.array(self.matrix, dtype=np.float32) self._material.render(proj, view, self._model_matrix, []) if glIsVertexArray(self._vao): glBindVertexArray(self._vao) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDrawElements( GL_LINES, self._vertex_count, GL_UNSIGNED_INT, ctypes.c_void_p(0), ) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glBindVertexArray(0) self._material.end() return True
def _render_bounding_box(self) -> None: """Render bounding box.""" if self._vao_bounding_box is None: return glBindVertexArray(self._vao_bounding_box) glDrawElements(GL_LINES, self._count_bounding_box, GL_UNSIGNED_INT, ctypes.c_void_p(0))
def render(self): """Renders the model. NOTE: The current OpenGL context is used, thus, there *MUST* be one set up and active before calling this method. """ glBindVertexArray(self.vao) glDrawElements(GL_TRIANGLES, self.num_elements, GL_UNSIGNED_INT, None) glBindVertexArray(0)
def __generate_model(self): """Generate rotated model with shadows.""" glEnable(GL_CULL_FACE) self.__sh.change_shader(vertex=0, fragment=0) self.__prepare_shaders(self.__model_matrix, self.__light_matrix, False) self.__sh.bind_buffer() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glDrawElements(GL_TRIANGLES, View.__triangles.size, GL_UNSIGNED_SHORT, View.__triangles) self.__sh.clear()
def __generate_shadows(self): """Generate shadow matrix for rotated model.""" glDisable(GL_CULL_FACE) glEnable(GL_POLYGON_OFFSET_FILL) glPolygonOffset(3, 0) self.__sh.change_shader(vertex=1, fragment=1) self.__prepare_shaders(self.__model_matrix, self.__light_matrix, True) self.__sh.bind_fbo() glClear(GL_DEPTH_BUFFER_BIT) glDrawElements(GL_TRIANGLES, View.__triangles.size, GL_UNSIGNED_SHORT, View.__triangles) glFinish() glBindFramebuffer(GL_FRAMEBUFFER, 0) self.__sh.clear()
def render(self) -> None: """Render proxy objects to canvas with a diffuse shader.""" if not self.init(): return proj = self.parent.projection_matrix view = self.parent.modelview_matrix glUseProgram(self.parent.shaders['diffuse']) glUniformMatrix4fv(0, 1, GL_FALSE, glm.value_ptr(proj)) glUniformMatrix4fv(1, 1, GL_FALSE, glm.value_ptr(view)) for mesh in self._meshes: glBindVertexArray(mesh.vao) glUniform4fv(2, 1, glm.value_ptr(mesh.color)) glUniform1i(3, int(mesh.selected)) glDrawElements(GL_TRIANGLES, mesh.count, GL_UNSIGNED_INT, ctypes.c_void_p(0)) glBindVertexArray(0) glUseProgram(0)
def render(self, model, view_matrix, projection_matrix): glUseProgram(self.program) glEnableVertexAttribArray(self.vertices) glUniformMatrix4fv(self.model_view_matrix, 1, GL_TRUE, np.dot(view_matrix, model.matrix)) glUniformMatrix4fv(self.projection_matrix, 1, GL_TRUE, projection_matrix) glVertexAttribPointer(self.vertices, 3, GL_FLOAT, GL_FALSE, 0, model.vertex_buffer) glUniform1f(self.color_uniform, 0) glDrawElements(GL_LINES, model.line_buffer.size, GL_UNSIGNED_BYTE, model.line_buffer) glUniform1f(self.color_uniform, 0.5) glDrawElements(GL_TRIANGLES, model.index_buffer.size, GL_UNSIGNED_BYTE, model.index_buffer) glDisableVertexAttribArray(self.vertices)
def drawLineCube(color, pos, radius): vtIndices = [0, 1, 2, 3, 0, 4, 5, 1, 5, 4, 7, 6, 6, 7, 3, 2] glEnableClientState(GL_VERTEX_ARRAY) #bruce 051117 revised this glVertexPointer(3, GL_FLOAT, 0, drawing_globals.flatCubeVertices) #grantham 20051213 observations, reported/paraphrased by bruce 051215: # - should verify PyOpenGL turns Python float (i.e. C double) into C # float for OpenGL's GL_FLOAT array element type. # - note that GPUs are optimized for DrawElements types GL_UNSIGNED_INT # and GL_UNSIGNED_SHORT. glDisable(GL_LIGHTING) glColor3fv(color) glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius, radius, radius) glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices) #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[4]) #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[8]) #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[12]) glPopMatrix() glEnable(GL_LIGHTING) glDisableClientState(GL_VERTEX_ARRAY) return
def render_for_picking(self) -> None: """Render proxy objects for picking pass.""" if not self.init(): return proj = self.parent.projection_matrix view = self.parent.modelview_matrix glUseProgram(self.parent.shaders['solid']) glUniformMatrix4fv(0, 1, GL_FALSE, glm.value_ptr(proj)) glUniformMatrix4fv(1, 1, GL_FALSE, glm.value_ptr(view)) for mesh in self._meshes: glBindVertexArray(mesh.vao) glUniform1i(2, MAX_ID - mesh.object_id) glDrawElements(GL_TRIANGLES, mesh.count, GL_UNSIGNED_INT, ctypes.c_void_p(0)) glBindVertexArray(0) glUseProgram(0) glBindVertexArray(0) glUseProgram(0)
def drawLineCube(color, pos, radius): vtIndices = [0,1,2,3, 0,4,5,1, 5,4,7,6, 6,7,3,2] glEnableClientState(GL_VERTEX_ARRAY) #bruce 051117 revised this glVertexPointer(3, GL_FLOAT, 0, drawing_globals.flatCubeVertices) #grantham 20051213 observations, reported/paraphrased by bruce 051215: # - should verify PyOpenGL turns Python float (i.e. C double) into C # float for OpenGL's GL_FLOAT array element type. # - note that GPUs are optimized for DrawElements types GL_UNSIGNED_INT # and GL_UNSIGNED_SHORT. glDisable(GL_LIGHTING) glColor3fv(color) glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius,radius,radius) glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices) #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[4]) #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[8]) #glDrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_BYTE, vtIndices[12]) glPopMatrix() glEnable(GL_LIGHTING) glDisableClientState(GL_VERTEX_ARRAY) return
def _render_solid_obj(self, solid_object, width, height, VMatrix, PMatrix): glEnable(GL_DEPTH_TEST) glUseProgram(self.shader.program) glBindVertexArray(solid_object.vao) solid_object.elVBO.bind() mv_matrix = np.dot(VMatrix, solid_object.transform) glUniformMatrix4fv(self.shader.get_uniform("mv_matrix"), 1, True, mv_matrix.astype('float32')) glUniformMatrix4fv(self.shader.get_uniform("p_matrix"), 1, True, PMatrix.astype('float32')) glDisable(GL_CULL_FACE) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) # glPolygonMode(GL_FRONT_AND_BACK, GL_LINE) glDrawElements(GL_TRIANGLES, solid_object.elCount, GL_UNSIGNED_INT, solid_object.elVBO) solid_object.elVBO.unbind() glBindVertexArray(0) glUseProgram(0)
def drawsphere_worker(params): """ Draw a sphere. Receive parameters through a sequence so that this function and its parameters can be passed to another function for deferment. Right now this is only ColorSorter.schedule (see below) """ (pos, radius, detailLevel, n) = params del n # KLUGE: the detailLevel can be a tuple, (vboLevel, detailLevel). # The only for reason for this is that drawsphere_worker is used # in ProteinChunks (I added a comment there saying why that's bad) # and I don't have time to clean that up now. Ideally, vboLevel # would just be another parameter, or we'd combine it with detailLevel # in some other way not constrained by backward compatibility of # this internal worker function's API. [bruce 090304] if type(detailLevel) == type(()): (vboLevel, detailLevel) = detailLevel ## vboLevel = drawing_globals.use_drawing_variant glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius,radius,radius) if vboLevel == 0: # OpenGL 1.0 - glBegin/glEnd tri-strips vertex-by-vertex. glCallList(drawing_globals.sphereList[detailLevel]) else: # OpenGL 1.1/1.5 - Array/VBO/IBO variants. glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) size = len(drawing_globals.sphereArrays[detailLevel]) GLIndexType = drawing_globals.sphereGLIndexTypes[detailLevel] if vboLevel == 1: # DrawArrays from CPU RAM. verts = drawing_globals.sphereCArrays[detailLevel] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) glDrawArrays(GL_TRIANGLE_STRIP, 0, size) elif vboLevel == 2: # DrawElements from CPU RAM. verts = drawing_globals.sphereCElements[detailLevel][1] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) elif vboLevel == 3: # DrawArrays from graphics RAM VBO. vbo = drawing_globals.sphereArrayVBOs[detailLevel] vbo.bind() glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) glDrawArrays(GL_TRIANGLE_STRIP, 0, vbo.size) vbo.unbind() elif vboLevel == 4: # DrawElements from index in CPU RAM, verts in VBO. vbo = drawing_globals.sphereElementVBOs[detailLevel][1] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) vbo.unbind() elif vboLevel == 5: # VBO/IBO buffered DrawElements from graphics RAM. (ibo, vbo) = drawing_globals.sphereElementVBOs[detailLevel] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) ibo.bind() # Index data comes from the ibo. glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, None) vbo.unbind() ibo.unbind() pass glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) pass glPopMatrix() return
def drawsphere_worker(params): """ Draw a sphere. Receive parameters through a sequence so that this function and its parameters can be passed to another function for deferment. Right now this is only ColorSorter.schedule (see below) """ (pos, radius, detailLevel) = params vboLevel = drawing_globals.use_drawing_variant glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius,radius,radius) if vboLevel == 0: glCallList(drawing_globals.sphereList[detailLevel]) else: # Array variants. glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) size = len(drawing_globals.sphereArrays[detailLevel]) GLIndexType = drawing_globals.sphereGLIndexTypes[detailLevel] if vboLevel == 1: # DrawArrays from CPU RAM. verts = drawing_globals.sphereCArrays[detailLevel] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) glDrawArrays(GL_TRIANGLE_STRIP, 0, size) elif vboLevel == 2: # DrawElements from CPU RAM. verts = drawing_globals.sphereCElements[detailLevel][1] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) elif vboLevel == 3: # DrawArrays from graphics RAM VBO. vbo = drawing_globals.sphereArrayVBOs[detailLevel] vbo.bind() glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) glDrawArrays(GL_TRIANGLE_STRIP, 0, vbo.size) vbo.unbind() elif vboLevel == 4: # DrawElements from index in CPU RAM, verts in VBO. vbo = drawing_globals.sphereElementVBOs[detailLevel][1] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) vbo.unbind() elif vboLevel == 5: # VBO/IBO buffered DrawElements from graphics RAM. (ibo, vbo) = drawing_globals.sphereElementVBOs[detailLevel] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) ibo.bind() # Index data comes from the ibo. glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, None) vbo.unbind() ibo.unbind() pass glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) pass glPopMatrix() return
def drawsphere_worker(params): """ Draw a sphere. Receive parameters through a sequence so that this function and its parameters can be passed to another function for deferment. Right now this is only ColorSorter.schedule (see below) """ (pos, radius, detailLevel, n) = params del n # KLUGE: the detailLevel can be a tuple, (vboLevel, detailLevel). # The only for reason for this is that drawsphere_worker is used # in ProteinChunks (I added a comment there saying why that's bad) # and I don't have time to clean that up now. Ideally, vboLevel # would just be another parameter, or we'd combine it with detailLevel # in some other way not constrained by backward compatibility of # this internal worker function's API. [bruce 090304] if type(detailLevel) == type(()): (vboLevel, detailLevel) = detailLevel ## vboLevel = drawing_globals.use_drawing_variant glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius, radius, radius) if vboLevel == 0: # OpenGL 1.0 - glBegin/glEnd tri-strips vertex-by-vertex. glCallList(drawing_globals.sphereList[detailLevel]) else: # OpenGL 1.1/1.5 - Array/VBO/IBO variants. glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) size = len(drawing_globals.sphereArrays[detailLevel]) GLIndexType = drawing_globals.sphereGLIndexTypes[detailLevel] if vboLevel == 1: # DrawArrays from CPU RAM. verts = drawing_globals.sphereCArrays[detailLevel] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) glDrawArrays(GL_TRIANGLE_STRIP, 0, size) elif vboLevel == 2: # DrawElements from CPU RAM. verts = drawing_globals.sphereCElements[detailLevel][1] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) elif vboLevel == 3: # DrawArrays from graphics RAM VBO. vbo = drawing_globals.sphereArrayVBOs[detailLevel] vbo.bind() glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) glDrawArrays(GL_TRIANGLE_STRIP, 0, vbo.size) vbo.unbind() elif vboLevel == 4: # DrawElements from index in CPU RAM, verts in VBO. vbo = drawing_globals.sphereElementVBOs[detailLevel][1] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) vbo.unbind() elif vboLevel == 5: # VBO/IBO buffered DrawElements from graphics RAM. (ibo, vbo) = drawing_globals.sphereElementVBOs[detailLevel] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) ibo.bind() # Index data comes from the ibo. glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, None) vbo.unbind() ibo.unbind() pass glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) pass glPopMatrix() return
def run(): #Start OpenGL and ask it for an OpenGL context pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode( SCREEN_SIZE, pygame.HWSURFACE | pygame.OPENGL | pygame.DOUBLEBUF) #The first thing we do is print some OpenGL details and check that we have a good enough version print("OpenGL Implementation Details:") if glGetString(GL_VENDOR): print("\tGL_VENDOR: {}".format(glGetString(GL_VENDOR).decode())) if glGetString(GL_RENDERER): print("\tGL_RENDERER: {}".format(glGetString(GL_RENDERER).decode())) if glGetString(GL_VERSION): print("\tGL_VERSION: {}".format(glGetString(GL_VERSION).decode())) if glGetString(GL_SHADING_LANGUAGE_VERSION): print("\tGL_SHADING_LANGUAGE_VERSION: {}".format( glGetString(GL_SHADING_LANGUAGE_VERSION).decode())) major_version = int( glGetString(GL_VERSION).decode().split()[0].split('.')[0]) minor_version = int( glGetString(GL_VERSION).decode().split()[0].split('.')[1]) if major_version < 3 or (major_version < 3 and minor_version < 0): print("OpenGL version must be at least 3.0 (found {0})".format( glGetString(GL_VERSION).decode().split()[0])) #Now onto the OpenGL initialisation #Set up depth culling glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) glDepthFunc(GL_LEQUAL) glDepthRange(0.0, 1.0) #We create out shaders which do little more than set a flat colour for each face VERTEX_SHADER = shaders.compileShader( b""" #version 130 in vec4 position; in vec4 normal; uniform mat4 projectionMatrix; uniform mat4 viewMatrix; uniform mat4 modelMatrix; flat out float theColor; void main() { vec4 temp = modelMatrix * position; temp = viewMatrix * temp; gl_Position = projectionMatrix * temp; theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1); } """, GL_VERTEX_SHADER) FRAGMENT_SHADER = shaders.compileShader( b""" #version 130 flat in float theColor; out vec4 outputColor; void main() { outputColor = vec4(1.0, 0.5, theColor, 1.0); } """, GL_FRAGMENT_SHADER) shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER) #And then grab our attribute locations from it glBindAttribLocation(shader, 0, b"position") glBindAttribLocation(shader, 1, b"normal") #Create the Vertex Array Object to hold our volume mesh vertexArrayObject = GLuint(0) glGenVertexArrays(1, vertexArrayObject) glBindVertexArray(vertexArrayObject) #Create the index buffer object indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER, usage=GL_STATIC_DRAW) #Create the VBO vertexPositions = vbo.VBO(vertices, usage=GL_STATIC_DRAW) #Bind our VBOs and set up our data layout specifications with indexPositions, vertexPositions: glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, False, 6 * vertices.dtype.itemsize, vertexPositions + (0 * vertices.dtype.itemsize)) glEnableVertexAttribArray(1) glVertexAttribPointer(1, 3, GL_FLOAT, False, 6 * vertices.dtype.itemsize, vertexPositions + (3 * vertices.dtype.itemsize)) glBindVertexArray(0) glDisableVertexAttribArray(0) #Now grab out transformation martix locations modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix") viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix") projectionMatrixUnif = glGetUniformLocation(shader, b"projectionMatrix") modelMatrix = np.array([[1.0, 0.0, 0.0, -32.0], [0.0, 1.0, 0.0, -32.0], [0.0, 0.0, 1.0, -32.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') viewMatrix = np.array([[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, -50.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') projectionMatrix = np.array([[0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0]], dtype='f') #These next few lines just set up our camera frustum fovDeg = 45.0 frustumScale = 1.0 / tan(radians(fovDeg) / 2.0) zNear = 1.0 zFar = 1000.0 projectionMatrix[0][0] = frustumScale projectionMatrix[1][1] = frustumScale projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar) projectionMatrix[2][3] = -1.0 projectionMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) #viewMatrix and projectionMatrix don't change ever so just set them once here with shader: glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix) glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix) #These are used to track the rotation of the volume LastFrameMousePos = (0, 0) CurrentMousePos = (0, 0) xRotation = 0 yRotation = 0 while True: clock.tick() for event in pygame.event.get(): if event.type == pygame.QUIT: return if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: return if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: CurrentMousePos = event.pos LastFrameMousePos = CurrentMousePos if event.type == pygame.MOUSEMOTION and 1 in event.buttons: CurrentMousePos = event.pos diff = (CurrentMousePos[0] - LastFrameMousePos[0], CurrentMousePos[1] - LastFrameMousePos[1]) xRotation += event.rel[0] yRotation += event.rel[1] LastFrameMousePos = CurrentMousePos glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #Perform the rotation of the mesh moveToOrigin = np.array( [[1.0, 0.0, 0.0, -32.0], [0.0, 1.0, 0.0, -32.0], [0.0, 0.0, 1.0, -32.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') rotateAroundX = np.array( [[1.0, 0.0, 0.0, 0.0], [0.0, cos(radians(yRotation)), -sin(radians(yRotation)), 0.0], [0.0, sin(radians(yRotation)), cos(radians(yRotation)), 0.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') rotateAroundY = np.array( [[cos(radians(xRotation)), 0.0, sin(radians(xRotation)), 0.0], [0.0, 1.0, 0.0, 0.0], [-sin(radians(xRotation)), 0.0, cos(radians(xRotation)), 0.0], [0.0, 0.0, 0.0, 1.0]], dtype='f') modelMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) with shader: glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix) glBindVertexArray(vertexArrayObject) glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None) glBindVertexArray(0) # Show the screen pygame.display.flip()
def render(self, mode=GL_TRIANGLES): ''' at once ''' glDrawElements(mode, self.nElement, GL_UNSIGNED_INT, c_void_p(0))
def drawsphere_worker(params): """ Draw a sphere. Receive parameters through a sequence so that this function and its parameters can be passed to another function for deferment. Right now this is only ColorSorter.schedule (see below) """ (pos, radius, detailLevel) = params vboLevel = drawing_globals.use_drawing_variant glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius, radius, radius) if vboLevel == 0: glCallList(drawing_globals.sphereList[detailLevel]) else: # Array variants. glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_NORMAL_ARRAY) size = len(drawing_globals.sphereArrays[detailLevel]) GLIndexType = drawing_globals.sphereGLIndexTypes[detailLevel] if vboLevel == 1: # DrawArrays from CPU RAM. verts = drawing_globals.sphereCArrays[detailLevel] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) glDrawArrays(GL_TRIANGLE_STRIP, 0, size) elif vboLevel == 2: # DrawElements from CPU RAM. verts = drawing_globals.sphereCElements[detailLevel][1] glVertexPointer(3, GL_FLOAT, 0, verts) glNormalPointer(GL_FLOAT, 0, verts) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) elif vboLevel == 3: # DrawArrays from graphics RAM VBO. vbo = drawing_globals.sphereArrayVBOs[detailLevel] vbo.bind() glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) glDrawArrays(GL_TRIANGLE_STRIP, 0, vbo.size) vbo.unbind() elif vboLevel == 4: # DrawElements from index in CPU RAM, verts in VBO. vbo = drawing_globals.sphereElementVBOs[detailLevel][1] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) # Can't use the C index in sphereCElements yet, fatal PyOpenGL bug. index = drawing_globals.sphereElements[detailLevel][0] glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, index) vbo.unbind() elif vboLevel == 5: # VBO/IBO buffered DrawElements from graphics RAM. (ibo, vbo) = drawing_globals.sphereElementVBOs[detailLevel] vbo.bind() # Vertex and normal data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) glNormalPointer(GL_FLOAT, 0, None) ibo.bind() # Index data comes from the ibo. glDrawElements(GL_TRIANGLE_STRIP, size, GLIndexType, None) vbo.unbind() ibo.unbind() pass glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) pass glPopMatrix() return
def test_drawing(glpane, initOnly=False): """ When TEST_DRAWING is enabled at the start of graphics/widgets/GLPane_rendering_methods.py, and when TestGraphics_Command is run (see its documentation for various ways to do that), this file is loaded and GLPane.paintGL() calls the test_drawing() function instead of the usual body of paintGL(). """ # WARNING: this duplicates some code with test_Draw_model(). # Load the sphere shaders if needed. global _USE_SHADERS if _USE_SHADERS: if not drawing_globals.test_sphereShader: print "test_drawing: Loading sphere shaders." try: from graphics.drawing.gl_shaders import GLSphereShaderObject drawing_globals.test_sphereShader = GLSphereShaderObject() ##### REVIEW: is this compatible with my refactoring in drawing_globals? # If not, use of Test Graphics Performance command might cause subsequent # bugs in other code. Ideally we'd call the new methods that encapsulate # this, to setup shaders. [bruce 090304 comment] print "test_drawing: Sphere-shader initialization is complete.\n" except: _USE_SHADERS = False print "test_drawing: Exception while loading sphere shaders, will reraise and not try again" raise pass global start_pos, first_time if first_time: # Set up the viewing scale, but then let interactive zooming work. glpane.scale = nSpheres * .6 pass # This same function gets called to set up for drawing, and to draw. if not initOnly: glpane._setup_modelview() glpane._setup_projection() ##glpane._compute_frustum_planes() glClearColor(64.0, 64.0, 64.0, 1.0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) ##glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) glMatrixMode(GL_MODELVIEW) pass global test_csdl, test_dl, test_dls, test_ibo, test_vbo, test_spheres global test_DrawingSet, test_endpoints, test_Object # See below for test case descriptions and timings on a MacBook Pro. # The Qt event toploop in NE1 tops out at about 60 frames-per-second. # NE1 with test toploop, single CSDL per draw (test case 1) # . 17,424 spheres (132x132, through the color sorter) 4.8 FPS # Russ 080919: More recently, 12.2 FPS. # . Level 2 spheres have 9 triangles x 20 faces, 162 distinct vertices, # visited on the average 2.3 times, giving 384 tri-strip vertices. # . 17,424 spheres is 6.7 million tri-strip vertices. (6,690,816) if testCase == 1: if test_csdl is None: print("Test case 1, %d^2 spheres\n %s." % (nSpheres, "ColorSorter")) test_csdl = ColorSortedDisplayList() ColorSorter.start(None, test_csdl) drawsphere( [0.5, 0.5, 0.5], # color [0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, testloop=nSpheres) ColorSorter.finish(draw_now=True) pass else: test_csdl.draw() pass # NE1 with test toploop, single display list per draw (test case 2) # . 10,000 spheres (all drawing modes) 17.5 FPS # . 17,424 spheres (132x132, manual display list) 11.1 FPS # . 40,000 spheres (mode 5 - VBO/IBO spheres from DL's) 2.2 FPS # . 40,000 spheres (mode 6 - Sphere shaders from DL's) 2.5 FPS # . 90,000 spheres (all drawing modes) 1.1 FPS elif testCase == 2: if test_dl is None: print("Test case 2, %d^2 spheres\n %s." % (nSpheres, "One display list calling primitive dl's")) test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) drawsphere_worker_loop(( [0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, nSpheres)) glEndList() pass else: glColor3i(127, 127, 127) glCallList(test_dl) pass # NE1 with test toploop, one big chunk VBO/IBO of box quads (test case 3) # . 17,424 spheres (1 box/shader draw call) 43.7 FPS # . 17,424 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 57.7 FPS # . 40,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 56.7 FPS # . 90,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 52.7 FPS # . 160,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 41.4 FPS # . 250,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 27.0 FPS elif int(testCase) == 3: doTransforms = False if test_spheres is None: print("Test case 3, %d^2 spheres\n %s." % (nSpheres, "One big VBO/IBO chunk buffer")) if testCase == 3.1: print("Sub-test 3.1, animate partial updates.") elif testCase == 3.2: print("Sub-test 3.2, animate partial updates" + " w/ C per-chunk array buffering.") elif testCase == 3.3: print("Sub-test 3.3, animate partial updates" + " w/ Python array buffering.") # . 3.4 - Big batch draw, with transforms indexed by IDs added. # (Second FPS number with debug colors in the vertex shader off.) # - 90,000 (300x300) spheres, TEXTURE_XFORMS = True, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 250, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 275, 0.3(0.6) FPS # (What happens after 250? CPU usage goes from 40% to 94%.) # -160,000 (400x400) spheres, TEXTURE_XFORMS = True, 26 FPS # -250,000 (500x500) spheres, TEXTURE_XFORMS = True, 26 FPS elif testCase == 3.4: print("Sub-test 3.4, add transforms indexed by IDs.") from graphics.drawing.gl_shaders import TEXTURE_XFORMS from graphics.drawing.gl_shaders import N_CONST_XFORMS from graphics.drawing.gl_shaders import UNIFORM_XFORMS if TEXTURE_XFORMS: print "Transforms in texture memory." elif UNIFORM_XFORMS: print "%d transforms in uniform memory." % N_CONST_XFORMS pass else: print "transforms not supported, error is likely" doTransforms = True pass centers = [] radius = .5 radii = [] colors = [] if not doTransforms: transformIDs = None else: transformIDs = [] transformChunkID = -1 # Allocate IDs sequentially from 0. # For this test, allow arbitrarily chunking the primitives. primCounter = transformChunkLength transforms = [] # Accumulate transforms as a list of lists. # Initialize transforms with an identity matrix. # Transforms here are lists (or Numpy arrays) of 16 numbers. identity = ([1.0] + 4 * [0.0]) * 3 + [1.0] pass for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.75 + t * .25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Transforms go into a texture memory image if needed. # Per-primitive Transform IDs go into an attribute VBO. if doTransforms: primCounter = primCounter + 1 if primCounter >= transformChunkLength: # Start a new chunk, allocating a transform matrix. primCounter = 0 transformChunkID += 1 if 0: # 1 # Debug hack: Label mat[0,0] with the chunk ID. # Vertex shader debug code shows these in blue. # If viewed as geometry, it will be a slight # stretch of the array in the X direction. transforms += [ [1.0 + transformChunkID / 100.0] + identity[1:] ] elif 0: # 1 # Debug hack: Fill mat with mat.element pattern. transforms += [[ transformChunkID + i / 100.0 for i in range(16) ]] else: transforms += [identity] pass pass # All of the primitives in a chunk have the same ID. transformIDs += [transformChunkID] pass continue continue test_spheres = GLSphereBuffer() test_spheres.addSpheres(centers, radii, colors, transformIDs, None) if doTransforms: print("%d primitives in %d transform chunks of size <= %d" % (nSpheres * nSpheres, len(transforms), transformChunkLength)) shader = drawing_globals.test_sphereShader shader.setupTransforms(transforms) pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Update portions for animation. pulse = time.time() pulse -= floor(pulse) # 0 to 1 in each second # Test animating updates on 80% of the radii in 45% of the columns. # . 3.1 - Update radii Python array per-column, send to graphics RAM. # - 2,500 (50x50) spheres 55 FPS # - 10,000 (100x100) spheres 35 FPS # - 17,424 (132x132) spheres 22.2 FPS # - 40,000 (200x200) spheres 12.4 FPS # - 90,000 (300x300) spheres 6.0 FPS if testCase == 3.1: # Not buffered, send each column change. radius = .5 margin = nSpheres / 10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres - margin): t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t * .25) phase = pulse + float(x + y) / nSpheres radii += 8 * [thisRad - .1 + .1 * sin(phase * 2 * pi)] continue C_radii = numpy.array(radii, dtype=numpy.float32) offset = x * nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_radii) continue pass # . 3.2 - Numpy buffered in C array, subscript assignments to C. # - 2,500 (50x50) spheres 48 FPS # - 10,000 (100x100) spheres 17.4 FPS # - 17,424 (132x132) spheres 11.2 FPS # - 40,000 (200x200) spheres 5.5 FPS # - 90,000 (300x300) spheres 2.5 FPS elif testCase == 3.2: # Buffered per-chunk at the C array level. radius = .5 margin = nSpheres / 10 global C_array if C_array is None: # Replicate. C_array = numpy.zeros((8 * (nSpheres - (2 * margin)), ), dtype=numpy.float32) pass for x in range(margin, nSpheres, 2): count = 0 for y in range(margin, nSpheres - margin): t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t * .25) phase = pulse + float(x + y) / nSpheres C_array[count*8:(count+1)*8] = \ thisRad-.1 + .1*sin(phase * 2*pi) count += 1 continue offset = x * nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_array) continue pass # . 3.3 - updateRadii in Python array, copy via C to graphics RAM. # - 2,500 (50x50) spheres 57 FPS # - 10,000 (100x100) spheres 32 FPS # - 17,424 (132x132) spheres 20 FPS # - 40,000 (200x200) spheres 10.6 FPS # - 90,000 (300x300) spheres 4.9 FPS elif testCase == 3.3: # Buffered at the Python level, batch the whole-array update. radius = .5 margin = nSpheres / 10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres - margin): t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t * .25) phase = pulse + float(x + y) / nSpheres radii += [thisRad - .1 + .1 * sin(phase * 2 * pi)] continue test_spheres.updateRadii( # Update, but don't send yet. x * nSpheres + margin, radii, send=False) continue test_spheres.sendRadii() pass # Options: color = [0.0, 1.0, 0.0], transform_id = 1, radius = 1.0 test_spheres.draw() pass # NE1 with test toploop, separate sphere VBO/IBO box/shader draws (test case 4) # . 17,424 spheres (132x132 box/shader draw quads calls) 0.7 FPS elif testCase == 4: if test_ibo is None: print("Test case 4, %d^2 spheres\n %s." % (nSpheres, "Separate VBO/IBO shader/box buffer sphere calls, no DL")) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() pass else: drawing_globals.test_sphereShader.configShader(glpane) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius, radius, radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) pass # NE1 with test toploop, # One DL around separate VBO/IBO shader/box buffer sphere calls (test case 5) # . 17,424 spheres (1 box/shader DL draw call) 9.2 FPS elif testCase == 5: if test_dl is None: print("Test case 5, %d^2 spheres\n %s." % ( nSpheres, "One DL around separate VBO/IBO shader/box buffer sphere calls" )) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject(GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject(GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() # Wrap a display list around the draws. test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius, radius, radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) glEndList() else: glColor3i(127, 127, 127) glCallList(test_dl) pass pass # NE1 with test toploop, # N column DL's around VBO/IBO shader/box buffer sphere calls (test case 6) # . 2,500 (50x50) spheres 58 FPS # . 10,000 (100x100) spheres 57 FPS # . 17,424 (132x132) spheres 56 FPS # . 40,000 (200x200) spheres 50 FPS # . 90,000 (300x300) spheres 28 FPS # . 160,000 (400x400) spheres 16.5 FPS # . 250,000 (500x500) spheres 3.2 FPS elif testCase == 6: if test_dls is None: print("Test case 6, %d^2 spheres\n %s." % (nSpheres, "N col DL's around VBO/IBO shader/box buffer sphere calls")) # Wrap n display lists around the draws (one per column.) test_dls = glGenLists( nSpheres) # Returns ID of first DL in the set. test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] # Each column is relative to its bottom sphere location. Start # at the lower-left corner, offset so the whole pattern comes up # centered on the origin. start_pos = V(0, 0, 0) # So it doesn't get subtracted twice. pos = sphereLoc(x, 0) - V(nSpheres / 2.0, nSpheres / 2.0, 0) for y in range(nSpheres): centers += [sphereLoc(0, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.75 + t * .25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue test_sphere = GLSphereBuffer() test_sphere.addSpheres(centers, radii, colors, None, None) test_spheres += [test_sphere] glNewList(test_dls + x, GL_COMPILE_AND_EXECUTE) glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) test_sphere.draw() glPopMatrix() glEndList() continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Turn the lights on. for x in range(nSpheres): glCallList(test_dls + x) continue pass pass # NE1 with test toploop, # N column VBO sets of shader/box buffer sphere calls (test case 7) # . 2,500 (50x50) spheres 50 FPS # . 10,000 (100x100) spheres 30.5 FPS # . 17,424 (132x132) spheres 23.5 FPS # . 40,000 (200x200) spheres 16.8 FPS # . 90,000 (300x300) spheres 10.8 FPS # . 160,000 (400x400) spheres 9.1 FPS # . 250,000 (500x500) spheres 7.3 FPS elif testCase == 7: if test_spheres is None: print("Test case 7, %d^2 spheres\n %s." % (nSpheres, "Per-column VBO/IBO chunk buffers")) test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.75 + t * .25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue _spheres1 = GLSphereBuffer() _spheres1.addSpheres(centers, radii, colors, None, None) test_spheres += [_spheres1] continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) for chunk in test_spheres: chunk.draw() pass # NE1 with test toploop, # Short chunk VBO sets of shader/box buffer sphere calls (test case 8) # . 625 (25x25) spheres 30 FPS, 79 chunk buffers of length 8. # . 2,500 (50x50) spheres 13.6 FPS, 313 chunk buffers of length 8. # . 10,000 (100x100) spheres 6.4 FPS, 704 chunk buffers of length 8. # . 10,000 (100x100) spheres 3.3 FPS, 1250 chunk buffers of length 8. # . 17,424 (132x132) spheres 2.1 FPS, 2178 chunk buffers of length 8. # . 2,500 (50x50) spheres 33.5 FPS, 105 chunk buffers of length 24. # . 17,424 (132x132) spheres 5.5 FPS, 726 chunk buffers of length 24. # # Subcase 8.1: CSDLs in a DrawingSet. (Initial pass-through version.) # . 2,500 (50x50) spheres 36.5 FPS, 105 chunk buffers of length 24. # . 5,625 (75x75) spheres 16.1 FPS, 235 chunk buffers of length 24. # . 10,000 (100x100) spheres 0.5 FPS?!, 414 chunk buffers of length 24. # Has to be <= 250 chunks for constant memory transforms? # . 10,000 (100x100) spheres 11.8 FPS, 50 chunk buffers of length 200. # After a minute of startup. # . 10,000 (100x100) spheres 9.3 FPS, 200 chunk buffers of length 50. # After a few minutes of startup. # Subcase 8.2: CSDLs in a DrawingSet with transforms. (Pass-through.) # . 10,000 (100x100) spheres 11.5 FPS, 50 chunk buffers of length 200. # # Subcase 8.1: CSDLs in a DrawingSet. (First HunkBuffer version.) # Measured with auto-rotate on, ignoring startup and occasional outliers. # As before, on a 2 core, 2.4 GHz Intel MacBook Pro with GeForce 8600M GT. # HUNK_SIZE = 10000 # . 2,500 (50x50) spheres 140-200 FPS, 105 chunks of length 24. # . 5,625 (75x75) spheres 155-175 FPS, 235 chunks of length 24. # . 10,000 (100x100) spheres 134-145 FPS, 50 chunks of length 200. # . 10,000 (100x100) spheres 130-143 FPS, 200 chunks of length 50. # . 10,000 (100x100) spheres 131-140 FPS, 1,250 chunks of length 8. # Chunks are gathered into hunk buffers, so no chunk size speed diff. # . 17,424 (132x132) spheres 134-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 131-140 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 20000 # . 17,424 (132x132) spheres 131-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 130-141 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 10000 # . 40,000 (200x200) spheres 77.5-82.8 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 34.9-42.6 FPS, 11,2500 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # Rotate the sphere-array off-axis 45 degrees to minimize. # (Try adding multi-sampled anti-aliasing, to the drawing test...) # . 160,000 (400x400) spheres 26.4-27.1 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.8-17.1 FPS, 31,250 chunks of length 8. # The pattern is getting too large, far-clipping is setting in. # . 360,000 (600x600) spheres 11.6-11.8 FPS, 45,000 chunks of length 8. # Extreme far-clipping in the drawing test pattern. # HUNK_SIZE = 20000; no significant speed-up. # . 40,000 (200x200) spheres 75.9-81.5 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 41.2-42.4 FPS, 11,250 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # . 160,000 (400x400) spheres 26.5-26.9 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.5-17.1 FPS, 31,250 chunks of length 8. # . 360,000 (600x600) spheres 11.8-12.1 FPS, 45,000 chunks of length 8. # HUNK_SIZE = 5000; no significant slowdown or CPU load difference. # . 40,000 (200x200) spheres 81.0-83.8 FPS, 5,000 chunks of length 8. # . 160,000 (400x400) spheres 27.3-29.4 FPS, 20,000 chunks of length 8. # . 360,000 (600x600) spheres 11.7-12.1 FPS, 45,000 chunks of length 8. # # Retest after updating MacOS to 10.5.5, with TestGraphics, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 68.7-74.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 39.4-42.0 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 24.4-25.2 FPS, 20,000 chunks of length 8. # Retest with glMultiDrawElements drawing indexes in use, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 52.8-54.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 22.8-23.3 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 13.5-15.2 FPS, 20,000 chunks of length 8. # # Retest with reworked halo/sphere shader, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 52.8-53.7 FPS, 2,178 chunks of length 8. [60] # . 40,000 (200x200) spheres 29.3-30.4 FPS, 5,000 chunks of length 8.[156] # . 90,000 (300x300) spheres 18.2-19.2 FPS, 11,250 chunks of length 8.[381] # . 160,000 (400x400) spheres 10.2-11.6 FPS, 20,000 chunks of length 8.[747] # Billboard drawing patterns instead of cubes, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 49.7-55.7 FPS, 2,178 chunks of length 8. [35] # . 40,000 (200x200) spheres 39.6-40.8 FPS, 5,000 chunks of length 8. [88] # . 90,000 (300x300) spheres 18.9-19.5 FPS, 11,250 chunks of length 8.[225] # . 160,000 (400x400) spheres 11.2-11.7 FPS, 20,000 chunks of length 8.[476] # elif int(testCase) == 8: doTransforms = False doCylinders = False if test_spheres is None: # Setup. print("Test case 8, %d^2 primitives\n %s, length %d." % (nSpheres, "Short VBO/IBO chunk buffers", chunkLength)) if testCase == 8.1: print( "Sub-test 8.1, sphere chunks are in CSDL's in a DrawingSet." ) test_DrawingSet = DrawingSet() elif testCase == 8.2: print("Sub-test 8.2, spheres, rotate with TransformControls.") test_DrawingSet = DrawingSet() doTransforms = True elif testCase == 8.3: print( "Sub-test 8.3, cylinder chunks are in CSDL's in a DrawingSet." ) test_DrawingSet = DrawingSet() doCylinders = True pass if test_DrawingSet: # note: doesn't happen in test 8.0, which causes a bug then. [bruce 090223 comment] print "constructed test_DrawingSet =", test_DrawingSet if USE_GRAPHICSMODE_DRAW: print("Use graphicsMode.Draw_model for DrawingSet in paintGL.") pass t1 = time.time() if doTransforms: # Provide several TransformControls to test separate action. global numTCs, TCs numTCs = 3 TCs = [TransformControl() for i in range(numTCs)] pass def primCSDL(centers, radii, colors): if not doTransforms: csdl = ColorSortedDisplayList() # Transformless. else: # Test pattern for TransformControl usage - vertical columns # of TC domains, separated by X coord of first center point. # Chunking will be visible when transforms are changed. xCoord = centers[0][0] - start_pos[ 0] # Negate centering X. xPercent = ( xCoord / (nSpheres + nSpheres / 10 + nSpheres / 100 - 1 + (nSpheres <= 1))) xTenth = int(xPercent * 10 + .5) csdl = ColorSortedDisplayList(TCs[xTenth % numTCs]) pass # Test selection using the CSDL glname. ColorSorter.pushName(csdl.glname) ColorSorter.start(glpane, csdl) for (color, center, radius) in zip(colors, centers, radii): if not doCylinders: # Through ColorSorter to the sphere primitive buffer... drawsphere(color, center, radius, DRAWSPHERE_DETAIL_LEVEL) else: # Through ColorSorter to cylinder primitive buffer... if not drawing_globals.cylinderShader_available(): print "warning: not cylinderShader_available(), error is likely:" if (True and # Whether to do tapered shader-cylinders. # Display List cylinders don't support taper. glpane.glprefs.cylinderShader_desired()): ###cylRad = (radius/2.0, (.75-radius)/2.0) cylRad = (radius / 1.5 - .167, .3 - radius / 1.5) else: cylRad = radius / 2.0 pass endPt2 = center + V(0.5, 0.0, 0.0) # 0.5, -0.5) drawcylinder(color, center, endPt2, cylRad) global test_endpoints test_endpoints += [(center, endPt2)] pass continue ColorSorter.popName() ColorSorter.finish(draw_now=True) test_DrawingSet.addCSDL(csdl) return csdl if testCase == 8: #bruce 090223 revised to try to avoid traceback def chunkFn(centers, radii, colors): res = GLSphereBuffer() res.addSpheres(centers, radii, colors, None, None) return res pass else: chunkFn = primCSDL pass test_spheres = [] radius = .5 centers = [] radii = [] colors = [] global test_endpoints test_endpoints = [] for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x + y) / (nSpheres + nSpheres ) # 0 to 1 fraction. thisRad = radius * (.5 + t * .5) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Put out short chunk buffers. if len(centers) >= chunkLength: test_spheres += [chunkFn(centers, radii, colors)] centers = [] radii = [] colors = [] continue continue # Remainder fraction buffer. if len(centers): test_spheres += [chunkFn(centers, radii, colors)] pass print "Setup time", time.time() - t1, "seconds." print "%d chunk buffers" % len(test_spheres) pass elif not initOnly: # Run. test_Draw_8x(glpane) pass elif testCase == 100: #bruce 090102 # before making more of these, modularize it somehow from commands.TestGraphics.test_selection_redraw import test_selection_redraw test_class = test_selection_redraw params = (nSpheres, ) # note: test size is not directly comparable to other tests with same value of nSpheres if test_Object is None \ or not isinstance(test_Object, test_class) \ or test_Object.current_params() != params: # review: same_vals? # Setup. if test_Object: test_Object.destroy() test_Object = test_class(*params) test_Object.activate() print test_Object pass # review: safe to change elif to if? not sure, GL state is only initialized below elif not initOnly: # Run. test_Object.draw_complete() pass pass if not initOnly: glMatrixMode(GL_MODELVIEW) glFlush() pass first_time = False return
def main(): global width global height global camera width = 1024 height = 1024 delta_time = 0.0 last_frame = 0.0 if not glfw.init(): return glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3) glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3) glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE) glfw.window_hint(glfw.RESIZABLE, GL_FALSE) window = glfw.create_window(width, height, "opengl_lab1", None, None) glfw.set_key_callback(window, key_callback) glfw.set_cursor_pos_callback(window, mousemove_callback) glfw.set_mouse_button_callback(window, mouseclick_callback) if not window: glfw.terminate() return glfw.make_context_current(window) fun1 = lambda x, z: math.sin(x+z) fun2 = lambda x, z: math.exp(-x*x - z*z) fun3 = lambda x, z: (x**2 + z**2) / (x*z) contour_plot = lambda x, z: 0.0 heightmap_dummy_fun = lambda x, z: 0.0 surface_size = 50 (fun_vao1, ind_fun1) = create_surface(100, 100, surface_size, fun1, False) (fun_vao2, ind_fun2) = create_surface(100, 100, surface_size, fun2, False) (fun_vao3, ind_fun3) = create_surface(100, 100, surface_size, fun3, False) (grad_vao, grad_point_count) = create_grad(100, 100, surface_size) (contour_plot_vao, ind_con, vec_lines, vector_line_indexes) = create_surface(100, 100, surface_size, 0, False, True) (heightmap_vao, ind_hm) = create_surface(100,100, surface_size, heightmap_dummy_fun, True) (sphere_vao, sphere_ind, normals_for_glyph) = uv_sphere(22, 11) (torus_vao, torus_ind) = uv_torus(5, 10, 100, 100) (cm_vao, ind_cm) = create_surface(100, 100, surface_size, heightmap_dummy_fun, True) (cloud_vao, points_count) = read_ply() (perlin_vao, ind_perlin) = create_surface(100, 100, surface_size, heightmap_dummy_fun, False) (div_vao, ind_div) = create_surface(100, 100, surface_size, heightmap_dummy_fun, False) (traj_vao, ind_traj) = simple_cube() fun_shader_sources = [(GL_VERTEX_SHADER, "shaders/functions.vert"), (GL_FRAGMENT_SHADER, "shaders/functions.frag")] fun_program = ShaderProgram(fun_shader_sources) hm_shader_sources = [(GL_VERTEX_SHADER, "shaders/heightmap.vert"), (GL_FRAGMENT_SHADER, "shaders/heightmap.frag")] hm_program = ShaderProgram(hm_shader_sources) hm_texture = read_texture("1.jpg") contour_plot_shader_sources = [(GL_VERTEX_SHADER, "shaders/contourplot.vert"), (GL_FRAGMENT_SHADER, "shaders/contourplot.frag")] contour_plot_program = ShaderProgram(contour_plot_shader_sources) sphere_shader_sources = [(GL_VERTEX_SHADER, "shaders/sphere.vert"), (GL_FRAGMENT_SHADER, "shaders/sphere.frag")] sphere_program = ShaderProgram(sphere_shader_sources) glyph_shader_sources = [(GL_VERTEX_SHADER, "shaders/glyph.vert"), (GL_GEOMETRY_SHADER, "shaders/glyph.geom"), (GL_FRAGMENT_SHADER, "shaders/glyph.frag")] glyph_program = ShaderProgram(glyph_shader_sources) grad_shader_sources = [(GL_VERTEX_SHADER, "shaders/grad.vert"), (GL_GEOMETRY_SHADER, "shaders/grad.geom"), (GL_FRAGMENT_SHADER, "shaders/grad.frag")] grad_program = ShaderProgram(grad_shader_sources) cm_shader_sources = [(GL_VERTEX_SHADER, "shaders/colormap.vert"), (GL_FRAGMENT_SHADER, "shaders/colormap.frag")] cm_program = ShaderProgram( cm_shader_sources ) perlin_shader_sources = [(GL_VERTEX_SHADER, "shaders/perlin.vert"), (GL_FRAGMENT_SHADER, "shaders/perlin.frag")] perlin_program = ShaderProgram(perlin_shader_sources) cloud_shader_sources = [(GL_VERTEX_SHADER, "shaders/ply.vert"), (GL_FRAGMENT_SHADER, "shaders/ply.frag")] cloud_program = ShaderProgram(cloud_shader_sources) vf_shader_sources = [(GL_VERTEX_SHADER, "shaders/vector_field.vert"), (GL_FRAGMENT_SHADER, "shaders/vector_field.frag")] vf_program = ShaderProgram(vf_shader_sources) traj_shader_sources = [(GL_VERTEX_SHADER, "shaders/trajectory.vert"), (GL_FRAGMENT_SHADER, "shaders/trajectory.frag")] traj_program = ShaderProgram(traj_shader_sources) check_gl_errors() projection = projectionMatrixTransposed(60.0, float(width) / float(height), 1, 1000.0) HDR_TEXTURES_AMOUNT = 33 cm_textures = read_cm_textures(HDR_TEXTURES_AMOUNT) cm_texture_num = 0 cm_change_counter = 0 hdr_textures_speed = 6 perlin_time = 0.0 perlin_time_step = 0.03 cube_multiplier = 1.0 cube_center = [0.0, 0.0, 0.0] traj_points_list = [ cube_center ] cube_edge_length = 2.0 * cube_multiplier offset = cube_edge_length / 10 left_cube_pos = -25 * cube_edge_length cube_steps = -left_cube_pos / offset - 10 traj_points_count = int(cube_steps) for i in range(traj_points_count): traj_points_list.append( [0.5*cube_edge_length * i, 0.0, 0.0] ) traj_part_index = 0 while not glfw.window_should_close(window): current_frame = glfw.get_time() delta_time = current_frame - last_frame last_frame = current_frame glfw.poll_events() doCameraMovement(camera, delta_time) model = translateM4x4(np.array([0.0, 0.0, 0.0])) view = camera.get_view_matrix() glClearColor(0.5, 0.5, 0.5, 1.0) glViewport(0, 0, width, height) glEnable(GL_DEPTH_TEST) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) fun_program.bindProgram() glUniform3fv(fun_program.uniformLocation("col"), 1 , [1.0, 0, 0] ) glUniformMatrix4fv(fun_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(fun_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(fun_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(fun_vao1) glDrawElements(GL_TRIANGLE_STRIP, ind_fun1, GL_UNSIGNED_INT, None) model = translateM4x4(np.array([-1.5*surface_size,0.0 ,0.0 ])) glUniform3fv(fun_program.uniformLocation("col"), 1, [0.0, 1.0, 0]) glUniformMatrix4fv(fun_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glBindVertexArray(fun_vao2) glDrawElements(GL_TRIANGLE_STRIP, ind_fun2, GL_UNSIGNED_INT, None) model = translateM4x4(np.array([1.5 * surface_size, 0.0, 0.0])) glUniform3fv(fun_program.uniformLocation("col"), 1, [0.0, 0.0, 1.0]) glUniformMatrix4fv(fun_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glBindVertexArray(fun_vao3) glDrawElements(GL_TRIANGLE_STRIP, ind_fun3, GL_UNSIGNED_INT, None) cloud_program.bindProgram() translate_cloud = translateM4x4(np.array([-2.5*surface_size,0.0 ,0.0 ])) # rotate_cloud = rotateYM4x4(math.radians(180)) model = translate_cloud # glUniform3fv(fun_program.uniformLocation("col"), 1, [0.0, 1.0, 0]) glUniformMatrix4fv(cloud_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(cloud_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(cloud_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(cloud_vao) glDrawArrays(GL_POINTS, 0, points_count) sphere_program.bindProgram() sph_scale = scaleM4x4(np.array([sphere_radius, sphere_radius, sphere_radius])) sph_translate = translateM4x4(np.array([0.0, 0.0, 2.0 * surface_size])) glUniformMatrix4fv(sphere_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(sph_translate + sph_scale).flatten()) glUniformMatrix4fv(sphere_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(sphere_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(sphere_vao) glDrawElements(GL_TRIANGLES, sphere_ind, GL_UNSIGNED_INT, None) torus_translate = translateM4x4(np.array([0.0, 0.0, 3.0 * surface_size])) glUniformMatrix4fv(sphere_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(torus_translate + sph_scale).flatten()) glBindVertexArray(torus_vao) glDrawElements(GL_TRIANGLES, torus_ind, GL_UNSIGNED_INT, None) glyph_program.bindProgram() sph_scale = scaleM4x4(np.array([sphere_radius, sphere_radius, sphere_radius])) sph_translate = translateM4x4(np.array([0.0, 0.0, 2.0 * surface_size])) glUniformMatrix4fv(glyph_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(sph_translate + sph_scale).flatten()) glUniformMatrix4fv(glyph_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(glyph_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) vao = glGenVertexArrays(1) glBindVertexArray(vao) vbo = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, vbo) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(normals_for_glyph), normals_for_glyph.flatten(), GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(0) glDrawArrays(GL_POINTS, 0, 10000) glBindVertexArray(0) contour_plot_program.bindProgram() model = translateM4x4(np.array([-1.5 * surface_size, 0.0, -1.5 * surface_size])) glUniformMatrix4fv(contour_plot_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(contour_plot_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(contour_plot_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(contour_plot_vao) glDrawElements(GL_TRIANGLE_STRIP, ind_con, GL_UNSIGNED_INT, None) fun_program.bindProgram() lines_vao = glGenVertexArrays(1) glBindVertexArray(lines_vao) vbo_lines = glGenBuffers(1) vbo_indices = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, vbo_lines) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(vec_lines), vec_lines.flatten(), GL_STATIC_DRAW) # glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_indices) glBufferData(GL_ELEMENT_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(vector_line_indexes), vector_line_indexes.flatten(), GL_STATIC_DRAW) glUniformMatrix4fv(fun_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(fun_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(fun_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(lines_vao) glDrawElements(GL_LINES, vector_line_indexes.size, GL_UNSIGNED_INT, None) hm_program.bindProgram() model = translateM4x4(np.array([0.0, 0.0, -1.5 * surface_size])) bindTexture(0, hm_texture) glUniform1i(hm_program.uniformLocation("tex"), 0) glUniformMatrix4fv(hm_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(hm_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(hm_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(heightmap_vao) glDrawElements(GL_TRIANGLE_STRIP, ind_hm, GL_UNSIGNED_INT, None) cm_program.bindProgram() model = translateM4x4(np.array([1.5 * surface_size, 0.0, -1.5 * surface_size])) cur_cm_texture = cm_textures[cm_texture_num % HDR_TEXTURES_AMOUNT] bindTexture(1, cur_cm_texture) if cm_change_counter % hdr_textures_speed == 0: cm_texture_num += 1 cm_change_counter += 1 glUniform1i(cm_program.uniformLocation("cm_switch"), False) glUniform1i(cm_program.uniformLocation("tex"), 1) glUniformMatrix4fv(cm_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(cm_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(cm_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(cm_vao) glDrawElements(GL_TRIANGLE_STRIP, ind_cm, GL_UNSIGNED_INT, None) # draw second animated hdr on the same shader model = translateM4x4(np.array([2.5 * surface_size, 0.0, -2.5 * surface_size])) glUniformMatrix4fv(cm_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniform1i(cm_program.uniformLocation("cm_switch"), True) glDrawElements(GL_TRIANGLE_STRIP, ind_cm, GL_UNSIGNED_INT, None) perlin_program.bindProgram() model = translateM4x4(np.array([0.0, 0.0, -3.5 * surface_size])) glUniformMatrix4fv(perlin_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(perlin_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(perlin_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glUniform1f(perlin_program.uniformLocation("time"), perlin_time) perlin_time += perlin_time_step glBindVertexArray(perlin_vao) glDrawElements(GL_TRIANGLE_STRIP, ind_perlin, GL_UNSIGNED_INT, None) grad_program.bindProgram() model = translateM4x4(np.array([-25.0, 0.0, -7.0 * surface_size])) glUniformMatrix4fv(grad_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(grad_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(grad_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(grad_vao) glDrawArrays(GL_LINES, 0, grad_point_count) vf_program.bindProgram() model = translateM4x4(np.array([0.0, 0.0, -5.5 * surface_size])) glUniformMatrix4fv(vf_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glUniformMatrix4fv(vf_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(vf_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glUniform1i(vf_program.uniformLocation("cm_switch"), True) glBindVertexArray(div_vao) glDrawElements(GL_TRIANGLE_STRIP, ind_div, GL_UNSIGNED_INT, None) glUniform1i(vf_program.uniformLocation("cm_switch"), False) model = translateM4x4(np.array([1.0 * surface_size, 0.0, -6.5 * surface_size])) glUniformMatrix4fv(vf_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(model).flatten()) glDrawElements(GL_TRIANGLE_STRIP, ind_div, GL_UNSIGNED_INT, None) traj_program.bindProgram() l_traj_part =[] r_traj_part =[] if offset > 0: traj_part_index = int(traj_points_count - cm_change_counter % cube_steps) r_traj_part = traj_points_list[0:traj_part_index] for traj_coords in r_traj_part: l_traj_part.append( [-x for x in traj_coords] ) else: traj_part_index = int(traj_points_count - cm_change_counter % cube_steps) # traj_part_index = int(cm_change_counter % cube_steps) l_traj_part = traj_points_list[0:traj_part_index] for traj_coords in l_traj_part: r_traj_part.append([-x for x in traj_coords]) l_traj_vec = np.array(l_traj_part, dtype=np.float32) r_traj_vec = np.array(r_traj_part, dtype=np.float32) indices_list = [i for i in range(len(r_traj_part))] indices_vec = np.array(indices_list, dtype=np.uint32) left_traj_vao = glGenVertexArrays(1) right_traj_vao = glGenVertexArrays(1) left_traj_vertices = glGenBuffers(1) left_traj_indices = glGenBuffers(1) right_traj_vertices = glGenBuffers(1) right_traj_indices = glGenBuffers(1) glBindVertexArray(left_traj_vao) glPointSize( 3.0 ) glBindBuffer(GL_ARRAY_BUFFER, left_traj_vertices) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(l_traj_vec), l_traj_vec.flatten(), GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, left_traj_indices) glBufferData(GL_ELEMENT_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(indices_vec), indices_vec.flatten(), GL_STATIC_DRAW) glBindVertexArray(right_traj_vao) glBindBuffer(GL_ARRAY_BUFFER, right_traj_vertices) glBufferData(GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(r_traj_vec), r_traj_vec.flatten(), GL_STATIC_DRAW) glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) glEnableVertexAttribArray(0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, right_traj_indices) glBufferData(GL_ELEMENT_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(indices_vec), indices_vec.flatten(), GL_STATIC_DRAW) glBindVertexArray(0) cube_scale_ = scaleM4x4(np.array([1.0, 1.0, 1.0])) left_cube_pos += offset left_translation = translateM4x4(np.array([left_cube_pos, 0.0, -7.5 * surface_size])) glUniformMatrix4fv(traj_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(left_translation).flatten()) glUniformMatrix4fv(traj_program.uniformLocation("view"), 1, GL_FALSE, np.transpose(view).flatten()) glUniformMatrix4fv(traj_program.uniformLocation("projection"), 1, GL_FALSE, projection.flatten()) glBindVertexArray(left_traj_vao) glDrawElements(GL_LINE_STRIP, indices_vec.size, GL_UNSIGNED_INT, None) glBindVertexArray(traj_vao) glDrawElements(GL_TRIANGLE_STRIP, ind_traj, GL_UNSIGNED_INT, None) right_translation = translateM4x4(np.array([-left_cube_pos, 0.0, -8.5 * surface_size])) glUniformMatrix4fv(traj_program.uniformLocation("model"), 1, GL_FALSE, np.transpose(right_translation).flatten()) glDrawElements(GL_TRIANGLE_STRIP, ind_traj, GL_UNSIGNED_INT, None) glBindVertexArray(right_traj_vao) glDrawElements(GL_LINE_STRIP, indices_vec.size, GL_UNSIGNED_INT, None) if not cm_change_counter % cube_steps: # left_cube_pos = left_cube_pos + offset * (cube_steps-1) offset *= -1 # r_traj_part, l_traj_part = l_traj_part, r_traj_part traj_program.unbindProgram() glfw.swap_buffers(window) glfw.terminate()
def render( self, proj: np.ndarray, view: np.ndarray, lights: List[Light], parent_matrix: Optional[np.ndarray] = None, ) -> None: """ Virtual function for rendering the object. Some objects can overwrite this function. Args: proj: Camera projection matrix. view: Camera location/view matrix. lights: Light objects in the scene parent_matrix: Parent matrix is the matrix of the parent. Parent can be the scene itself or another object. In case of another object, object will position itself relative to its parent object. """ if not self._visible: return if not self.has_vao or self._needs_update: self.build() if self._vertex_count == 0: return self.update_matrix(parent_matrix=parent_matrix) self.track() # Material shading mode. mode = None if self._has_vertex_colors: mode = Shader.PER_VERTEX_COLOR self.material.render(proj, view, self._model_matrix, lights, mode) # Actual rendering if glIsVertexArray(self._vao): glBindVertexArray(self._vao) pmode = GL_LINE primitive = GL_LINE_STRIP if self.material.display == SOLID: pmode = GL_FILL primitive = GL_TRIANGLES if self.material.display == POINTS: pmode = GL_POINT primitive = GL_POINTS glPolygonMode(GL_FRONT_AND_BACK, pmode) glDrawElements( primitive, self._vertex_count, GL_UNSIGNED_INT, ctypes.c_void_p(0), ) if pmode != GL_FILL: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glBindVertexArray(0) # End using the shader program. self.material.end() # Render motion path if self.track_motion: self._motion_path_line.render(proj, view, lights, parent_matrix) # render children for child in self.children: self.children[child].render(proj, view, lights, self._model_matrix)
def run(): #Start OpenGL and ask it for an OpenGL context pygame.init() clock = pygame.time.Clock() screen = pygame.display.set_mode(SCREEN_SIZE, pygame.HWSURFACE|pygame.OPENGL|pygame.DOUBLEBUF) #The first thing we do is print some OpenGL details and check that we have a good enough version print("OpenGL Implementation Details:") if glGetString(GL_VENDOR): print("\tGL_VENDOR: {}".format(glGetString(GL_VENDOR).decode())) if glGetString(GL_RENDERER): print("\tGL_RENDERER: {}".format(glGetString(GL_RENDERER).decode())) if glGetString(GL_VERSION): print("\tGL_VERSION: {}".format(glGetString(GL_VERSION).decode())) if glGetString(GL_SHADING_LANGUAGE_VERSION): print("\tGL_SHADING_LANGUAGE_VERSION: {}".format(glGetString(GL_SHADING_LANGUAGE_VERSION).decode())) major_version = int(glGetString(GL_VERSION).decode().split()[0].split('.')[0]) minor_version = int(glGetString(GL_VERSION).decode().split()[0].split('.')[1]) if major_version < 3 or (major_version < 3 and minor_version < 0): print("OpenGL version must be at least 3.0 (found {0})".format(glGetString(GL_VERSION).decode().split()[0])) #Now onto the OpenGL initialisation #Set up depth culling glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glDepthMask(GL_TRUE) glDepthFunc(GL_LEQUAL) glDepthRange(0.0, 1.0) #We create out shaders which do little more than set a flat colour for each face VERTEX_SHADER = shaders.compileShader(b""" #version 130 in vec4 position; in vec4 normal; uniform mat4 projectionMatrix; uniform mat4 viewMatrix; uniform mat4 modelMatrix; flat out float theColor; void main() { vec4 temp = modelMatrix * position; temp = viewMatrix * temp; gl_Position = projectionMatrix * temp; theColor = clamp(abs(dot(normalize(normal.xyz), normalize(vec3(0.9,0.1,0.5)))), 0, 1); } """, GL_VERTEX_SHADER) FRAGMENT_SHADER = shaders.compileShader(b""" #version 130 flat in float theColor; out vec4 outputColor; void main() { outputColor = vec4(1.0, 0.5, theColor, 1.0); } """, GL_FRAGMENT_SHADER) shader = shaders.compileProgram(VERTEX_SHADER, FRAGMENT_SHADER) #And then grab our attribute locations from it glBindAttribLocation(shader, 0, b"position") glBindAttribLocation(shader, 1, b"normal") #Create the Vertex Array Object to hold our volume mesh vertexArrayObject = GLuint(0) glGenVertexArrays(1, vertexArrayObject) glBindVertexArray(vertexArrayObject) #Create the index buffer object indexPositions = vbo.VBO(indices, target=GL_ELEMENT_ARRAY_BUFFER, usage=GL_STATIC_DRAW) #Create the VBO vertexPositions = vbo.VBO(vertices, usage=GL_STATIC_DRAW) #Bind our VBOs and set up our data layout specifications with indexPositions, vertexPositions: glEnableVertexAttribArray(0) glVertexAttribPointer(0, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(0*vertices.dtype.itemsize)) glEnableVertexAttribArray(1) glVertexAttribPointer(1, 3, GL_FLOAT, False, 6*vertices.dtype.itemsize, vertexPositions+(3*vertices.dtype.itemsize)) glBindVertexArray(0) glDisableVertexAttribArray(0) #Now grab out transformation martix locations modelMatrixUnif = glGetUniformLocation(shader, b"modelMatrix") viewMatrixUnif = glGetUniformLocation(shader, b"viewMatrix") projectionMatrixUnif = glGetUniformLocation(shader, b"projectionMatrix") modelMatrix = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') viewMatrix = np.array([[1.0,0.0,0.0,0.0],[0.0,1.0,0.0,0.0],[0.0,0.0,1.0,-50.0],[0.0,0.0,0.0,1.0]], dtype='f') projectionMatrix = np.array([[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0],[0.0,0.0,0.0,0.0]], dtype='f') #These next few lines just set up our camera frustum fovDeg = 45.0 frustumScale = 1.0 / tan(radians(fovDeg) / 2.0) zNear = 1.0 zFar = 1000.0 projectionMatrix[0][0] = frustumScale projectionMatrix[1][1] = frustumScale projectionMatrix[2][2] = (zFar + zNear) / (zNear - zFar) projectionMatrix[2][3] = -1.0 projectionMatrix[3][2] = (2 * zFar * zNear) / (zNear - zFar) #viewMatrix and projectionMatrix don't change ever so just set them once here with shader: glUniformMatrix4fv(projectionMatrixUnif, 1, GL_TRUE, projectionMatrix) glUniformMatrix4fv(viewMatrixUnif, 1, GL_TRUE, viewMatrix) #These are used to track the rotation of the volume LastFrameMousePos = (0,0) CurrentMousePos = (0,0) xRotation = 0 yRotation = 0 while True: clock.tick() for event in pygame.event.get(): if event.type == pygame.QUIT: return if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: return if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: CurrentMousePos = event.pos LastFrameMousePos = CurrentMousePos if event.type == pygame.MOUSEMOTION and 1 in event.buttons: CurrentMousePos = event.pos diff = (CurrentMousePos[0] - LastFrameMousePos[0], CurrentMousePos[1] - LastFrameMousePos[1]) xRotation += event.rel[0] yRotation += event.rel[1] LastFrameMousePos = CurrentMousePos glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) #Perform the rotation of the mesh moveToOrigin = np.array([[1.0,0.0,0.0,-32.0],[0.0,1.0,0.0,-32.0],[0.0,0.0,1.0,-32.0],[0.0,0.0,0.0,1.0]], dtype='f') rotateAroundX = np.array([[1.0,0.0,0.0,0.0],[0.0,cos(radians(yRotation)),-sin(radians(yRotation)),0.0],[0.0,sin(radians(yRotation)),cos(radians(yRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') rotateAroundY = np.array([[cos(radians(xRotation)),0.0,sin(radians(xRotation)),0.0],[0.0,1.0,0.0,0.0],[-sin(radians(xRotation)),0.0,cos(radians(xRotation)),0.0],[0.0,0.0,0.0,1.0]], dtype='f') modelMatrix = rotateAroundY.dot(rotateAroundX.dot(moveToOrigin)) with shader: glUniformMatrix4fv(modelMatrixUnif, 1, GL_TRUE, modelMatrix) glBindVertexArray(vertexArrayObject) glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, None) glBindVertexArray(0) # Show the screen pygame.display.flip()
def _render_volume_obj(self, volume_object, width, height, VMatrix, PMatrix): glBindFramebuffer(GL_FRAMEBUFFER, self.fbo) glViewport(0, 0, width, height) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_3D, volume_object.stack_object.stack_texture) glClear(GL_COLOR_BUFFER_BIT) # Clear back buffer. glEnable(GL_CULL_FACE) glCullFace(GL_BACK) glUseProgram(self.b_shader.program) glBindVertexArray(volume_object.vao) volume_object.elVBO.bind() mv_matrix = np.dot(VMatrix, volume_object.transform) glUniformMatrix4fv(self.b_shader.get_uniform("mv_matrix"), 1, True, mv_matrix.astype('float32')) glUniformMatrix4fv(self.b_shader.get_uniform("p_matrix"), 1, True, PMatrix.astype('float32')) glDrawElements(GL_TRIANGLES, volume_object.elCount, GL_UNSIGNED_INT, volume_object.elVBO) volume_object.elVBO.unbind() glBindVertexArray(0) glUseProgram(0) glBindFramebuffer(GL_FRAMEBUFFER, 0) glActiveTexture(GL_TEXTURE0 + 1) glBindTexture(GL_TEXTURE_2D, self.bfTex) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_3D, volume_object.stack_object.stack_texture) glUseProgram(self.f_shader.program) glUniform1i(self.f_shader.get_uniform("texture3s"), 0) glUniform1i(self.f_shader.get_uniform("backfaceTex"), 1) tex_inv_matrix = np.dot(PMatrix, np.dot(mv_matrix, la.inv(volume_object.tex_transform))) glUniformMatrix4fv(self.f_shader.get_uniform('tex_inv_matrix'), 1, True, tex_inv_matrix.astype('float32')) glUniform1f(self.f_shader.get_uniform('isolevel'), volume_object.threshold/255.0) glEnable(GL_CULL_FACE) glCullFace(GL_FRONT) glBindVertexArray(volume_object.vao) volume_object.elVBO.bind() glUniformMatrix4fv(self.f_shader.get_uniform("mv_matrix"), 1, True, mv_matrix.astype('float32')) glUniformMatrix4fv(self.f_shader.get_uniform("p_matrix"), 1, True, PMatrix.astype('float32')) glDrawElements(GL_TRIANGLES, volume_object.elCount, GL_UNSIGNED_INT, volume_object.elVBO) glActiveTexture(GL_TEXTURE0+1) glBindTexture(GL_TEXTURE_2D, 0) glCullFace(GL_BACK) volume_object.elVBO.unbind() glBindVertexArray(0) glUseProgram(0)
def draw(self, drawIndex = None, highlighted = False, selected = False, patterning = True, highlight_color = None, opacity = 1.0): """ Draw the buffered geometry, binding vertex attribute values for the shaders. If no drawIndex is given, the whole array is drawn. """ self.shader.setActive(True) # Turn on the chosen shader. glEnableClientState(GL_VERTEX_ARRAY) self.shader.setupDraw(highlighted, selected, patterning, highlight_color, opacity) # XXX No transform data until that is more implemented. ###self.shader.setupTransforms(self.transforms) # (note: the reason TransformControls work in their test case # is due to a manual call of shader.setupTransforms. [bruce 090306 guess]) if self.shader.get_TEXTURE_XFORMS(): # Activate a texture unit for transforms. ## XXX Not necessary for custom shader programs. ##glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, self.transform_memory) ### BUG: pylint warning: # Instance of 'GLPrimitiveBuffer' has no 'transform_memory' member #### REVIEW: should this be the attr of that name in GLShaderObject, # i.e. self.shader? I didn't fix it myself as a guess, in case other # uses of self also need fixing in the same way. [bruce 090304 comment] # Set the sampler to the handle for the active texture image (0). ## XXX Not needed if only one texture is being used? ##glActiveTexture(GL_TEXTURE0) ##glUniform1iARB(self.shader._uniform("transforms"), 0) pass glDisable(GL_CULL_FACE) # Draw the hunks. for hunkNumber in range(self.nHunks): # Bind the per-vertex generic attribute arrays for one hunk. for buffer in self.hunkBuffers: buffer.flush() # Sync graphics card copies of the VBO data. buffer.bindHunk(hunkNumber) continue # Shared vertex coordinate data VBO: GL_ARRAY_BUFFER_ARB. self.hunkVertVBO.bind() glVertexPointer(3, GL_FLOAT, 0, None) # Shared vertex index data IBO: GL_ELEMENT_ARRAY_BUFFER_ARB self.hunkIndexIBO.bind() if drawIndex is not None: # Draw the selected primitives for this Hunk. index = drawIndex[hunkNumber] primcount = len(index) glMultiDrawElementsVBO( self.drawingMode, self.C_indexBlockLengths, GL_UNSIGNED_INT, index, primcount) else: # For initial testing, draw all primitives in the Hunk. if hunkNumber < self.nHunks-1: nToDraw = HUNK_SIZE # Hunks before the last. else: nToDraw = self.nPrims - (self.nHunks-1) * HUNK_SIZE pass glDrawElements(self.drawingMode, self.nIndices * nToDraw, GL_UNSIGNED_INT, None) pass continue self.shader.setActive(False) # Turn off the chosen shader. glEnable(GL_CULL_FACE) self.hunkIndexIBO.unbind() # Deactivate the ibo. self.hunkVertVBO.unbind() # Deactivate all vbo's. glDisableClientState(GL_VERTEX_ARRAY) for buffer in self.hunkBuffers: buffer.unbindHunk() # glDisableVertexAttribArrayARB. continue return
def render(__, mode=GL_QUADS): glDrawElements(mode, __.nElement, GL_UNSIGNED_INT, c_void_p(0))
def paint(self): self._applyGLOptions() if self.__antialiasing: glEnable(GL_LINE_SMOOTH) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) glLineWidth(1.5) if self.draw_faces: # need face with self.shader_program: glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.mesh.face_vertices) glColor4f(*self.face_color) glEnableClientState(GL_NORMAL_ARRAY) glNormalPointerf(self.mesh.face_normal_vectors) glDrawArrays(GL_TRIANGLES, 0, np.product(self.mesh.face_vertices.shape[:-1])) glDisableClientState(GL_NORMAL_ARRAY) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) if self.debug_face_normals: # Visualize the face normal vectors glEnableClientState(GL_VERTEX_ARRAY) N = self.mesh.face_vertices.shape[0] * 3 v = np.concatenate([ self.mesh.face_vertices, self.mesh.face_vertices + self.mesh.face_normal_vectors, ]) e = np.array([np.arange(N), np.arange(N) + N]).T.flatten() glColor4f(1.0, 1.0, 0.0, 1.0) glVertexPointerf(v) glDrawElements(GL_LINES, e.shape[0], GL_UNSIGNED_INT, e) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) if self.debug_face_edges: # visualize all face edges glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.mesh.wireframe_vertices) glColor4f(1.0, 1.0, 0.0, 1.0) edges = self.mesh.face_edges.flatten() glDrawElements(GL_LINES, edges.shape[0], GL_UNSIGNED_INT, edges) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY) if self.draw_wireframe and self.mesh.has_wireframe: # draw a mesh wireframe which may or may not be identical to the face edges, depending on the mesh glEnableClientState(GL_VERTEX_ARRAY) glVertexPointerf(self.mesh.wireframe_vertices) glColor4f(0, 1, 0, 1) edges = self.mesh.wireframe_edges.flatten() glDrawElements(GL_LINES, edges.shape[0], GL_UNSIGNED_INT, edges) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_COLOR_ARRAY)
def draw(self, drawIndex=None, highlighted=False, selected=False, patterning=True, highlight_color=None, opacity=1.0): """ Draw the buffered geometry, binding vertex attribute values for the shaders. If no drawIndex is given, the whole array is drawn. """ self.shader.setActive(True) # Turn on the chosen shader. glEnableClientState(GL_VERTEX_ARRAY) self.shader.setupDraw(highlighted, selected, patterning, highlight_color, opacity) # XXX No transform data until that is more implemented. ###self.shader.setupTransforms(self.transforms) # (note: the reason TransformControls work in their test case # is due to a manual call of shader.setupTransforms. [bruce 090306 guess]) if self.shader.get_TEXTURE_XFORMS(): # Activate a texture unit for transforms. ## XXX Not necessary for custom shader programs. ##glEnable(GL_TEXTURE_2D) glBindTexture(GL_TEXTURE_2D, self.transform_memory) ### BUG: pylint warning: # Instance of 'GLPrimitiveBuffer' has no 'transform_memory' member #### REVIEW: should this be the attr of that name in GLShaderObject, # i.e. self.shader? I didn't fix it myself as a guess, in case other # uses of self also need fixing in the same way. [bruce 090304 comment] # Set the sampler to the handle for the active texture image (0). ## XXX Not needed if only one texture is being used? ##glActiveTexture(GL_TEXTURE0) ##glUniform1iARB(self.shader._uniform("transforms"), 0) pass glDisable(GL_CULL_FACE) # Draw the hunks. for hunkNumber in range(self.nHunks): # Bind the per-vertex generic attribute arrays for one hunk. for buffer in self.hunkBuffers: buffer.flush() # Sync graphics card copies of the VBO data. buffer.bindHunk(hunkNumber) continue # Shared vertex coordinate data VBO: GL_ARRAY_BUFFER_ARB. self.hunkVertVBO.bind() glVertexPointer(3, GL_FLOAT, 0, None) # Shared vertex index data IBO: GL_ELEMENT_ARRAY_BUFFER_ARB self.hunkIndexIBO.bind() if drawIndex is not None: # Draw the selected primitives for this Hunk. index = drawIndex[hunkNumber] primcount = len(index) glMultiDrawElementsVBO(self.drawingMode, self.C_indexBlockLengths, GL_UNSIGNED_INT, index, primcount) else: # For initial testing, draw all primitives in the Hunk. if hunkNumber < self.nHunks - 1: nToDraw = HUNK_SIZE # Hunks before the last. else: nToDraw = self.nPrims - (self.nHunks - 1) * HUNK_SIZE pass glDrawElements(self.drawingMode, self.nIndices * nToDraw, GL_UNSIGNED_INT, None) pass continue self.shader.setActive(False) # Turn off the chosen shader. glEnable(GL_CULL_FACE) self.hunkIndexIBO.unbind() # Deactivate the ibo. self.hunkVertVBO.unbind() # Deactivate all vbo's. glDisableClientState(GL_VERTEX_ARRAY) for buffer in self.hunkBuffers: buffer.unbindHunk() # glDisableVertexAttribArrayARB. continue return
def _render_volume_obj(self, volume_object, width, height, VMatrix, PMatrix): glBindFramebuffer(GL_FRAMEBUFFER, self.fbo) glViewport(0, 0, width, height) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_3D, volume_object.stack_object.stack_texture) glClear(GL_COLOR_BUFFER_BIT) # Clear back buffer. glEnable(GL_CULL_FACE) glCullFace(GL_FRONT) # NB flipped # glValidateProgram(self.b_shader.program) # logging.debug("b_valid ", glGetProgramiv(self.b_shader.program, # GL_VALIDATE_STATUS)) # logging.debug(glGetProgramInfoLog(self.b_shader.program).decode()) glUseProgram(self.b_shader.program) glBindVertexArray(volume_object.vao) volume_object.elVBO.bind() mv_matrix = np.dot(VMatrix, volume_object.transform) glUniformMatrix4fv(self.b_shader.get_uniform("mv_matrix"), 1, True, mv_matrix.astype('float32')) glUniformMatrix4fv(self.b_shader.get_uniform("p_matrix"), 1, True, PMatrix.astype('float32')) glDrawElements(GL_TRIANGLES, volume_object.elCount, GL_UNSIGNED_INT, volume_object.elVBO) volume_object.elVBO.unbind() glBindVertexArray(0) glUseProgram(0) glBindFramebuffer(GL_FRAMEBUFFER, 0) glActiveTexture(GL_TEXTURE0 + 1) glBindTexture(GL_TEXTURE_2D, self.bfTex) glActiveTexture(GL_TEXTURE0) glBindTexture(GL_TEXTURE_3D, volume_object.stack_object.stack_texture) glUseProgram(self.f_shader.program) glUniform1i(self.f_shader.get_uniform("texture3s"), 0) glUniform1i(self.f_shader.get_uniform("backfaceTex"), 1) glEnable(GL_CULL_FACE) glCullFace(GL_BACK) glBindVertexArray(volume_object.vao) volume_object.elVBO.bind() glUniformMatrix4fv(self.f_shader.get_uniform("mv_matrix"), 1, True, mv_matrix.astype('float32')) glUniformMatrix4fv(self.f_shader.get_uniform("p_matrix"), 1, True, PMatrix.astype('float32')) glDrawElements(GL_TRIANGLES, volume_object.elCount, GL_UNSIGNED_INT, volume_object.elVBO) glActiveTexture(GL_TEXTURE0+1) glBindTexture(GL_TEXTURE_2D, 0) glCullFace(GL_BACK) volume_object.elVBO.unbind() glBindVertexArray(0) glUseProgram(0)
def Draw(self, va, ib, shader): shader.Bind() va.Bind() ib.Bind() glDrawElements(GL_TRIANGLES, ib.GetCount(), GL_UNSIGNED_INT, None)
def test_drawing(glpane, initOnly = False): """ When TEST_DRAWING is enabled at the start of graphics/widgets/GLPane_rendering_methods.py, and when TestGraphics_Command is run (see its documentation for various ways to do that), this file is loaded and GLPane.paintGL() calls the test_drawing() function instead of the usual body of paintGL(). """ # WARNING: this duplicates some code with test_Draw_model(). # Load the sphere shaders if needed. global _USE_SHADERS if _USE_SHADERS: if not drawing_globals.test_sphereShader: print "test_drawing: Loading sphere shaders." try: from graphics.drawing.gl_shaders import GLSphereShaderObject drawing_globals.test_sphereShader = GLSphereShaderObject() ##### REVIEW: is this compatible with my refactoring in drawing_globals? # If not, use of Test Graphics Performance command might cause subsequent # bugs in other code. Ideally we'd call the new methods that encapsulate # this, to setup shaders. [bruce 090304 comment] print "test_drawing: Sphere-shader initialization is complete.\n" except: _USE_SHADERS = False print "test_drawing: Exception while loading sphere shaders, will reraise and not try again" raise pass global start_pos, first_time if first_time: # Set up the viewing scale, but then let interactive zooming work. glpane.scale = nSpheres * .6 pass # This same function gets called to set up for drawing, and to draw. if not initOnly: glpane._setup_modelview() glpane._setup_projection() ##glpane._compute_frustum_planes() glClearColor(64.0, 64.0, 64.0, 1.0) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ) ##glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ) glMatrixMode(GL_MODELVIEW) pass global test_csdl, test_dl, test_dls, test_ibo, test_vbo, test_spheres global test_DrawingSet, test_endpoints, test_Object # See below for test case descriptions and timings on a MacBook Pro. # The Qt event toploop in NE1 tops out at about 60 frames-per-second. # NE1 with test toploop, single CSDL per draw (test case 1) # . 17,424 spheres (132x132, through the color sorter) 4.8 FPS # Russ 080919: More recently, 12.2 FPS. # . Level 2 spheres have 9 triangles x 20 faces, 162 distinct vertices, # visited on the average 2.3 times, giving 384 tri-strip vertices. # . 17,424 spheres is 6.7 million tri-strip vertices. (6,690,816) if testCase == 1: if test_csdl is None: print ("Test case 1, %d^2 spheres\n %s." % (nSpheres, "ColorSorter")) test_csdl = ColorSortedDisplayList() ColorSorter.start(None, test_csdl) drawsphere([0.5, 0.5, 0.5], # color [0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, testloop = nSpheres ) ColorSorter.finish(draw_now = True) pass else: test_csdl.draw() pass # NE1 with test toploop, single display list per draw (test case 2) # . 10,000 spheres (all drawing modes) 17.5 FPS # . 17,424 spheres (132x132, manual display list) 11.1 FPS # . 40,000 spheres (mode 5 - VBO/IBO spheres from DL's) 2.2 FPS # . 40,000 spheres (mode 6 - Sphere shaders from DL's) 2.5 FPS # . 90,000 spheres (all drawing modes) 1.1 FPS elif testCase == 2: if test_dl is None: print ("Test case 2, %d^2 spheres\n %s." % (nSpheres, "One display list calling primitive dl's")) test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) drawsphere_worker_loop(([0.0, 0.0, 0.0], # pos .5, # radius DRAWSPHERE_DETAIL_LEVEL, nSpheres )) glEndList() pass else: glColor3i(127, 127, 127) glCallList(test_dl) pass # NE1 with test toploop, one big chunk VBO/IBO of box quads (test case 3) # . 17,424 spheres (1 box/shader draw call) 43.7 FPS # . 17,424 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 57.7 FPS # . 40,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 56.7 FPS # . 90,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 52.7 FPS # . 160,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 41.4 FPS # . 250,000 spheres (1 box/shader draw call w/ rad/ctrpt attrs) 27.0 FPS elif int(testCase) == 3: doTransforms = False if test_spheres is None: print ("Test case 3, %d^2 spheres\n %s." % (nSpheres, "One big VBO/IBO chunk buffer")) if testCase == 3.1: print ("Sub-test 3.1, animate partial updates.") elif testCase == 3.2: print ("Sub-test 3.2, animate partial updates" + " w/ C per-chunk array buffering.") elif testCase == 3.3: print ("Sub-test 3.3, animate partial updates" + " w/ Python array buffering.") # . 3.4 - Big batch draw, with transforms indexed by IDs added. # (Second FPS number with debug colors in the vertex shader off.) # - 90,000 (300x300) spheres, TEXTURE_XFORMS = True, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 250, 26(29) FPS # - 90,000 (300x300) spheres, N_CONST_XFORMS = 275, 0.3(0.6) FPS # (What happens after 250? CPU usage goes from 40% to 94%.) # -160,000 (400x400) spheres, TEXTURE_XFORMS = True, 26 FPS # -250,000 (500x500) spheres, TEXTURE_XFORMS = True, 26 FPS elif testCase == 3.4: print ("Sub-test 3.4, add transforms indexed by IDs.") from graphics.drawing.gl_shaders import TEXTURE_XFORMS from graphics.drawing.gl_shaders import N_CONST_XFORMS from graphics.drawing.gl_shaders import UNIFORM_XFORMS if TEXTURE_XFORMS: print "Transforms in texture memory." elif UNIFORM_XFORMS: print "%d transforms in uniform memory." % N_CONST_XFORMS pass else: print "transforms not supported, error is likely" doTransforms = True pass centers = [] radius = .5 radii = [] colors = [] if not doTransforms: transformIDs = None else: transformIDs = [] transformChunkID = -1 # Allocate IDs sequentially from 0. # For this test, allow arbitrarily chunking the primitives. primCounter = transformChunkLength transforms = [] # Accumulate transforms as a list of lists. # Initialize transforms with an identity matrix. # Transforms here are lists (or Numpy arrays) of 16 numbers. identity = ([1.0] + 4*[0.0]) * 3 + [1.0] pass for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.75 + t*.25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Transforms go into a texture memory image if needed. # Per-primitive Transform IDs go into an attribute VBO. if doTransforms: primCounter = primCounter + 1 if primCounter >= transformChunkLength: # Start a new chunk, allocating a transform matrix. primCounter = 0 transformChunkID += 1 if 0: # 1 # Debug hack: Label mat[0,0] with the chunk ID. # Vertex shader debug code shows these in blue. # If viewed as geometry, it will be a slight # stretch of the array in the X direction. transforms += [ [1.0+transformChunkID/100.0] + identity[1:]] elif 0: # 1 # Debug hack: Fill mat with mat.element pattern. transforms += [ [transformChunkID + i/100.0 for i in range(16)]] else: transforms += [identity] pass pass # All of the primitives in a chunk have the same ID. transformIDs += [transformChunkID] pass continue continue test_spheres = GLSphereBuffer() test_spheres.addSpheres(centers, radii, colors, transformIDs, None) if doTransforms: print ("%d primitives in %d transform chunks of size <= %d" % (nSpheres * nSpheres, len(transforms), transformChunkLength)) shader = drawing_globals.test_sphereShader shader.setupTransforms(transforms) pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Update portions for animation. pulse = time.time() pulse -= floor(pulse) # 0 to 1 in each second # Test animating updates on 80% of the radii in 45% of the columns. # . 3.1 - Update radii Python array per-column, send to graphics RAM. # - 2,500 (50x50) spheres 55 FPS # - 10,000 (100x100) spheres 35 FPS # - 17,424 (132x132) spheres 22.2 FPS # - 40,000 (200x200) spheres 12.4 FPS # - 90,000 (300x300) spheres 6.0 FPS if testCase == 3.1: # Not buffered, send each column change. radius = .5 margin = nSpheres/10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres-margin): t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t*.25) phase = pulse + float(x+y)/nSpheres radii += 8 * [thisRad-.1 + .1*sin(phase * 2*pi)] continue C_radii = numpy.array(radii, dtype=numpy.float32) offset = x*nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_radii) continue pass # . 3.2 - Numpy buffered in C array, subscript assignments to C. # - 2,500 (50x50) spheres 48 FPS # - 10,000 (100x100) spheres 17.4 FPS # - 17,424 (132x132) spheres 11.2 FPS # - 40,000 (200x200) spheres 5.5 FPS # - 90,000 (300x300) spheres 2.5 FPS elif testCase == 3.2: # Buffered per-chunk at the C array level. radius = .5 margin = nSpheres/10 global C_array if C_array is None: # Replicate. C_array = numpy.zeros((8 * (nSpheres-(2*margin)),), dtype=numpy.float32) pass for x in range(margin, nSpheres, 2): count = 0 for y in range(margin, nSpheres-margin): t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t*.25) phase = pulse + float(x+y)/nSpheres C_array[count*8:(count+1)*8] = \ thisRad-.1 + .1*sin(phase * 2*pi) count += 1 continue offset = x*nSpheres + margin test_spheres.radii_vbo.update(offset * 8, C_array) continue pass # . 3.3 - updateRadii in Python array, copy via C to graphics RAM. # - 2,500 (50x50) spheres 57 FPS # - 10,000 (100x100) spheres 32 FPS # - 17,424 (132x132) spheres 20 FPS # - 40,000 (200x200) spheres 10.6 FPS # - 90,000 (300x300) spheres 4.9 FPS elif testCase == 3.3: # Buffered at the Python level, batch the whole-array update. radius = .5 margin = nSpheres/10 for x in range(margin, nSpheres, 2): radii = [] for y in range(margin, nSpheres-margin): t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. # Sphere radii progress from 3/4 to full size. thisRad = radius * (.75 + t*.25) phase = pulse + float(x+y)/nSpheres radii += [thisRad-.1 + .1*sin(phase * 2*pi)] continue test_spheres.updateRadii( # Update, but don't send yet. x*nSpheres + margin, radii, send = False) continue test_spheres.sendRadii() pass # Options: color = [0.0, 1.0, 0.0], transform_id = 1, radius = 1.0 test_spheres.draw() pass # NE1 with test toploop, separate sphere VBO/IBO box/shader draws (test case 4) # . 17,424 spheres (132x132 box/shader draw quads calls) 0.7 FPS elif testCase == 4: if test_ibo is None: print ("Test case 4, %d^2 spheres\n %s." % (nSpheres, "Separate VBO/IBO shader/box buffer sphere calls, no DL")) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject( GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject( GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() pass else: drawing_globals.test_sphereShader.configShader(glpane) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius,radius,radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) pass # NE1 with test toploop, # One DL around separate VBO/IBO shader/box buffer sphere calls (test case 5) # . 17,424 spheres (1 box/shader DL draw call) 9.2 FPS elif testCase == 5: if test_dl is None: print ("Test case 5, %d^2 spheres\n %s." % (nSpheres, "One DL around separate VBO/IBO shader/box buffer sphere calls")) # Collect transformed bounding box vertices and offset indices. # Start at the lower-left corner, offset so the whole pattern comes # up centered on the origin. cubeVerts = drawing_globals.shaderCubeVerts cubeIndices = drawing_globals.shaderCubeIndices C_indices = numpy.array(cubeIndices, dtype=numpy.uint32) test_ibo = GLBufferObject( GL_ELEMENT_ARRAY_BUFFER_ARB, C_indices, GL_STATIC_DRAW) test_ibo.unbind() C_verts = numpy.array(cubeVerts, dtype=numpy.float32) test_vbo = GLBufferObject( GL_ARRAY_BUFFER_ARB, C_verts, GL_STATIC_DRAW) test_vbo.unbind() # Wrap a display list around the draws. test_dl = glGenLists(1) glNewList(test_dl, GL_COMPILE_AND_EXECUTE) glEnableClientState(GL_VERTEX_ARRAY) test_vbo.bind() # Vertex data comes from the vbo. glVertexPointer(3, GL_FLOAT, 0, None) drawing_globals.test_sphereShader.setActive(True) glDisable(GL_CULL_FACE) glColor3i(127, 127, 127) test_ibo.bind() # Index data comes from the ibo. for x in range(nSpheres): for y in range(nSpheres): # From drawsphere_worker_loop(). pos = start_pos + (x+x/10+x/100) * V(1, 0, 0) + \ (y+y/10+y/100) * V(0, 1, 0) radius = .5 glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) glScale(radius,radius,radius) glDrawElements(GL_QUADS, 6 * 4, GL_UNSIGNED_INT, None) glPopMatrix() continue continue drawing_globals.test_sphereShader.setActive(False) glEnable(GL_CULL_FACE) test_ibo.unbind() test_vbo.unbind() glDisableClientState(GL_VERTEX_ARRAY) glEndList() else: glColor3i(127, 127, 127) glCallList(test_dl) pass pass # NE1 with test toploop, # N column DL's around VBO/IBO shader/box buffer sphere calls (test case 6) # . 2,500 (50x50) spheres 58 FPS # . 10,000 (100x100) spheres 57 FPS # . 17,424 (132x132) spheres 56 FPS # . 40,000 (200x200) spheres 50 FPS # . 90,000 (300x300) spheres 28 FPS # . 160,000 (400x400) spheres 16.5 FPS # . 250,000 (500x500) spheres 3.2 FPS elif testCase == 6: if test_dls is None: print ("Test case 6, %d^2 spheres\n %s." % (nSpheres, "N col DL's around VBO/IBO shader/box buffer sphere calls")) # Wrap n display lists around the draws (one per column.) test_dls = glGenLists(nSpheres) # Returns ID of first DL in the set. test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] # Each column is relative to its bottom sphere location. Start # at the lower-left corner, offset so the whole pattern comes up # centered on the origin. start_pos = V(0, 0, 0) # So it doesn't get subtracted twice. pos = sphereLoc(x, 0) - V(nSpheres/2.0, nSpheres/2.0, 0) for y in range(nSpheres): centers += [sphereLoc(0, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.75 + t*.25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue test_sphere = GLSphereBuffer() test_sphere.addSpheres(centers, radii, colors, None, None) test_spheres += [test_sphere] glNewList(test_dls + x, GL_COMPILE_AND_EXECUTE) glPushMatrix() glTranslatef(pos[0], pos[1], pos[2]) test_sphere.draw() glPopMatrix() glEndList() continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) # Turn the lights on. for x in range(nSpheres): glCallList(test_dls + x) continue pass pass # NE1 with test toploop, # N column VBO sets of shader/box buffer sphere calls (test case 7) # . 2,500 (50x50) spheres 50 FPS # . 10,000 (100x100) spheres 30.5 FPS # . 17,424 (132x132) spheres 23.5 FPS # . 40,000 (200x200) spheres 16.8 FPS # . 90,000 (300x300) spheres 10.8 FPS # . 160,000 (400x400) spheres 9.1 FPS # . 250,000 (500x500) spheres 7.3 FPS elif testCase == 7: if test_spheres is None: print ("Test case 7, %d^2 spheres\n %s." % (nSpheres, "Per-column VBO/IBO chunk buffers")) test_spheres = [] for x in range(nSpheres): centers = [] radius = .5 radii = [] colors = [] for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.75 + t*.25) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] continue _spheres1 = GLSphereBuffer() _spheres1.addSpheres(centers, radii, colors, None, None) test_spheres += [_spheres1] continue pass else: shader = drawing_globals.test_sphereShader shader.configShader(glpane) for chunk in test_spheres: chunk.draw() pass # NE1 with test toploop, # Short chunk VBO sets of shader/box buffer sphere calls (test case 8) # . 625 (25x25) spheres 30 FPS, 79 chunk buffers of length 8. # . 2,500 (50x50) spheres 13.6 FPS, 313 chunk buffers of length 8. # . 10,000 (100x100) spheres 6.4 FPS, 704 chunk buffers of length 8. # . 10,000 (100x100) spheres 3.3 FPS, 1250 chunk buffers of length 8. # . 17,424 (132x132) spheres 2.1 FPS, 2178 chunk buffers of length 8. # . 2,500 (50x50) spheres 33.5 FPS, 105 chunk buffers of length 24. # . 17,424 (132x132) spheres 5.5 FPS, 726 chunk buffers of length 24. # # Subcase 8.1: CSDLs in a DrawingSet. (Initial pass-through version.) # . 2,500 (50x50) spheres 36.5 FPS, 105 chunk buffers of length 24. # . 5,625 (75x75) spheres 16.1 FPS, 235 chunk buffers of length 24. # . 10,000 (100x100) spheres 0.5 FPS?!, 414 chunk buffers of length 24. # Has to be <= 250 chunks for constant memory transforms? # . 10,000 (100x100) spheres 11.8 FPS, 50 chunk buffers of length 200. # After a minute of startup. # . 10,000 (100x100) spheres 9.3 FPS, 200 chunk buffers of length 50. # After a few minutes of startup. # Subcase 8.2: CSDLs in a DrawingSet with transforms. (Pass-through.) # . 10,000 (100x100) spheres 11.5 FPS, 50 chunk buffers of length 200. # # Subcase 8.1: CSDLs in a DrawingSet. (First HunkBuffer version.) # Measured with auto-rotate on, ignoring startup and occasional outliers. # As before, on a 2 core, 2.4 GHz Intel MacBook Pro with GeForce 8600M GT. # HUNK_SIZE = 10000 # . 2,500 (50x50) spheres 140-200 FPS, 105 chunks of length 24. # . 5,625 (75x75) spheres 155-175 FPS, 235 chunks of length 24. # . 10,000 (100x100) spheres 134-145 FPS, 50 chunks of length 200. # . 10,000 (100x100) spheres 130-143 FPS, 200 chunks of length 50. # . 10,000 (100x100) spheres 131-140 FPS, 1,250 chunks of length 8. # Chunks are gathered into hunk buffers, so no chunk size speed diff. # . 17,424 (132x132) spheres 134-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 131-140 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 20000 # . 17,424 (132x132) spheres 131-140 FPS, 88 chunks of length 200. # . 17,424 (132x132) spheres 130-141 FPS, 2,178 chunks of length 8. # HUNK_SIZE = 10000 # . 40,000 (200x200) spheres 77.5-82.8 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 34.9-42.6 FPS, 11,2500 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # Rotate the sphere-array off-axis 45 degrees to minimize. # (Try adding multi-sampled anti-aliasing, to the drawing test...) # . 160,000 (400x400) spheres 26.4-27.1 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.8-17.1 FPS, 31,250 chunks of length 8. # The pattern is getting too large, far-clipping is setting in. # . 360,000 (600x600) spheres 11.6-11.8 FPS, 45,000 chunks of length 8. # Extreme far-clipping in the drawing test pattern. # HUNK_SIZE = 20000; no significant speed-up. # . 40,000 (200x200) spheres 75.9-81.5 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 41.2-42.4 FPS, 11,250 chunks of length 8. # Spheres are getting down to pixel size, causing moire patterns. # . 160,000 (400x400) spheres 26.5-26.9 FPS, 20,000 chunks of length 8. # . 250,000 (500x500) spheres 16.5-17.1 FPS, 31,250 chunks of length 8. # . 360,000 (600x600) spheres 11.8-12.1 FPS, 45,000 chunks of length 8. # HUNK_SIZE = 5000; no significant slowdown or CPU load difference. # . 40,000 (200x200) spheres 81.0-83.8 FPS, 5,000 chunks of length 8. # . 160,000 (400x400) spheres 27.3-29.4 FPS, 20,000 chunks of length 8. # . 360,000 (600x600) spheres 11.7-12.1 FPS, 45,000 chunks of length 8. # # Retest after updating MacOS to 10.5.5, with TestGraphics, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 68.7-74.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 39.4-42.0 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 24.4-25.2 FPS, 20,000 chunks of length 8. # Retest with glMultiDrawElements drawing indexes in use, HUNK_SIZE = 5000 # . 40,000 (200x200) spheres 52.8-54.4 FPS, 5,000 chunks of length 8. # . 90,000 (300x300) spheres 22.8-23.3 FPS, 11,250 chunks of length 8. # . 160,000 (400x400) spheres 13.5-15.2 FPS, 20,000 chunks of length 8. # # Retest with reworked halo/sphere shader, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 52.8-53.7 FPS, 2,178 chunks of length 8. [60] # . 40,000 (200x200) spheres 29.3-30.4 FPS, 5,000 chunks of length 8.[156] # . 90,000 (300x300) spheres 18.2-19.2 FPS, 11,250 chunks of length 8.[381] # . 160,000 (400x400) spheres 10.2-11.6 FPS, 20,000 chunks of length 8.[747] # Billboard drawing patterns instead of cubes, HUNK_SIZE = 5000 [setup time] # . 17,424 (132x132) spheres 49.7-55.7 FPS, 2,178 chunks of length 8. [35] # . 40,000 (200x200) spheres 39.6-40.8 FPS, 5,000 chunks of length 8. [88] # . 90,000 (300x300) spheres 18.9-19.5 FPS, 11,250 chunks of length 8.[225] # . 160,000 (400x400) spheres 11.2-11.7 FPS, 20,000 chunks of length 8.[476] # elif int(testCase) == 8: doTransforms = False doCylinders = False if test_spheres is None: # Setup. print ("Test case 8, %d^2 primitives\n %s, length %d." % (nSpheres, "Short VBO/IBO chunk buffers", chunkLength)) if testCase == 8.1: print ("Sub-test 8.1, sphere chunks are in CSDL's in a DrawingSet.") test_DrawingSet = DrawingSet() elif testCase == 8.2: print ("Sub-test 8.2, spheres, rotate with TransformControls.") test_DrawingSet = DrawingSet() doTransforms = True elif testCase == 8.3: print ("Sub-test 8.3, cylinder chunks are in CSDL's in a DrawingSet.") test_DrawingSet = DrawingSet() doCylinders = True pass if test_DrawingSet: # note: doesn't happen in test 8.0, which causes a bug then. [bruce 090223 comment] print "constructed test_DrawingSet =", test_DrawingSet if USE_GRAPHICSMODE_DRAW: print ("Use graphicsMode.Draw_model for DrawingSet in paintGL.") pass t1 = time.time() if doTransforms: # Provide several TransformControls to test separate action. global numTCs, TCs numTCs = 3 TCs = [TransformControl() for i in range(numTCs)] pass def primCSDL(centers, radii, colors): if not doTransforms: csdl = ColorSortedDisplayList() # Transformless. else: # Test pattern for TransformControl usage - vertical columns # of TC domains, separated by X coord of first center point. # Chunking will be visible when transforms are changed. xCoord = centers[0][0] - start_pos[0] # Negate centering X. xPercent = (xCoord / (nSpheres + nSpheres/10 + nSpheres/100 - 1 + (nSpheres <= 1))) xTenth = int(xPercent * 10 + .5) csdl = ColorSortedDisplayList(TCs[xTenth % numTCs]) pass # Test selection using the CSDL glname. ColorSorter.pushName(csdl.glname) ColorSorter.start(glpane, csdl) for (color, center, radius) in zip(colors, centers, radii): if not doCylinders: # Through ColorSorter to the sphere primitive buffer... drawsphere(color, center, radius, DRAWSPHERE_DETAIL_LEVEL) else: # Through ColorSorter to cylinder primitive buffer... if not drawing_globals.cylinderShader_available(): print "warning: not cylinderShader_available(), error is likely:" if (True and # Whether to do tapered shader-cylinders. # Display List cylinders don't support taper. glpane.glprefs.cylinderShader_desired()): ###cylRad = (radius/2.0, (.75-radius)/2.0) cylRad = (radius/1.5 - .167, .3 - radius/1.5) else: cylRad = radius/2.0 pass endPt2 = center + V(0.5, 0.0, 0.0) # 0.5, -0.5) drawcylinder(color, center, endPt2, cylRad) global test_endpoints test_endpoints += [(center, endPt2)] pass continue ColorSorter.popName() ColorSorter.finish(draw_now = True) test_DrawingSet.addCSDL(csdl) return csdl if testCase == 8: #bruce 090223 revised to try to avoid traceback def chunkFn(centers, radii, colors): res = GLSphereBuffer() res.addSpheres(centers, radii, colors, None, None) return res pass else: chunkFn = primCSDL pass test_spheres = [] radius = .5 centers = [] radii = [] colors = [] global test_endpoints test_endpoints = [] for x in range(nSpheres): for y in range(nSpheres): centers += [sphereLoc(x, y)] # Sphere radii progress from 3/4 to full size. t = float(x+y)/(nSpheres+nSpheres) # 0 to 1 fraction. thisRad = radius * (.5 + t*.5) radii += [thisRad] # Colors progress from red to blue. colors += [rainbow(t)] # Put out short chunk buffers. if len(centers) >= chunkLength: test_spheres += [ chunkFn(centers, radii, colors) ] centers = [] radii = [] colors = [] continue continue # Remainder fraction buffer. if len(centers): test_spheres += [chunkFn(centers, radii, colors)] pass print "Setup time", time.time() - t1, "seconds." print "%d chunk buffers" % len(test_spheres) pass elif not initOnly: # Run. test_Draw_8x(glpane) pass elif testCase == 100: #bruce 090102 # before making more of these, modularize it somehow from commands.TestGraphics.test_selection_redraw import test_selection_redraw test_class = test_selection_redraw params = ( nSpheres, ) # note: test size is not directly comparable to other tests with same value of nSpheres if test_Object is None \ or not isinstance(test_Object, test_class) \ or test_Object.current_params() != params: # review: same_vals? # Setup. if test_Object: test_Object.destroy() test_Object = test_class(*params) test_Object.activate() print test_Object pass # review: safe to change elif to if? not sure, GL state is only initialized below elif not initOnly: # Run. test_Object.draw_complete() pass pass if not initOnly: glMatrixMode(GL_MODELVIEW) glFlush() pass first_time = False return