有没有办法更快地渲染点 OpenGL [英] is there a way to render points faster OpenGL

查看:70
本文介绍了有没有办法更快地渲染点 OpenGL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

i need to visualize around 50k-60k points in openGL i managed to print them all but when i use rotate it takes so much time between each rotation because it just prints all the data every single frame. is there a way to print all the data once and freeze the importing of the data so it will keep the image but stop processing?

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+ 个点需要太多时间.我需要它只读取一次点并冻结图像而不是旋转.感谢帮助

prints all the points but between each rotation goes over all of the points and prints them again because there are 60k+ points it takes too much time between each rotation. i need it to read the points only once and freeze the image and not the rotation. thanks for the help

推荐答案

瓶颈是 for 循环和 glBegin/glEnd 序列.从每一帧的文件中读取数据.请注意,使用 glBegin/glEnd 序列和固定函数矩阵堆栈已被弃用数十年.在启动时读取文件并创建一个顶点缓冲对象.(阅读更多关于 Vertex SpecificationShader 以获得最先进的渲染方式.)

The bottleneck is the for loop and the glBegin/glEnd sequence. The data is read from the files in every frame. Note, that drawing by using glBegin/glEnd sequences and the fixed function matrix stack is deprecated since decades. Read the files once at start up and create a Vertex Buffer Object. (Read more about Vertex Specification and Shader for a state-of-the-art way of rendering.)

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

The closest solution to your existing code is to use client side capability glEnableClientState and fixed function attributes glVertexPointer. With this solution you don't need any shader program.
In the following I assume that you use PyOpenGL.

将顶点坐标加载到数组中

Load the vertex coordinates to an array

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

创建一个顶点缓冲对象并创建和初始化缓冲对象的数据商店:

Create a Vertex Buffer Object and create and initialize the buffer object's data store:

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

创建一个可以从缓冲区中绘制点原语的函数:

Create a function which can draw the Point primitives from the buffer:

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)

在你的程序中使用这个函数:

Use this functions in your program:

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 颜色 (x, y, z, r, g, b),因此每个属性元组由 6 个组件组成,而不是 3 个.


If you wnat to add individual colors for each point, then vertex and its attribute doesn't only consists of the coordinates (x, y, z), it also has to have to RGB color (x, y, z, r, g, b), so each attribute tuple consists of 6 components rather than 3.

固定功能颜色属性必须由客户端状态GL_COLOR_ARRAY启用.添加属性由glColorPointer.

The fixed function color attribute has to be enabled by the client state GL_COLOR_ARRAY. Add the attribute is specified by glColorPointer.

每个属性元组的大小为 24 字节,因为元组由 6 个分量 (x, y, z, r, g, b) 组成,每个分量的大小为 4 个字节(这是float的大小).
这个大小必须分别传递给 glVertexPointer 的第三个参数(sride)glColorPointer.

Each attribute tuple has a size of 24 bytes, because a tuple consits of 6 components (x, y, z, r, g, b) and each component has a size of 4 bytes (this is the size of float).
This size has to be passed to 3rd parameter (sride) of glVertexPointer respectively glColorPointer.

如果绑定了一个命名的缓冲区对象,那么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).

If a named buffer object is bound, then the last parameter of glVertexPointer respectively glColorPointer is treated as byte offset into the buffer objects buffer store. The offset is the number of bytes to the 1st component of the attribute.
In case of glVertexPointer the offset is 0, because (x, y, z) are the first components in the attribute tuple. In case of glColorPointer the offset is 3*4=12 bytes, because (r, g, b) are after the 3 coordinates (x, y, z) and the size of each component is 4. Since the type of the last parameter is a pointer, the offset has to be casted to ctypes.c_void_p (e.g. ctypes.c_void_p(3*4)). For this python built-in library ctypes has to be imported. If the offset is 0, None can be used instead of ctypes.c_void_p(0).

顶点属性的规范可能如下所示:

The specification of the vertex attribtes may lookslike this:

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

这篇关于有没有办法更快地渲染点 OpenGL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