Hack to map Vertex Buffer Objects into Numpy arrays...

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

  1. Rene Dudfield

    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,

  2. Mike Fletcher

    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.

  3. Mike C. Fletcher

    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.

  4. rndblnch

    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

  5. Derek Dorian

    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 :(

  6. rndblnch

    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...

  7. sashimi

    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')

  8. Mike Fletcher

    Mike Fletcher on 06/13/2011 11:23 a.m. #

    Thanks, I've implemented something based on this in the mapBuffer function.

Comments are closed.

Pingbacks

Pingbacks are closed.