[英]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?我读过一些使用glBegin
和glEnd
会导致问题的地方? 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()
Thanks!!谢谢!!
I have read some places that using
glBegin
andglEnd
cause issues?我读过一些使用glBegin
和glEnd
会导致问题的地方? What should I use instead ...我应该用什么代替...
Drawing by glBegin
and glEnd
is deprecated in modern OpenGL (see Fixed Function Pipeline and Legacy OpenGL ).在现代 OpenGL 中不推荐使用glBegin
和glEnd
(请参阅固定功能管道和旧版 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
, orTEXTURE_COORD_ARRAY
, for the vertex, normal, color, secondary color, color index, edge flag, fog coordinate, or texture coordinate array, respectively.数组设置为VERTEX_ARRAY
、NORMAL_ARRAY
、COLOR_ARRAY
、SECONDARY_COLOR_ARRAY
、INDEX_ARRAY
、EDGE_FLAG_ARRAY
、FOG_COORD_ARRAY
或TEXTURE_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_array
和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:边必须由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中“现代”的方法是使用着色器程序,并更换glEnableClientState
由glEnableVertexAttribArray
和glVertexPointer
分别glColorPointer
通过glVertexAttribPointer
(通过使用合适的参数,当然)。
See also PyGame and OpenGL 4 .另请参阅PyGame 和 OpenGL 4 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.