Pygame OpenGL 3D Cube Lag

后端 未结 1 1316
南方客
南方客 2021-01-23 16:31

I am following a tutorial series that is rather old on pyOpenGL and I am doing exactly as he does. However I am experiencing lag - I have AMD FX-6300 with 8gb ram, GTX-1050ti an

相关标签:
1条回答
  • 2021-01-23 17:13

    I have read some places that using glBegin and glEnd cause issues? What should I use instead ...

    Drawing by glBegin and glEnd is deprecated in modern OpenGL (see Fixed Function Pipeline and Legacy OpenGL). In modern OpenGL Vertices are Specified by Vertex Buffer Objects and Vertex Array Object and evrything is drawn using a Shader program.

    As a first step to this direction I recommend to use Vertex Buffer Objects and client-side capability

    See OpenGL 4.6 API Compatibility Profile Specification; 10.3.3 Specifying Arrays for Fixed-Function Attributes; page 402

    The commands

    void VertexPointer( int size, enum type, sizei stride, const void *pointer );
    void NormalPointer( enum type, sizei stride, const void *pointer );
    void ColorPointer( int size, enum type, sizei stride, const void *pointer );
    void SecondaryColorPointer( int size, enum type, sizei stride, const void *pointer );
    void IndexPointer( enum type, sizei stride, const void *pointer );
    void EdgeFlagPointer( sizei stride, const void *pointer );
    void FogCoordPointer( enum type, sizei stride, const void *pointer );
    void TexCoordPointer( int size, enum type, sizei stride, const void *pointer );
    

    specify the location and organization of arrays to store vertex coordinates, normals, colors, secondary colors, color indices, edge flags, fog coordinates.

    [...]

    An individual array is enabled or disabled by calling one of

    void EnableClientState( enum array );
    void DisableClientState( enum array );
    

    with array set to VERTEX_ARRAY, NORMAL_ARRAY, COLOR_ARRAY, SECONDARY_COLOR_ARRAY, INDEX_ARRAY, EDGE_FLAG_ARRAY, FOG_COORD_ARRAY, or TEXTURE_COORD_ARRAY, for the vertex, normal, color, secondary color, color index, edge flag, fog coordinate, or texture coordinate array, respectively.

    To do so you have to prepare and you have to include NumPy:

    import numpy
    

    Create global variables for the vertex buffer objects and create attribute sets (pairs of color and vertex coordinate) for the faces and create the vertex buffer objects for the faces (vertex coordinate and color). Finally create the vertex buffer object for the vertices coordinates of the edges:

    def main():
    
        global face_vbos, edge_vbo
    
        .....
    
        # define the vertex buffers vor the faces
    
        vertex_array = []
        color_array = []
        for face in range(len(surfaces)):
            for vertex in surfaces[face]:
                vertex_array .append( vertices[vertex] )
                color_array.append( colors[face] )
        
        face_vbos = glGenBuffers(2)
        glBindBuffer(GL_ARRAY_BUFFER, face_vbos[0])
        glBufferData( GL_ARRAY_BUFFER, numpy.array( vertex_array, dtype=numpy.float32 ), GL_STATIC_DRAW )
        glBindBuffer(GL_ARRAY_BUFFER, face_vbos[1])
        glBufferData( GL_ARRAY_BUFFER, numpy.array( color_array, dtype=numpy.float32 ), GL_STATIC_DRAW )
        glBindBuffer(GL_ARRAY_BUFFER, 0)
    
        # define the vertex buffer for the edges
        edge_vbo = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, edge_vbo)
        glBufferData( GL_ARRAY_BUFFER, numpy.array( vertices, dtype=numpy.float32 ), GL_STATIC_DRAW )
        glBindBuffer(GL_ARRAY_BUFFER, 0)
    
        while True:
    
            # [...]
    

    When you draw the faces and edges the you have define an array of vertex data (glVertexPointer ) and to define an array of colors (glColorPointer) to enable the client-side capability (glEnableClientState).
    The faces can be drawn by glDrawArrays, since all the coordinates a colors are stored in an consecutive array (vertex_array and color_array -> face_vbos ).
    The edges have to be drawn by glDrawElements, using the indices edges, since the vertices (vertices -> edge_vbo) have to be indexed to form lines:

    def Cube(veritces):
        
        global face_vbos, edge_vbo 
    
        # draw faces
        
        glBindBuffer(GL_ARRAY_BUFFER, face_vbos[0])
        glVertexPointer( 3, GL_FLOAT, 0, None )
        glEnableClientState( GL_VERTEX_ARRAY )  
        glBindBuffer(GL_ARRAY_BUFFER, face_vbos[1]) 
        glColorPointer( 3, GL_FLOAT, 0, None ) 
        glEnableClientState( GL_COLOR_ARRAY ) 
        glBindBuffer(GL_ARRAY_BUFFER, 0) 
    
        glDrawArrays(GL_QUADS, 0, 6*4)
    
        glDisableClientState( GL_VERTEX_ARRAY )   
        glDisableClientState( GL_COLOR_ARRAY ) 
        
        #draw edges
    
        glBindBuffer(GL_ARRAY_BUFFER, edge_vbo)
        glVertexPointer( 3, GL_FLOAT, 0, None ) 
        glEnableClientState( GL_VERTEX_ARRAY ) 
        glBindBuffer(GL_ARRAY_BUFFER, 0) 
    
        glColor3f( 1, 1, 0 )
        glDrawElements(GL_LINES, 2*12, GL_UNSIGNED_INT, numpy.array( edges, dtype=numpy.uint32 ))
    
        glDisableClientState( GL_VERTEX_ARRAY )  
    

    This can be further improved by using Vertex Array Objects and an Index buffer for the edges:

    def main():
    
        global face_vao, edge_vao
    
        # [...]
    
        # define the vertex buffers vor the faces
    
        attribute_array = []
        for face in range(len(surfaces)):
            for vertex in surfaces[face ]:
                attribute_array.append( vertices[vertex] )
                attribute_array.append( colors[face] )
        
        face_vbos = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, face_vbos)
        glBufferData( GL_ARRAY_BUFFER, numpy.array( attribute_array, dtype=numpy.float32 ), GL_STATIC_DRAW )
        glBindBuffer(GL_ARRAY_BUFFER, 0)
    
        # define the vertex array object for the faces
    
        face_vao = glGenVertexArrays( 1 )
        glBindVertexArray( face_vao )
    
        glBindBuffer(GL_ARRAY_BUFFER, face_vbos)
        glVertexPointer( 3, GL_FLOAT, 6*4, None )
        glEnableClientState( GL_VERTEX_ARRAY )  
        glColorPointer( 3, GL_FLOAT, 6*4, ctypes.cast(3*4, ctypes.c_void_p) )
        glEnableClientState( GL_COLOR_ARRAY ) 
        glBindBuffer(GL_ARRAY_BUFFER, 0) 
        
        glBindVertexArray( 0 )
    
        # define the vertex buffer for the edges
    
        edge_vbo = glGenBuffers(1)
        glBindBuffer(GL_ARRAY_BUFFER, edge_vbo)
        glBufferData( GL_ARRAY_BUFFER, numpy.array( vertices, dtype=numpy.float32 ), GL_STATIC_DRAW )
        glBindBuffer(GL_ARRAY_BUFFER, 0)
    
        # define the vertex array object for the edges
    
        edge_vao = glGenVertexArrays( 1 )
        glBindVertexArray( edge_vao )
    
        glBindBuffer(GL_ARRAY_BUFFER, edge_vbo)
        glVertexPointer( 3, GL_FLOAT, 0, None ) 
        glEnableClientState( GL_VERTEX_ARRAY ) 
        glBindBuffer(GL_ARRAY_BUFFER, 0) 
    
        edge_ibo = glGenBuffers(1)
        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, edge_ibo )
        glBufferData( GL_ELEMENT_ARRAY_BUFFER, numpy.array( edges, dtype=numpy.uint32 ), GL_STATIC_DRAW )
    
        glBindVertexArray( 0 )
        glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 )
    
        while True:
    
            # [...]
    
    def Cube(veritces):
        
        global face_vao, edge_vao
    
        # draw faces
        
        glBindVertexArray( face_vao )
        glDrawArrays( GL_QUADS, 0, 6*4 )
        glBindVertexArray( 0 )
        
        #draw edges
    
        glColor3f( 1, 1, 0 )
        glBindVertexArray( edge_vao )
        glDrawElements( GL_LINES, 2*12, GL_UNSIGNED_INT, None )
        glBindVertexArray( 0 )
    

    An further performance imporvement you can gain by Face Culling and enbaling the Depth Test. The depth test should be less or eauel, so that the edges are not covered by the faces:

    # enable depth test (less or equal)
    glEnable( GL_DEPTH_TEST )
    glDepthFunc( GL_LEQUAL )
    
    # enable back face culling (front faces are drawn clockwise)
    glEnable( GL_CULL_FACE )
    glCullFace( GL_BACK )
    glFrontFace( GL_CW )
    

    Note, the last step to draw geometry in a "modern" way in OpenGL would be to use a Shader program and to replace glEnableClientState by glEnableVertexAttribArray and glVertexPointer respectively glColorPointer by glVertexAttribPointer (of course by using the proper parameters).

    See also PyGame and OpenGL 4.

    0 讨论(0)
提交回复
热议问题