glDrawArrays против glDrawElements - PullRequest
8 голосов
/ 25 мая 2011

Хорошо, я все еще пытаюсь заставить это работать. Важные части моего кода:

def __init__(self, vertices, normals, triangles):
    self.bufferVertices = glGenBuffersARB(1)
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferVertices)
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, ADT.arrayByteCount(vertices), ADT.voidDataPointer(vertices), GL_STATIC_DRAW_ARB)
    self.vertices = vertices
    self.bufferNormals = glGenBuffersARB(1)
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferNormals)
    glBufferDataARB(GL_ARRAY_BUFFER_ARB, ADT.arrayByteCount(normals), ADT.voidDataPointer(normals), GL_STATIC_DRAW_ARB)
    self.normals = normals
    self.bufferTriangles = glGenBuffersARB(1)

    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, self.bufferTriangles)
    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ADT.arrayByteCount(triangles), ADT.voidDataPointer(triangles), GL_STATIC_DRAW_ARB)

    self.triangles = triangles
    glDisableClientState(GL_VERTEX_ARRAY) **(Not sure if any of the following influence in any way)** 
    glDisableClientState(GL_NORMAL_ARRAY)
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0)
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0)

Я не думаю, что здесь что-то не так из того, что я читал о VBO. Так что теперь у меня есть буфера вершин, нормалей (еще не использованных) и индексов треугольников. Теперь для фактического розыгрыша:

def draw(self, type):
    glDisableClientState(GL_VERTEX_ARRAY)  
    glDisableClientState(GL_NORMAL_ARRAY)
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0)
    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0)
    **Again above line not sure if they have any use.**        
    glEnableClientState(GL_VERTEX_ARRAY)         
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferVertices)
    glVertexPointer(3, GL_FLOAT, 0, None)

    glEnableClientState(GL_NORMAL_ARRAY);
    glBindBufferARB(GL_ARRAY_BUFFER_ARB, self.bufferNormals)
    glNormalPointer(GL_FLOAT, 0, None)

    if type == GL_POINTS:    
        #glDrawArrays( GL_POINTS, 0, len(self.vertices) );    
        glDrawElements(type, len(self.vertices), GL_UNSIGNED_SHORT, 0)
    else:
        #glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, self.bufferTriangles)**(If I uncomment this doesnt seem to make any difference?!)**
        #glDrawArrays( GL_TRIANGLES, 0, len(self.triangles) );  
        glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, 0)**(What does it draw now since GL_ELEMENT_ARRAY_BUFFER_ARB is binded to 0 ?!)**

Теперь glDrawArrays работает. Но в случае, когда я должен нарисовать свои треугольники, он не рисует треугольники, которые я определил в bufferTriangles (это нормально из того, что я прочитал, так как drawArrays не использует индексы? Или я здесь не прав?). Проблема в том, что если я пытаюсь использовать glDrawElements, все вылетает с:

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x000000003150ebbc
Crashed Thread:  0

Thread 0 Crashed:
0   com.apple.GeForce8xxxGLDriver   0x1a3e7050 gldGetTextureLevel + 743600
1   com.apple.GeForce8xxxGLDriver   0x1a3e7563 gldGetTextureLevel + 744899
2   GLEngine                        0x1a206eee gleDrawArraysOrElements_VBO_Exec + 1950

Теперь, что мне здесь не хватает? Из того, что я могу понять, я, вероятно, пропускаю плохой указатель где-то Обратите внимание, что даже если я пытаюсь использовать glDrawElements (type, 24, GL_UNSIGNED_INT, 0), он все равно падает, даже если число определенных треугольников намного больше, поэтому я не думаю, что это имеет какое-либо отношение к размеру.

С уважением, Богдан

EDIT: Итак, теперь я сделал дополнительную проверку, и вот моя текущая ситуация: я изменил len (треугольники) на ADT.byteCount, решения пока нет. Итак, я проверил все данные, которые я получал, и это выглядит так: массив вершин содержит ~ 60000 * 3 = 180000 записей вершин типа GL_Float, как и массив нормали. Поскольку вершин всего <62535, я использую сокращение без знака для треугольников. Поэтому у меня Лен (треугольники) составляет ~ 135000. Я также изменил glDrawElements (GL_TRIANGLES, len (self.triangles), <strong>GL_UNSIGNED_SHORT , 0). Я также проверил, и все данные из массива треугольников находятся между 0 и 62534, как я был думая, может быть, какой-то индекс, который находится вне диапазона, упал через корыто Что еще может быть не так? Да, и как работает glDrawElements (GL_POINTS, ...)? Нужны ли какие-то индексы?

EDIT2 Я обновил код выше и, как там сказано, теперь элементы draw рисуют мой GL_POINTS, но я не уверен, где он получает индексы? Или они не нужны в случае GL_POINTS? А для GL_TRIANGLES это работает следующим образом, с комментируемым glBindBufferARB (GL_ELEMENT_ARRAY_BUFFER_ARB, self.bufferTriangles), но опять же, какие индексы здесь требуется, чтобы буфер элементов был связан с 0 ?! И еще одна вещь: glDrawElements не будет рисовать все точки, которые делает glDrawArrays. Для лучшего объяснения:

