glDrawArrays против glDrawElements

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

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), он все равно аварийно завершает работу, даже если количество определенных треугольников намного больше, поэтому я не думаю, что это имеет какое-либо отношение к размер.

С уважением, Богдан!--8-->

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

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

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

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

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

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

в отношении

EDIT3

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

вершины - массива поплавков,

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

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

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

рисунок делается:

glDrawElements (GL_TRIANGLES, len(self.треугольники), GL_UNSIGNED_SHORT, 0)

обновление

хорошо, когда я tought я получил, как это должно работать, я попытался пропустить 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 ответов


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

EDIT: согласно вашим изменениям, у меня есть еще несколько ответов. Конечно!--8--> нужны индексы тоже. Он просто использует каждый индекс для рисования точки, а не каждые три индекса для треугольника. Это просто, что для очков вам часто не нужно glDrawElements, поскольку вы все равно не используете вершины, но для этого вам все равно нужны индексы. Это не волшебным образом становится glDrawArrays звонок под капотом.

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

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


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


причина

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)