简体   繁体   English

Pygame OpenGL 3D 立方体滞后

[英]Pygame OpenGL 3D Cube Lag

I am following a tutorial series that is rather old on pyOpenGL and I am doing exactly as he does.我正在关注一个在 pyOpenGL 上相当古老的教程系列,我正在按照他的方式做。 However I am experiencing lag - I have AMD FX-6300 with 8gb ram, GTX-1050ti and files are stored on a flashdrive.但是我遇到了延迟 - 我有带 8gb 内存的 AMD FX-6300、GTX-1050ti,文件存储在闪存驱动器上。 I have read some places that using glBegin and glEnd cause issues?我读过一些使用glBeginglEnd会导致问题的地方? What should I use instead and how would I do it in this code:我应该使用什么来代替以及如何在此代码中执行此操作:

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

The tutorial is here教程在这里

Thanks!!谢谢!!

I have read some places that using glBegin and glEnd cause issues?我读过一些使用glBeginglEnd会导致问题的地方? What should I use instead ...我应该用什么代替...

Drawing by glBegin and glEnd is deprecated in modern OpenGL (see Fixed Function Pipeline and Legacy OpenGL ).在现代 OpenGL 中不推荐使用glBeginglEnd (请参阅固定功能管道旧版 OpenGL )。 In modern OpenGL Vertices are Specified by Vertex Buffer Objects and Vertex Array Object and evrything is drawn using a Shader program .在现代 OpenGL 中,顶点顶点缓冲区对象顶点数组对象指定,并且所有内容都是使用着色器程序绘制的。

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;请参阅OpenGL 4.6 API 兼容性配置文件规范; 10.3.3 Specifying Arrays for Fixed-Function Attributes; 10.3.3 为固定函数属性指定数组; page 402 第 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.数组设置为VERTEX_ARRAYNORMAL_ARRAYCOLOR_ARRAYSECONDARY_COLOR_ARRAYINDEX_ARRAYEDGE_FLAG_ARRAYFOG_COORD_ARRAYTEXTURE_COORD_ARRAY 、法线边缘、雾化索引、颜色坐标、顶点颜色坐标、顶点颜色坐标、顶点颜色坐标。

To do so you have to prepare and you have to include NumPy :为此,您必须做好准备并且必须包含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 ).当您绘制面和边时,您已经定义了一个顶点数据数组 ( glVertexPointer ) 并定义了一个颜色数组 ( glColorPointer ) 以启用客户端功能 ( 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 ).面可以通过glDrawArrays绘制,因为颜色的所有坐标都存储在一个连续的数组中( vertex_arraycolor_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:边必须由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 )  

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 .您可以通过Face Culling和 Enbaling Depth Test获得进一步的性能改进。 The depth test should be less or eauel, so that the edges are not covered by the faces:深度测试应该是 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 )

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).请注意,最后一步绘制几何在OpenGL中“现代”的方法是使用着色器程序,并更换glEnableClientStateglEnableVertexAttribArrayglVertexPointer分别glColorPointer通过glVertexAttribPointer (通过使用合适的参数,当然)。

See also PyGame and OpenGL 4 .另请参阅PyGame 和 OpenGL 4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM