要完整回答这个问题,就不得不先提一下OpenGL缓冲区更新。
OpenGL指令glBufferData https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml创建并初始化缓冲区对象的数据存储。缓冲区对象的现有数据存储被完全销毁,并创建新的数据存储(可能具有不同的大小)。如果将数据指针传递给函数,则数据存储将完全由数据初始化。假设缓冲区的大小和提供的数据的大小相等。
glBufferSubData https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml更新现有数据存储的整个数据或数据子集。假设数据存储是之前创建的glBufferData
。不会销毁或创建任何数据存储。
当然,从技术上来说glBufferData
总是可以用来代替glBufferSubData
, but glBufferSubData
会表现得更好,因为消除了昂贵的缓冲区创建(分配)。
Using
self.vbo.set_array(self.verts)
是一个坏主意,因为从实现中可以看出(PyOpenGL/OpenGL/arrays/vbo.py https://github.com/Distrotech/PyOpenGL/blob/master/OpenGL/arrays/vbo.py),此方法创建一个全新的缓冲区,可能具有新的大小,并将强制重新创建缓冲区对象的数据存储(因为self.copied = False
).
如果之前创建了缓冲区,那么self.vbo.copy_data()
将通过以下方式更新数据glBufferSubData
(see if self.copied:
in copy_data
)。为了使这项工作有效,缓冲区必须是当前绑定的缓冲区(self.vbo.bind()
)。此外还必须设置复制信息(VBO.copy_segments
)。复制信息由项目设置者声明(VBO.__setitem__
).
这意味着,在“方法 1”中,您必须执行如下操作:
self.vbo[:] = self.verts
self.vbo.bind()
self.vbo.copy_data()
Since OpenGL.arrays.vbo http://pyopengl.sourceforge.net/documentation/pydoc/OpenGL.arrays.vbo.html无非是 OpenGL 缓冲区指令的包装器,我更喜欢使用glBufferSubData
直接,在这种情况下效果最好:
# Approach 3:
# Direct buffer update by `glBufferSubData`
self.vbo.bind()
self.vbo.implementation.glBufferSubData(self.vbo.target, 0, self.vbo.data)
通过这种方法,甚至可以更新数据存储的子集。注意第二个参数glBufferSubData
是缓冲区对象数据存储的字节偏移量。此外还有一个重载实现,它可以处理缓冲区大小和直接数据指针。