glDrawArrays vs 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),它仍然会崩溃,即使定义的三角形数量更大,所以我认为它与大小无关。

问候,波格丹

编辑:好吧,所以现在我已经做了一些额外的检查,这里是我目前的情况:我已经将len(三角形)更改为ADT.byteCount,但目前还没有解决方案。 所以我检查了我得到的所有数据,它是这样的:顶点数组包含~60000 * 3 = 180000个GL_Float类型的顶点条目,和法线数组一样。 由于只有<62535个顶点,我使用三角形的无符号短整型。 所以我有len(三角形)是~135000。 我也改变了glDrawElements(GL_TRIANGLES,len(self.triangles), GL_UNSIGNED_SHORT ,0)。我也检查过了,三角形数组中的所有数据都在0到62534之间,因为我想也许有一些索引是超出范围滑槽。 这里还有什么可能是错的? 哦,glDrawElements(GL_POINTS,...)如何工作? 它是否也需要某种指数?

EDIT2我已经更新了上面的代码,并且如上所述,现在绘制元素绘制了我的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 min(三角形)= 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)

我对Python GL没有经验,但我想我发现了一些东西。 您可以使用len(self.triangles)在调用glDrawElements ,所以我想,让你三角形阵列中的索引的数量。 但是为什么在glBufferData使用len(triangles)作为大小,而不是像其他调用中那样使用ADT.arrayByteCount 。 所以你的缓冲区太小了,因为它包含len(triangles)字节,尽管三角形包含未签名的整数。 如果三角形确实包含字节(我怀疑),您将不得不在glDrawElements使用GL_UNSIGNED_BYTE

编辑:根据您的编辑,我得到了一些更多的答案。 当然, glDrawElements(GL_POINTS, ...)需要索引。 它只是使用每个索引来绘制一个点,而不是每三个三角形的索引。 只是你经常不需要glDrawElements ,因为你不重复使用顶点,但是你仍然需要它的索引。 它不会神奇地成为glDrawArrays调用的glDrawArrays

请记住, vertices数组包含浮点数,并且glDrawArrays绘制顶点,所以您必须绘制len(vertices)/3个顶点。 Juts记住,一个元素是一个索引(单个顶点),而不是一个三角形,顶点是3个浮点数(或者你在glVertexPointer指定的),而不仅仅是一个。

但是如果你的triangles数组真的包含3个索引的元组(因此len(triangles)是三角形数而不是索引数),你将不得不绘制3*len(triangles)元素(索引)。 如果你的vertices数组包含矢量而不是浮点数,那么在glDrawArrays调用中绘制len(vertices)顶点是正确的。 因此很高兴看到他们的声明是确定的。


根据我的经验,一旦您开始使用某些更高级的OpenGL调用,Python 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.在使用C语言编写OpenGL示例时要小心,因为它们使用(void*)0作为void指针,它不能被正确解释为指针PyOpenGL,它将0视为非空值。

相反,你应该使用

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

(另请参阅https://stackoverflow.com/a/14365737/478380)

链接地址: http://www.djcxy.com/p/52845.html

上一篇: glDrawArrays vs glDrawElements

下一篇: How wrong is it to create an event handler delegate with out the standard (Obj sender, EventArgs args) signature?