Hack to map Vertex Buffer Objects into Numpy arrays...
Written by
on
in
Snaking.
This post from the numpy list shows you how to turn a ctypes c_void_p into a numpy array. The glMapBuffer() function maps your currently-bound array into a void * which you can access directly... combining the two:
def map_buffer( vbo, access=GL_READ_WRITE ): """Map the given buffer into a numpy array...""" func = ctypes.pythonapi.PyBuffer_FromMemory func.restype = ctypes.py_object vp = glMapBuffer( vbo.target, access ) buffer = func( ctypes.c_void_p(vp), vbo.size ) array = frombuffer( buffer, 'B' ) return array
You have to call vbo.bind() before you call map_buffer(), and you need to do a glUnmapBuffer() before you do vbo.unbind(). You can use array.view() to get a different data-type in the array, and reshape() to get a different data-shape. Will have to think about making a wrapped version of something like this available on the vbo objects, AFAIK only ctypes arrays and numpy arrays (of the current formats supported) will support this kind of behaviour, but even with those restrictions it might be useful.
Fixed an API bug in the glBufferData() calls as well (this post's code is from the test script for that), fix should show up in the next release.
Comments
Comments are closed.
Pingbacks
Pingbacks are closed.
Rene Dudfield on 09/02/2009 8:28 a.m. #
hi,
cool :)
I guess you could use pygame frombuffer too... if you wanted to view your verticies as an image... not sure why you would though, hehe.
Also I think PIL supports the buffer interface... and you could always turn it into a numpy array, and then from there send it to other numpy array supporting packages.
cu,
Mike Fletcher on 09/02/2009 9:52 a.m. #
Actually, this came up because of VBO's used as *Pixel* Buffer Objects. i.e. you bind a VBO as a target of either pack/unpack target (depending on whether you want to receive/transfer the image) and then issue the pixel-transfer operation (e.g. glReadPixels), the image is now in your VBO/PBO and you can read it by mapping and manipulating. For Pygame buffers this would make the data a surface and you could blit to/from it with regular sprites and the like.
Mike C. Fletcher on 09/02/2009 9:57 a.m. #
Reminds me that I need to sit down some time and make a generic "buffer object" data-handler (along with adding "convert a pointer to a sized buffer" entry points to the current ones). Direct Pygame-surface/PIL-Image data-handling might be nice too. Ah, always more to do and less time to do it.
rndblnch on 09/06/2009 2:36 p.m. #
do you manage to use pixel buffer objects with pyopengl ?
i tried with no luck to do a screenshot using:
glBindBuffer(GL_PIXEL_PACK_BUFFER, glGenBuffers(1))
glReadPixels(0, 0, width, height,
GL_RGBA, GL_UNSIGNED_BYTE, c_void_p(0))
data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY)
but got an invalid operation error for the glReadPixels (works without BindBuffer/MapBuffer)...
any hints?
renaud
Derek Dorian on 09/10/2009 5:30 a.m. #
glBindBuffer(GL_PIXEL_PACK_BUFFER, glGenBuffers(1))
glReadPixels(0, 0, width, height,
GL_RGBA, GL_UNSIGNED_BYTE, c_void_p(0))
data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY)
...
same goes for me.
No luck :(
rndblnch on 09/15/2009 5:16 p.m. #
got it: forgot the glBufferData before trying to fill it with glReadPixel ...
sorry for the noise...
sashimi on 05/29/2011 6:28 a.m. #
I found a more simple solution.
p = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE)
ptr = ctypes.cast(p, ctypes.POINTER(ctypes.c_float * num_vertex))
array = np.frombuffer(ptr.contents, 'f')
Mike Fletcher on 06/13/2011 11:23 a.m. #
Thanks, I've implemented something based on this in the mapBuffer function.