Проблемы с VBO OpenGL 4 и массивами Numpy, Pyglet/Python

Я начинаю использовать OpenGL 4 в Python (через Pyglet и некоторый фреймворковый код, который я получил из сети / написал сам для загрузки шейдеров / программ), но я думаю, что понимаю вещи довольно хорошо, поэтому я не думаю, что есть проблема где-то в моем коде.

Так в чем моя проблема? Кажется, что, когда числовые массивы или буферы достигают определенного размера, странные вещи случаются, когда я рисую. Пожалуйста, посмотрите на картинку, чтобы понять, что я имею в виду. https://i.imgur.com/8Oym6VA.png?1

На картинке видно, что я рисую несколько "роботов", каждый из которых состоит из 8 коробок. Данные для робота были рассчитаны только один раз с использованием базовых данных вершины / цвета / индекса куба, а затем соответствующим образом переведены / масштабированы / повернуты и добавлены в больший массив. На рисунке слева я рисую 172 таких робота в одном VAO, на правом рисунке 173 робота. Как видите, странные вещи случаются, когда я перебираю это "магическое" число. Похоже, что все вершины каким-то образом связаны с первой точкой, которая должна быть нарисована на экране (верхняя правая-передняя часть "тела" первых нарисованных роботов). Если я перенесу первого робота куда-нибудь еще, все точки все еще будут связаны с этой точкой - чтобы проиллюстрировать, что я убедился, что точка на рисунке не центрирована по (0,0,0) или что-то подобное. На левой картинке есть данные вершин и цветов с 131328 числами с плавающей запятой, индексные данные имеют длину 49248. Правое изображение имеет данные о вершине и цвете с 132096 числами с плавающей точкой, а индексные данные - 49536 значений с плавающей точкой. Если я разделю данные на более чем одну VAO, то я легко смогу нарисовать роботов в 100 раз (с 100 VAO конечно) без каких-либо проблем (даже роботы в 1000 раз с 1000 VAO работали хорошо, за исключением того, что я потратил много времени) памяти и работает примерно с 0,2 FPS).

Чтобы проверить, есть ли что-то не так с классами Pyglets (или моими собственными), я также переписал все это с помощью вызовов OpenGL и столкнулся с той же проблемой. Итак, неужели VBO просто не должно быть таким большим (я почему-то сомневаюсь, что VBO может иметь только около 17k треугольников каждый)? Или это как-то связано с Numpy (раньше я работал с большими массивами в Numpy и не помню проблем)? О, между прочим, размер поплавков, кажется, не имеет значения (то же самое происходит, если все вершины находятся в масштабе [-1,1] или если подняться до [-35000, 35000].

Я довольно широко искал эту тему, но ничего подобного в своем поиске не встречал - если есть, то прошу прощения. Все, что я мог найти, это MemoryError при использовании действительно больших массивов, но мои массивы далеко не соответствуют размеру, необходимому для этого.

Мои системные характеристики:

  • Intel Core i7
  • Nvidia GeForce GTX 465
  • Windows 8 64-битная
  • Python 3.3 (64-разрядная версия)
  • Pyglet 1.2alpha1
  • Numpy бинарный пакет для Python 3.3 64-битный отсюда

И хотя я почти уверен, что в моем коде нет ничего плохого, я все еще показываю фрагменты, связанные с чертежом (опять же, я попробовал его и с базовыми вызовами OpenGL, и он не работал лучше),

Во-первых, у меня есть класс "Обработчик", который предназначен для хранения большого количества статических данных, поэтому я могу нарисовать его одним вызовом glDraw * (например, уровень игры или что-то подобное). Он создает методы для добавления к своим данным, метод для инициализации его VBO и VAO и функцию рисования, которая получает стек и рисует на нем. Он также получает программу (вершинный / цветной шейдер), с помощью которой он рисует.

class Handler:
def __init__(self, program):
    self.vertexData = numpy.array((), dtype=GLfloat)
    self.colorData = numpy.array((), dtype=GLfloat)
    self.indexData = numpy.array((), dtype=GLshort)

    self.program = program

def initBuffers(self):
    self.vao = GLuint()
    glGenVertexArrays(1, self.vao)
    glBindVertexArray(self.vao)

    #=======================================================================
    # Vertices
    #=======================================================================
    self.vertexBufferObject = pyglet.graphics.vertexbuffer.create_buffer(self.vertexData.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
    self.vertexBufferObject.bind()
    self.vertexBufferObject.set_data(self.vertexData.ctypes.data)
    glEnableVertexAttribArray(0)
    glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0)

    #=======================================================================
    # Color
    #=======================================================================
    self.colorBufferObject = pyglet.graphics.vertexbuffer.create_buffer(self.colorData.nbytes, GL_ARRAY_BUFFER, GL_STATIC_DRAW)
    self.colorBufferObject.bind()
    self.colorBufferObject.set_data(self.colorData.ctypes.data)
    glEnableVertexAttribArray(1)
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, 0)

    #=======================================================================
    # Index
    #=======================================================================
    self.indexBufferObject = pyglet.graphics.vertexbuffer.create_buffer(self.indexData.nbytes, GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW)
    self.indexBufferObject.bind()
    self.indexBufferObject.set_data(self.indexData.ctypes.data)

    glBindBuffer(GL_ARRAY_BUFFER, 0)
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
    glBindVertexArray(0)

    self.len = len(self.indexData)

