Pygame OpenGL 3D多维数据集滞后 [英] Pygame OpenGL 3D Cube Lag
问题描述
我正在关注pyOpenGL上的一个相当老的教程系列,我的工作完全和他一样.但是我遇到了滞后-我的AMD FX-6300带有8GB内存,GTX-1050ti,文件存储在闪存驱动器上.我已经阅读了一些使用 glBegin
和 glEnd
引起问题的地方?我应该改用什么,以及如何在此代码中完成该操作:
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 and files are stored on a flashdrive. I have read some places that using glBegin
and glEnd
cause issues? 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()
该教程是此处
谢谢!
推荐答案
我已经阅读了一些使用
glBegin
和glEnd
引起问题的地方?我应该改用什么...
I have read some places that using
glBegin
andglEnd
cause issues? What should I use instead ...
在现代OpenGL中不建议使用 glBegin
和 glEnd
进行绘制(请参见固定功能管道和旧版OpenGL ).在现代OpenGL中,指定了顶点顶点缓冲区对象和顶点数组对象然后使用 Shader程序绘制每个图像.
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
请参见 OpenGL 4.6 API兼容性配置文件规范;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 );
指定数组的位置和组织,以存储顶点坐标,法线,颜色,辅助颜色,颜色索引,边缘标志,雾坐标.
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 );
数组设置为 VERTEX_ARRAY
, NORMAL_ARRAY
, COLOR_ARRAY
, SECONDARY_COLOR_ARRAY
, INDEX_ARRAY
>, EDGE_FLAG_ARRAY
, FOG_COORD_ARRAY
或 TEXTURE_COORD_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.
为此,您必须准备并且必须包含 NumPy :
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:
# [...]
在绘制面和边时,您已经定义了一组顶点数据( glColorPointer
)启用客户端功能( glEnableClientState
).
可以通过 glDrawArrays
来绘制面孔,因为所有坐标的颜色都存储在其中连续数组( vertex_array
和 color_array
-> face_vbos
).
边缘必须通过 glDrawElements
,使用索引 edges
,因为必须将顶点(顶点
-> edge_vbo
)编入索引以形成线:
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 )
通过面部剔除,您可以进一步提高性能并加入深度测试.深度测试应小于或等于eauel,以使边缘不会被面孔覆盖:
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 )
请注意,以现代"图形绘制几何图形的最后一步.OpenGL中的一种方式是使用 Shader程序并将 glEnableClientState
分别替换为 glEnableVertexAttribArray
和 glVertexPointer
并将 glColorPointer
替换为 glVertexAttribPointer
(当然使用适当的参数).
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).
另请参见 PyGame和OpenGL 4 .
这篇关于Pygame OpenGL 3D多维数据集滞后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!