有没有一种方法可以更快地渲染点OpenGL

时间:2019-06-27 08:33:58

标签: python opengl pygame pyopengl opengl-compat

我需要在openGL中可视化大约50k-60k点,我设法将它们全部打印出来,但是当我使用旋转时,每次旋转之间需要花费很多时间,因为它只在每一帧中打印所有数据。 有没有一种方法可以一次打印所有数据并冻结数据的导入,以便保留图像但停止处理?

def PointClouds(pcd_files): #pcd_file
   glBegin(GL_POINTS)
   for i in pcd_files:
       pc = pypcd.PointCloud.from_path(i)
       number_of_points = pc.get_metadata().get('points')
       z = pc.pc_data['z']
       x = pc.pc_data['x']
       y = pc.pc_data['y']
       for j in range(number_of_points):
           glVertex3f(x[j], y[j], z[j])
   glEnd()

主要是:

files = glob.glob(os.getcwd() + "\\" + PCD_OutPutDirectory + "\*.pcd")

pygame.init()
display = (1700, 1000)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
gluPerspective(50, (display[0] / display[1]), 0.1, 5000)
glTranslatef(0, 0, -1000)
Clock = pygame.time.Clock()
while True:
    Clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
    glRotatef(2, 1, 1, 3)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    PointClouds(files)
    pygame.display.flip()

打印所有点,但每次旋转之间会遍历所有点并再次打印它们,因为有60k +点,每次旋转之间花费太多时间。我只需要读取点一次并冻结图像而不旋转。 谢谢你的帮助

1 个答案:

答案 0 :(得分:3)

瓶颈是for循环和glBegin / glEnd序列。从每一帧的文件中读取数据。 注意,几十年来,不赞成使用glBegin/glEnd序列和固定函数矩阵堆栈进行绘制。 在启动时读取一次文件,然后创建一个Vertex Buffer Object。 (阅读有关Vertex SpecificationShader的更多信息,以了解最新的渲染方式。)

与您现有代码最接近的解决方案是使用客户端功能glEnableClientState和固定功能属性glVertexPointer。使用此解决方案,您不需要任何着色器程序。
在下文中,我假设您使用PyOpenGL

将顶点坐标加载到数组

def LoadVertices(pcd_files):
    vertices = []
    for i in pcd_files:
       pc = pypcd.PointCloud.from_path(i)
       number_of_points = pc.get_metadata().get('points')
       z = pc.pc_data['z']
       x = pc.pc_data['x']
       y = pc.pc_data['y']
       for j in range(number_of_points):
           vertices += [x[j], y[j], z[j]]
    return vertices

创建一个Vertex Buffer Object并创建并初始化缓冲区对象的数据存储:

import ctypes
def CreateBuffer(vertices):
    bufferdata = (ctypes.c_float*len(vertices))(*vertices) # float buffer
    buffersize = len(vertices)*4                           # buffer size in bytes 

    vbo = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glBufferData(GL_ARRAY_BUFFER, buffersize, bufferdata, GL_STATIC_DRAW) 
    glBindBuffer(GL_ARRAY_BUFFER, 0)
    return vbo

创建一个可以从缓冲区绘制Point primitives的函数:

def DrawBuffer(vbo, noOfVertices):
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glEnableClientState(GL_VERTEX_ARRAY)
    glVertexPointer(3, GL_FLOAT, 0, None)

    glDrawArrays(GL_POINTS, 0, noOfVertices)

    glDisableClientState(GL_VERTEX_ARRAY)
    glBindBuffer(GL_ARRAY_BUFFER, 0)

在程序中使用此功能:

files = glob.glob(os.getcwd() + "\\" + PCD_OutPutDirectory + "\*.pcd")

pygame.init()
display = (1700, 1000)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

vArray    = LoadVertices(files)
noPoints  = len(vArray) // 3
bufferObj = CreateBuffer(vArray)

gluPerspective(50, (display[0] / display[1]), 0.1, 5000)
glTranslatef(0, 0, -1000)
Clock = pygame.time.Clock()
while True:
    Clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
    glRotatef(2, 1, 1, 3)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    DrawBuffer(bufferObj, noPoints)

    pygame.display.flip()