glDrawArrays( GL_POINTS, 0, len(self.vertices) );

Это правильно рисует все мои очки:

glDrawElements(type, len(self.vertices), GL_UNSIGNED_SHORT, 0)

Кажется, это заметно рисует меньше точек, чем glDrawArrays. Теперь забавно то, что если я передам в качестве размера что-то вроде 10 * len (self.vertices) для рисования элементов, то он нарисует все точки (некоторые могут быть дважды или больше; могу ли я это проверить?), Но разве это не приведет к краху?

Привет

EDIT3

Более точная информация о массивах:

вершин - массив с плавающей точкой,

len (вершины) = 180000 byteCount (вершины) = 720000

треугольники - массив numpy.uint16

len (треугольники) = 353439 byteCount (треугольники) = 706878 мин (треугольники) = 0 max (треугольники) = 59999, поэтому они должны указывать на правильные вершины

Рисунок сделан:

glDrawElements (GL_TRIANGLES, len (self.triangles), GL_UNSIGNED_SHORT, 0)

UPDATE

Хорошо, только когда я понял, что понял, как это должно работать, я попытался пропустить VBO для элементов и пошел просто:

glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, ADT.voidDataPointer(self.triangles))

Теперь это не только работает и отлично рисует все мои треугольники, но и FPS лучше. Разве VBO не должно быть быстрее? И что может привести к тому, что вышеприведенный подход сработает, но следующее приведет к сбою:

glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, self.bufferTriangles)
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, ADT.arrayByteCount(triangles), ADT.voidDataPointer(triangles), GL_STATIC_DRAW_ARB)
glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, 0)

Ответы [ 3 ]

4 голосов
/ 25 мая 2011

У меня нет опыта работы с Python GL, но я думаю, что что-то заметил. Вы используете len(self.triangles) в вызове glDrawElements, поэтому я полагаю, что это дает вам количество индексов в массиве треугольников. Но зачем тогда использовать len(triangles) в качестве размера в glBufferData, а не ADT.arrayByteCount, как в других вызовах. Таким образом, ваш буфер слишком мал, так как содержит len(triangles) байтов, хотя треугольники содержат беззнаковые целые. Если треугольники действительно содержат байты (в чем я сомневаюсь), вы должны использовать GL_UNSIGNED_BYTE в glDrawElements.

РЕДАКТИРОВАТЬ: В соответствии с вашими правками я получил еще несколько ответов. Конечно, glDrawElements(GL_POINTS, ...) тоже нужны индексы. Он просто использует каждый индекс, чтобы нарисовать точку, вместо каждых трех индексов для треугольника. Просто для точек вам часто не требуется glDrawElements, так как вы все равно не используете вершины, но для этого вам все же нужны индексы. Он волшебным образом не становится glDrawArrays вызовом под капотом.

И имейте в виду, что массив vertices содержит числа с плавающей точкой, а glDrawArrays рисует вершины, поэтому вам нужно нарисовать len(vertices)/3 вершин. Просто запомните, элемент - это индекс (одной вершины), а не треугольник, а вершина имеет 3 числа с плавающей запятой (или то, что вы указали в glVertexPointer), а не только один.

Но если ваш массив triangles действительно содержит кортежи из 3 индексов (и, следовательно, len(triangles) - это число треугольников, а не число индексов), вам придется рисовать 3*len(triangles) элементов (индексов). и если ваш массив vertices содержит векторы, а не только числа с плавающей запятой, то рисование вершин len(vertices) в вызове glDrawArrays является правильным. Поэтому было бы неплохо увидеть их заявления, чтобы быть уверенным.

0 голосов
/ 17 сентября 2015

Причина, по которой

glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, ADT.voidDataPointer(self.triangles))

работает, а

glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, 0)

не работает, заключается в том, что PyOpenGL ожидает None в качестве указателя void, а не 0. Будьте осторожны при использовании OpenGLпримеры написаны на C, потому что они используют (void*)0 в качестве указателя void, который неправильно интерпретируется PyOpenGL как указатель, который вместо этого обрабатывает 0 как не пустое значение.

Вместо этого следует использовать

glDrawElements(GL_TRIANGLES, len(self.triangles) , GL_UNSIGNED_SHORT, None)

(см. Также https://stackoverflow.com/a/14365737/478380)

0 голосов
/ 04 июня 2011

По моему опыту, оболочка Python OpenGL очень глючит, когда вы начинаете использовать некоторые из более сложных вызовов OpenGL.Похоже, что многие вызовы вызывают сбои без причины и иногда работают, если вы заменяете их эквивалентной последовательностью различных вызовов ... Я переключил языки программирования на OpenGL вместо того, чтобы иметь дело с этими проблемами.

...