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