【问题标题】:Pygame OpenGL 3D Cube LagPygame OpenGL 3D 立方体滞后
【发布时间】:2020-12-30 03:53:44
【问题描述】:

我正在关注 pyOpenGL 上相当古老的教程系列,并且我正在按照他的方式进行操作。但是我遇到了延迟——我有 AMD FX-6300 和 8gb 内存,GTX-1050ti 并且文件存储在闪存驱动器上。我读过一些使用glBeginglEnd 会导致问题的地方?我应该改用什么以及如何在这段代码中使用:

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import random

"""
- A Cube has 8 Nodes/Verticies
- 12 Lines/connections
- 6 Sides
"""


vertices = (
    (1, -1, -1),
    (1, 1, -1),
    (-1, 1, -1),
    (-1, -1, -1),
    (1, -1, 1),
    (1, 1, 1),
    (-1, -1, 1),
    (-1, 1, 1)
)

edges = ( #Contains vertexes/nodes
    (0, 1),
    (0, 3),
    (0, 4),
    (2, 1),
    (2, 3),
    (2, 7),
    (6, 3),
    (6, 4),
    (6, 7),
    (5, 1),
    (5, 4),
    (5, 7)
)

surfaces = (
    (0,1,2,3),
    (3,2,7,6),
    (6,7,5,4),
    (4,5,1,0),
    (1,5,7,2),
    (4,0,3,6),
)

colors = (
    (1,0,0),
    (0,1,0),
    (0,0,1),
    (0,0,0,),
    (1,1,1),
    (0,1,1),
    (1,0,0),
    (0,1,0),
    (0,0,1),
    (0,0,0,),
    (1,1,1),
    (0,1,1),    
)

def set_vertices(max_distance):
    #Create change between each cube
    x_value_change = random.randrange(-10, 10)
    y_value_change = random.randrange(-10, 10)
    z_value_change = random.randrange(-1 * max_distance, -20)

    new_vertices = []

    for vert in vertices: 
        new_vert = []

        new_x = vert[0] + x_value_change
        new_y = vert[1] + y_value_change
        new_z = vert[2] + z_value_change

        new_vert.append(new_x)
        new_vert.append(new_y)
        new_vert.append(new_z)

        new_vertices.append(new_vert) #Appends (1, 1, 1)
    return new_vertices

def Cube(veritces):
    glBegin(GL_QUADS)
    for surface in surfaces:
        x = 0
        for vertex in surface:
            x += 1
            glColor3fv((colors[x]))
            glVertex3fv(vertices[vertex])
    glEnd()

    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(vertices[vertex]) #Draws vertex's in position given according to vertices array
    glEnd()


def main():
    pygame.init()
    display = (1000, 800)
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL)

    gluPerspective(45, (display[0]/display[1]), 0.1, 50.0) #FOV, aspect ratio. clipping plane min, max

    glTranslatef(random.randrange(-5, 5), random.randrange(-5, 5), -40) #X,Y,Z -5 to zoom out on z axis
    #glRotatef(25, 1, 20, 0) #Degrees, x,y,z

    object_passed = False


    max_distance = 300
    cube_dict = {}

    for x in range(75): #Draws 75 cubes
        cube_dict[x] = set_vertices(max_distance) #Returns a new cube set of vertices

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    x_move = 0.3
                if event.key == pygame.K_RIGHT:
                    x_move = -0.3
                if event.key == pygame.K_UP:
                    y_move = -0.3
                if event.key == pygame.K_DOWN:
                    y_move = 0.3
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
                    x_move = 0
                if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
                    y_move = 0     
                    """
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 4:
                    glTranslatef(0, 0, 1)
                if event.button == 5:
                    glTranslatef(0, 0, -1)
                    """

        #glRotatef(1, 1, 1, 1)

        x = glGetDoublev(GL_MODELVIEW_MATRIX)

        camera_x = x[3][0] #Access camera cordinates
        camera_y = x[3][1]
        camera_z = x[3][2]



        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) #Clears the screen

        glTranslatef(x_move, y_move, 0.5)

        for each_cube in cube_dict:
            Cube(cube_dict[each_cube])

        pygame.display.flip() #Cant use update
        pygame.time.wait(10)



main()

pygame.quit()
quit()

教程是here

谢谢!!

【问题讨论】:

    标签: python pygame lag pyopengl


    【解决方案1】:

    我读过一些使用glBeginglEnd 会导致问题的地方?我应该改用什么...

    在现代 OpenGL 中不推荐使用 glBeginglEnd 绘图 (见Fixed Function PipelineLegacy OpenGL)。 在现代 OpenGL Vertices are SpecifiedVertex Buffer ObjectsVertex Array Object 并且所有东西都是使用Shader program 绘制的。

    作为朝着这个方向迈出的第一步,我建议使用Vertex Buffer Objects 和客户端功能

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

    命令

    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 );
    

    指定数组的位置和组织以存储顶点坐标、法线、颜色、辅助颜色、颜色索引、边缘标志、雾坐标。

    [...]

    通过调用其中一个来启用或禁用单个数组

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

    数组设置为VERTEX_ARRAYNORMAL_ARRAYCOLOR_ARRAYSECONDARY_COLOR_ARRAYINDEX_ARRAYEDGE_FLAG_ARRAYFOG_COORD_ARRAYTEXTURE_COORD_ARRAY,用于顶点、法线、颜色、辅助颜色、颜色索引、边缘标志、雾坐标或纹理坐标数组。

    为此,您必须做好准备,并且必须包含NumPy

    import numpy
    

    为顶点缓冲区对象创建全局变量并为面创建属性集(颜色和顶点坐标对)并为面创建顶点缓冲区对象(顶点坐标和颜色)。 最后为边的顶点坐标创建顶点缓冲对象:

    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:
    
            # [...]
    

    当您绘制面和边时,您已经定义了一个顶点数据数组 (glVertexPointer ) 并定义一组颜色 (glColorPointer) 启用客户端功能 (glEnableClientState)。
    面可以由glDrawArrays 绘制,因为颜色的所有坐标都存储在其中 一个连续的数组(vertex_arraycolor_array -> face_vbos )。
    边缘必须由glDrawElements 绘制,使用索引edges, 因为顶点 (vertices -> edge_vbo) 必须被索引以形成线条:

    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 )  
    

    这可以通过使用Vertex Array Objects 进一步改进 和一个Index buffer 的边缘:

    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 )
    

    Face Culling 可以进一步提高性能 并启用Depth Test。 深度测试应该是less或eauel,这样边缘就不会被面覆盖:

    # 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 )
    

    注意,在 OpenGL 中以“现代”方式绘制几何图形的最后一步是使用 Shader program 和 将glEnableClientState 替换为glEnableVertexAttribArrayglVertexPointer 分别将glColorPointer 替换为glVertexAttribPointer (当然是通过使用适当的参数)。

    另见PyGame and OpenGL 4

    【讨论】:

    • 再次感谢@Rabbid76。非常深入和信息丰富,给你最高评价!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 1970-01-01
    相关资源
    最近更新 更多