Pygame OpenGL 3D Cube Lag - PullRequest
       14

Pygame OpenGL 3D Cube Lag

0 голосов
/ 13 мая 2018

Я слежу за серией руководств, которая довольно старая на pyOpenGL, и делаю именно так, как он.Однако я испытываю задержку - у меня AMD FX-6300 с 8 Гб оперативной памяти, GTX-1050ti и файлы хранятся на флэш-накопителе.Я читал некоторые места, где использование glBegin и glEnd вызывает проблемы?Что я должен использовать вместо этого и как бы я сделал это в этом коде:

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

Учебное пособие здесь

Спасибо !!

1 Ответ

0 голосов
/ 13 мая 2018

Я читал некоторые места, где использование glBegin и glEnd вызывает проблемы?Что я должен использовать вместо ...

Рисование glBegin и glEnd устарело в современном OpenGL (см. Конвейер с фиксированными функциями и Legacy OpenGL ).В современном OpenGL Вершины задаются с помощью Объекты буфера вершин и Объект массива вершин , и все отрисовывается с помощью шейдерной программы .

В качестве первого шага в этом направлении я рекомендую использовать Объекты буфера вершин и возможности на стороне клиента

См. Спецификация профиля совместимости API OpenGL 4.6;10.3.3. Задание массивов для атрибутов с фиксированными функциями;стр. 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_ARRAY, NORMAL_ARRAY,COLOR_ARRAY, SECONDARY_COLOR_ARRAY, INDEX_ARRAY, EDGE_FLAG_ARRAY, FOG_COORD_ARRAY или TEXTURE_COORD_ARRAY для вершины, нормали, цвета, вторичного цвета, индекса цвета, флага края, координаты тумана или массива координат текстуры,соответственно.

Для этого вам нужно подготовиться и включить NumPy :

import numpy

Создать глобальные переменные для объектов буфера вершин

global face_vbos, edge_vbo

Создать наборы атрибутов (пары цвета и координаты вершины) для граней и создания объектов буфера вершин для граней (координата вершины и цвет).Наконец, создайте объект буфера вершин для координат вершин ребер:

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_array и color_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 )  


Это можно улучшить, используя Объекты массива вершин и Индексный буфер для краев:

global face_vao, edge_vao

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 )


Дальнейшее улучшение производительности вы можете получить с помощью Отбор лица и добавление теста Глубина .Тест на глубину должен быть меньше или краем, чтобы края не были закрыты гранями:

# 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 и замена glEnableClientState на glEnableVertexAttribArray и glVertexPointer соответственно glColorPointer glVertexAttribPointer (конечно, используя правильные параметры).

...