def addTo(self, vertices, color = None, index = None):
    if(color != None):
        self.colorData = numpy.append(self.colorData, color)
    if(index != None):
        self.indexData = numpy.append(self.indexData, index + len(self.vertexData)//4)
    self.vertexData = numpy.append(self.vertexData, vertices)

def draw(self, stack):
    glBindVertexArray(self.vao)
    self.indexBufferObject.bind()
    self.program.install()

    stack.push()
    self.program.usetM4F("modelToWorldMatrix", stack.ready(), row = GL_FALSE)
    glDrawElements(GL_TRIANGLES, self.len, GL_UNSIGNED_SHORT, 0)
    stack.pop()
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)
    glBindVertexArray(0)
    self.program.uninstall()

И я инициализирую обработчик с помощью некоторого очень простого кода, где translateMatrix(x, y, z) возвращает матрицу перевода, а applyTrans (base, trans) применяет trans к каждой вершине (x,y,z,w) в базе.

self.handler = Handler(self.ObjectColor)
    for i in range(1,n):
        self.handler.addTo(applyTrans(self.robots.vertexData, translateMatrix(2*i*(-1)**(i//2), 1.5*i*(-1)**i, 0.5*i*(-1)**i)), self.robots.colorData, self.robots.indexData)
self.handler.initBuffers()

И вызвать его в on_draw части окна Pyglet с

self.handler.draw()

ОБНОВИТЬ:

Я выяснил, в чем проблема, и теперь я чувствую себя совершенно глупо:P. По-видимому, я забыл указать dtype одного из массивов numpy, и по умолчанию он был равен int32. Поскольку я рисовал с флагом GL_UNSIGNED_SHORT (он же "uint16"), это стало проблемой. Теперь я позаботился о том, чтобы он оставался "uint16" как можно дольше (пока максимум данных индекса не превысит 2^16), и добавил проверку, чтобы увидеть, является ли indexData "uint16" или "uint32", и добавил соответствующие флаг команды glDraw.

Это, кажется, исправило это, поскольку теперь я могу легко добавить несколько тысяч (пробовал с максимумом 5000) к одному VBO, и это все еще работает.

Однако я до сих пор не понимаю, почему это выглядело так (все вершины связаны с первой) и почему это началось, когда это произошло. Максимальное значение indexData, когда он все еще был в порядке, было 32831, максимальное значение, когда он начал действовать, было 33023. Таким образом, оба значения, очевидно, ниже, чем 2^16, так почему же GL_UNSIGNED_SHORT по-прежнему не работает? Я оставлю вопрос открытым еще немного на тот случай, если кто-нибудь ответит на него и закроется через несколько дней / когда я получу ответ. Спасибо!

1 ответ

Вы можете использовать массивы Numpy с плавающими объектами вершинного буфера. Я не использовал их в контексте Pyglet, хотя. Что-то вроде:

from OpenGL.arrays import vbo

# setup
vertices_gl = vbo.VBO(vertPoints)
colours_gl = vbo.VBO(vertPoints)

# in drawing code
vertices.bind()
colours.bind()
glVertexPointer(2, gl.GL_FLOAT, 0, vertices_gl)
glColorPointer(2, gl.GL_FLOAT, 0, vertices_gl) 
Другие вопросы по тегам