我开始在Python中使用OpenGL 4(通过Pyglet和一些框架代码我从网上下载/自己编写用于加载着色器/程序),但我认为我理解的东西相当不错,所以我不这样做认为我的代码中存在某个问题。
那么我的问题是什么?似乎当numpy数组或缓冲区达到一定大小时,我画画时会发生奇怪的事情。请查看链接的图片,看看我的意思。 http://i.imgur.com/8Oym6VA.png?1
在图片上你可以看到我正在画一些“机器人”,每个机器人都是由8个盒子组成的。机器人的数据只计算一次,使用基本的立方体顶点/颜色/索引数据,然后适当地平移/缩放/旋转并附加到更大的阵列中。 在左边的图片中,我在一个VAO中绘制了172个这样的机器人,右边的图片有173个机器人。正如你所看到的,当我翻过那个“神奇”的数字时会发生奇怪的事情。看起来好像所有顶点都以某种方式连接到要在屏幕上绘制的第一个点(第一个绘制的机器人“身体”的右上方部分)。如果我将第一个机器人移动到其他地方,所有点仍然连接到该点 - 以说明我确保图片中的点不以(0,0,0)或类似的为中心。 左图有顶点和颜色数据,有131328个浮点数,索引数据长49248。右图有顶点和颜色数据,有132096个浮点数,而索引数据有49536个浮点数。 如果我将数据分成多个VAO,那么我可以轻松地绘制100倍价值的机器人(当然有100个VAO)没有任何问题(即使1000个VAO的1000个机器人也能很好地工作,除了服用了很多记忆和工作约0.2 FPS)。
为了测试Pyglets类(或我自己的)是否有任何问题,我还用OpenGL调用重写了整个事情,我遇到了同样的问题。 那么,维也纳国际中心是不是意味着那么大(我不知何故怀疑维多利亚州立大学每个只有大约17k个三角形)?或者它与Numpy有关(我之前在Numpy中使用过更大的阵列,我不记得有任何问题)?哦顺便说一句,浮点数的大小似乎并不重要(如果所有顶点都在[-1,1]范围内,如果上升到[-35000,35000],则会发生同样的事情。
我已经非常广泛地搜索了这个主题,但我在搜索中没有遇到任何类似的东西 - 如果有的话,我道歉。我所能找到的只是使用非常大的numpy数组时的MemoryError,但是我的数组远远不能达到生成它所需的大小。
我的系统规格是:
虽然我几乎可以肯定我的代码没有任何问题,但我仍然会在这里弹出与绘图相关的片段(同样,我也尝试过基本的OpenGL调用而且它不起作用好点)。
首先我有一个“Handler”类,它用于存储大量静态数据,因此我可以使用一个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应用于base中的每个顶点(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()
使用
在Pyglet Window的on_draw部分调用它self.handler.draw()
更新
我发现了问题所在,我现在觉得完全彻底愚蠢:P。 显然我忘了指定一个numpy数组的dtype,它默认为'int32'。由于我使用GL_UNSIGNED_SHORT标志(又名'uint16')进行绘制,因此它成了一个问题。 我现在确保它尽可能长时间保持'uint16'(直到索引数据的最大值高于2 ^ 16)并添加一个检查以查看indexData是'uint16'还是'uint32'并添加了相应的glDraw命令上的标志。
这似乎已经解决了,因为我现在可以轻松地将几千个(试用最多5.000个)机器人添加到一个VBO中它仍然有效。
我仍然不明白,这就是为什么它看起来像(所有顶点连接到第一个)以及为什么它开始时它。当indexData仍然正常时,它的最大值是32831,它开始执行时的最大值是33023.所以这两个值都明显低于2 ^ 16,那么为什么GL_UNSIGNED_SHORT还没有工作呢? 如果有人可以回答这个问题,我会暂时提出这个问题,并在几天后/当我得到答案时关闭。谢谢!