Nano Hash - криптовалюты, майнинг, программирование

есть ли способ рендерить точки быстрее OpenGL

мне нужно визуализировать около 50k-60k точек в openGL, мне удалось напечатать их все, но когда я использую поворот, между каждым поворотом требуется так много времени, потому что он просто печатает все данные в каждом отдельном кадре. есть ли способ распечатать все данные один раз и заморозить импорт данных, чтобы он сохранил изображение, но прекратил обработку?

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

печатает все точки, но между каждым вращением проходит по всем точкам и печатает их снова, потому что существует более 60 тысяч точек, между каждым вращением требуется слишком много времени. мне нужно, чтобы он считывал точки только один раз и замораживал изображение, а не вращение. Спасибо за помощь


  • Рисование последовательностями glBegin/glEnd и матричный стек с фиксированной функцией устарел уже несколько десятилетий. См. Конвейер фиксированных функций и Устаревший OpenGL. Прочтите об спецификации вершин и Shader для современного способа рендеринга. 27.06.2019
  • В случае, если предложения @Rabbid76 не могут быть применены (например, потому что вы ограничены старой версией), можете ли вы просто добавить логическое значение, которое изменяется после того, как вы напечатаете данные, а также условие, которое запускает повторную печать на основе логического значения? 27.06.2019
  • @MarkusDeibel Почему он ограничен старой версией? Я не вижу причин для этого. 27.06.2019
  • Возможно, по какой-то причине застрял в очень старой системе ¯\_(ツ)_/¯ 27.06.2019
  • @MarkusDeibel Хорошо, может быть. Но узким местом является цикл for и последовательность glBegin/glEnd. Даже в старой системе буферы могут использоваться благодаря возможностям на стороне клиента и фиксированным атрибутам функций. См. glEnableClientState и glVertexPointer . 27.06.2019
  • @ Rabbid76 Итак, какой метод рендеринга самый эффективный? 27.06.2019
  • @Noah Поместите все в буферы вершин при инициализации (старайтесь использовать большие буферы, а не чем множество крошечных буферов). Создавайте как можно меньше шейдеров (старайтесь использовать 1 шейдер). Постарайтесь изменить как можно меньше состояний в цикле рендеринга и попытаться отрендерить как можно больше мешей с одним и тем же шейдером подряд. Старайтесь избегать изменений буфера вершин, просто меняйте юниформы, как и матрицу модели. 27.06.2019
  • Как вы вращаетесь? надеюсь, вы используете одну матрицу преобразования для облака точек и не вращаете каждую точку самостоятельно в коде на стороне процессора, который был бы слишком медленным ... Один VBO может легко обрабатывать 300-100000 тысяч точек даже в более старой настройке с фиксированной функцией. Также вы обращаетесь к массиву 3 раза за точку, что безумно, особенно если у него есть собственная логика оператора []. Почему бы не использовать указатель для плавания или удвоения и использовать glVertex3fv или glVertex3dv. Это повысит скорость в 3 или более раз в зависимости от [] накладных расходов. Старая и медленная система? тогда зачем использовать питон? 28.06.2019

Ответы:


1

Узким местом является цикл for и последовательность glBegin/glEnd. Данные считываются из файлов в каждом кадре. Обратите внимание, что рисование с использованием glBegin/glEnd последовательности, а матричный стек с фиксированной функцией устарел десятилетиями. Прочитайте файлы один раз при запуске и создайте объект Vertex Buffer. (Подробнее о спецификации вершин и Shader для современного способа рендеринга.)

Ближайшим решением для вашего существующего кода является использование возможности на стороне клиента 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 и создайте и инициализируйте хранилище данных буферного объекта:

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 из буфера:

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 (x, y, z, r, g, b), поэтому каждый кортеж атрибута состоит из 6 компонентов, а не из 3.

Атрибут цвета фиксированной функции должен быть включен состоянием клиента GL_COLOR_ARRAY. Добавьте атрибут, указанный в glColorPointer.

Каждый кортеж атрибута имеет размер 24 байта, потому что кортеж состоит из 6 компонентов (x, y, z, r, g, b) и каждый компонент имеет размер 4 байта (это размер float).
Этот размер должен быть передан в 3-й параметр (sride ) из glVertexPointer соответственно glColorPointer.

Если именованный объект буфера связан, то последний параметр glVertexPointer соответственно glColorPointer обрабатывается как смещение в байтах в хранилище буфера объектов буфера. Смещение — это количество байтов до 1-го компонента атрибута.
В случае 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 должен быть импортирован. Если смещение равно 0, вместо ctypes.c_void_p(0) можно использовать None.

Спецификация атрибутов вершины может выглядеть следующим образом:

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()
27.06.2019
  • Большое спасибо! работает на 100%, выглядит намного лучше, вы случайно не знаете, как я могу добавить цвет для каждого пикселя? есть ли способ добавить его в список вершин как 4-й столбец? 28.06.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..