如果您要为每个点添加单独的颜色,那么顶点及其属性不仅包含坐标(x, y, z),还必须包含RGB color (x, y, z, r, g, b),因此每个属性元组由6个组成部分组成,而不是3个组成部分。

固定功能color属性必须由客户端状态GL_COLOR_ARRAY启用。添加属性由glColorPointer指定。

每个属性元组的大小为24个字节,因为元组包含6个组成部分(x, y, z, r, g, b),每个组成部分的大小为4个字节(这是float的大小)。
该大小必须分别传递到sride的第三参数(glVertexPointerglColorPointer

如果绑定了已命名的缓冲区对象,则glVertexPointerglColorPointer的最后一个参数将被视为缓冲区对象缓冲区存储区中的字节偏移量。偏移量是到属性的第一部分的字节数。
glVertexPointer的情况下,偏移量为0,因为(x, y, z)是属性元组中的第一部分。 在glColorPointer的情况下,偏移量为3 * 4 = 12字节,因为(r, g, b)在3个坐标(x, y, z)之后,并且每个分量的大小为4。 由于最后一个参数的类型是指针,因此必须将偏移量强制转换为ctypes.c_void_p(例如ctypes.c_void_p(3*4))。为此,必须导入python内置库ctypes。如果偏移量为0,则可以使用None代替ctypes.c_void_p(0)

顶点属性的规范可能看起来像这样:

glBindBuffer(GL_ARRAY_BUFFER, vbo)

stride = 6*4 # (24 bates) : [x, y, z, r, g, b] * sizeof(float)

glEnableClientState(GL_VERTEX_ARRAY)
glVertexPointer(3, GL_FLOAT, stride, None)

glEnableClientState(GL_COLOR_ARRAY)
offset = 3*4 # (12 bytes) : the rgb color starts after the 3 coordinates x, y, z 
glColorPointer(3, GL_FLOAT, stride, ctypes.c_void_p(offset))

一起:

import ctypes 

def LoadVertices(pcd_files):
    attributes = []
    for i in pcd_files:
       pc = pypcd.PointCloud.from_path(i)
       number_of_points = pc.get_metadata().get('points')
       z = pc.pc_data['z']
       x = pc.pc_data['x']
       y = pc.pc_data['y']
       r = # set the RGB color data here
       g =
       b = 
       for j in range(number_of_points):
           attributes += [x[j], y[j], z[j], r[j], g[j], b[j]]
    return attributes

def CreateBuffer(attributes):
    bufferdata = (ctypes.c_float*len(attributes))(*attributes) # float buffer
    buffersize = len(attributes)*4                             # buffer size in bytes 

    vbo = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glBufferData(GL_ARRAY_BUFFER, buffersize, bufferdata, GL_STATIC_DRAW) 
    glBindBuffer(GL_ARRAY_BUFFER, 0)
    return vbo

def DrawBuffer(vbo, noOfVertices):
    glBindBuffer(GL_ARRAY_BUFFER, vbo)

    stride = 6*4 # (24 bates) : [x, y, z, r, g, b] * sizeof(float)

    glEnableClientState(GL_VERTEX_ARRAY)
    glVertexPointer(3, GL_FLOAT, stride, None)

    glEnableClientState(GL_COLOR_ARRAY)
    offset = 3*4 # (12 bytes) : the rgb color starts after the 3 coordinates x, y, z 
    glColorPointer(3, GL_FLOAT, stride, ctypes.c_void_p(offset))

    glDrawArrays(GL_POINTS, 0, noOfVertices)

    glDisableClientState(GL_VERTEX_ARRAY)
    glDisableClientState(GL_COLOR_ARRAY)
    glBindBuffer(GL_ARRAY_BUFFER, 0)
files = glob.glob(os.getcwd() + "\\" + PCD_OutPutDirectory + "\*.pcd")

pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

vArray    = LoadVertices(files)
noPoints  = len(vArray) // 6  # 6 components per attribute tuple
bufferObj = CreateBuffer(vArray)

gluPerspective(50, (display[0] / display[1]), 0.1, 5000)
glTranslatef(0, 0, -1000)
Clock = pygame.time.Clock()
while True:
    Clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
    glRotatef(2, 1, 1, 3)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    DrawBuffer(bufferObj, noPoints)

    pygame.display.flip()
相关问题