numpy and glvertexpointer

150 views
Skip to first unread message

Jamie

unread,
Mar 28, 2008, 6:27:03 AM3/28/08
to pyglet-users
Hi,

I'm just starting to have a play with pyglet as a warm-up for pyweek
next week and I really like it. At the moment i'm just playing around
with particles and I was wondering if it's possible to use a numpy
array with glVertexPointer. I want to can use numpy's fast
manipulation of arrays to move the particles in the array around, then
pass this array straight through as a vertex array. Is this possible
at all? I know glVertexPointer expects a ctypes array, but is there
any way to convert between the two? Numpy arrays now have a ctypes
property to allow their data to be accessed from C, but i'm guessing
it's not as simple as that as it probably doesn't contain GLFloats?

Is there any other way to quickly manipulate a large array without
using numpy that I should be looking at instead? I'm struggling with
frame-rates when doing it in pure python.

Thanks,

Jamie

Alex Holkner

unread,
Mar 28, 2008, 10:00:27 AM3/28/08
to pyglet...@googlegroups.com
On Fri, Mar 28, 2008 at 9:27 PM, Jamie <jamieh...@gmail.com> wrote:
>
> Hi,
>
> I'm just starting to have a play with pyglet as a warm-up for pyweek
> next week and I really like it. At the moment i'm just playing around
> with particles and I was wondering if it's possible to use a numpy
> array with glVertexPointer. I want to can use numpy's fast
> manipulation of arrays to move the particles in the array around, then
> pass this array straight through as a vertex array. Is this possible
> at all? I know glVertexPointer expects a ctypes array, but is there
> any way to convert between the two?

Worst case, you can convert via a Python list.

> Numpy arrays now have a ctypes
> property to allow their data to be accessed from C, but i'm guessing
> it's not as simple as that as it probably doesn't contain GLFloats?

I haven't used numpy recently, but this sounds doable. a GLfloat is
the same as a c_float.

Alex.

Gary Herron

unread,
Mar 28, 2008, 10:50:35 AM3/28/08
to pyglet...@googlegroups.com

Yes, it is easily done, and the conversion is a one-liner that does
*not* copy the array. Here's the several relevant lines of code pulled
directly from my pyglet application. This works on Python2.5, Windows
and Linux, with pyglet 1.0 and 1.1.

def PointerToNumpy(a, ptype=ctypes.c_float):
a = numpy.ascontiguousarray(a) # Probably a NO-OP, but
perhaps not
return a.ctypes.data_as(ctypes.POINTER(ptype)) # Ugly and undocumented!

glVertexPointer(3, GL_FLOAT, 0, PointerToNumpy(VertexData))

Hope that helps,

Gary Herron


> >
>

Jamie

unread,
Mar 28, 2008, 11:01:38 AM3/28/08
to pyglet-users
Perfect! That's just what I was after.

Thanks very much,

Jamie

incantus

unread,
Mar 28, 2008, 6:28:36 PM3/28/08
to pyglet-users

Hi Jamie,

I have a simple particle engine I wrote using numpy a while ago. It
doesn't use pyglet, but it should be easy to replay the PyOpenGL code
with pyglet. The anim functionality is ported from rabbyt, so that is
under the MIT license, but the particle emitter is public domain.

http://groups.google.com/group/pyglet-users/web/particle.tar.gz

Jamie

unread,
Mar 30, 2008, 5:01:00 PM3/30/08
to pyglet-users
Hi,

I've finally had a chance to write some code to try and do this and it
just
doesn't seem to display anything. I'm probably doing something
stupid, but
I can't see it. I've set up a minimal test case that replicates what
i'm
doing in my app (below), and it also fails to display anything. Is
there a
flag i'm missing? Gary, does this look similar to what you do in your
code?

It looks to be doing the same thing as your example too incantus
(thanks for that),
but i'm not using textures or colourpointers.


Thanks,

Jamie

from pyglet import window
from pyglet.gl import *
import pyglet
from pyglet.window import key

import random as rd
import ctypes
from numpy import *


class VertexArrayTest(pyglet.window.Window):

def __init__(self):
super(VertexArrayTest,self).__init__(800,600)
self.glInit()
self.setupVA()

def glInit(self):
glClearColor(0, 0, 0, 0.0)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0.0, 800.0, 0.0, 600.0, 0, 20.0)
glMatrixMode(GL_MODELVIEW)

glEnable(GL_DEPTH_TEST)
glEnable(GL_VERTEX_ARRAY)

glLoadIdentity()



def setupVA(self):
self.vertarray=array([])
for i in range(50):
self.vertarray=append(self.vertarray,[10,10])
self.vertarray=append(self.vertarray,[10,20])
self.vertarray=append(self.vertarray,[20,20])
self.vertarray=append(self.vertarray,[20,10])

#self.vertarray=self.vertarray.reshape(50*4,2)

def on_draw(self):
glClear(GL_COLOR_BUFFER_BIT)

glLoadIdentity()

glEnableClientState(GL_VERTEX_ARRAY)
glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
self.cverts = ascontiguousarray(self.vertarray)
glColor4f(1,0,1,1)


glVertexPointer(2,GL_FLOAT,
0,self.cverts.ctypes.data_as(ctypes.POINTER(ctypes.c_float)))

glDrawArrays(GL_QUADS,0,50)
glPopClientAttrib()

vat=VertexArrayTest()
pyglet.app.run()

Gary Herron

unread,
Mar 31, 2008, 12:07:27 AM3/31/08
to pyglet...@googlegroups.com
Jamie wrote:
> Hi,
>
> I've finally had a chance to write some code to try and do this and it
> just
> doesn't seem to display anything. I'm probably doing something
> stupid, but
> I can't see it. I've set up a minimal test case that replicates what
> i'm
> doing in my app (below), and it also fails to display anything. Is
> there a
> flag i'm missing? Gary, does this look similar to what you do in your
> code?
>
It's close, but there are several little problems.

* If you are going to do depth testing, you need to clear the depth
buffer. Otherwise all draws past the first will not pass the depth
test and fail to draw anything.

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)


* Your array's type is (by default) numpy.float64 (i.e., doubles),
but you tell glVertexPointer that you are passing floats. This is
what you should tell it. (Or, since doubles are way overkill,
change your array to dtype=numpy.float32).
glVertexPointer(2,GL_DOUBLE,

0,self.cverts.ctypes.data_as(ctypes.POINTER(ctypes.c_double)))

* Your call to glDrawArrays is supposed to provide the number of
vertices not the number of quads.
glDrawArrays(GL_QUADS,0,4*50)

* Your method of building arrays is VERY inefficient -- every append
creates a new array, copies from the old, and ultimately deletes the
old. Try this instead:
self.vertarray = array([ [10+10*i,10+10*i, 10+10*i,20+10*i,
20+10*i,20+10*i, 20+10*i,10+10*i]
for i in range(50)
],
dtype=float64)
self.vertarray=self.vertarray.reshape(50*4,2) # Unneeded,
but nice

(I threw the +10*i into each coordinate to calculate 50 *different*
quads rather than one quad 50 times.)

* The call
glEnable(GL_VERTEX_ARRAY)
is not needed. In fact it's wrong, but seems to neither hurt nor
cause an error. Weird.

* The calls to glPushClientAttrib and glPopClientAttrib do nothing
useful (in this code; Don't know about your real code).


Hope that helps.

Gary Herron


--
Gary Herron, PhD.
Department of Computer Science
DigiPen Institute of Technology
(425) 895-4418

Gary Herron

unread,
Mar 31, 2008, 12:25:26 AM3/31/08
to pyglet...@googlegroups.com
Gary Herron wrote:
> Jamie wrote:
>
>> Hi,
>>
Sorry, after all those changes, I probably should have included a final
working version.

Gary Herron

t.py

Jamie

unread,
Mar 31, 2008, 3:47:46 AM3/31/08
to pyglet-users
Hi,

Thanks again for your help. I had a clear for the depth buffer in the
real code, and had tried passing the number of vertices rather than
quads, so I think the type of the array was the main issue. I
probably wouldn't have spotted that, as I didn't know you could define
the type of the array in numpy. I'll read a bit more about numpy now!

Thanks,

Jamie

gzy

unread,
May 26, 2008, 1:55:44 PM5/26/08
to pyglet-users
I managed to get gldrawelements in a similiar fashion:

self.cverts = ascontiguousarray(self.vertarray)
self.indices = array(range(4*40), dtype=int32)
self.cindices = ascontiguousarray(self.indices)
#glDrawArrays(GL_QUADS,0,4*50)

glDrawElements(GL_QUADS, len(self.indices), GL_UNSIGNED_INT,
self.cindices.ctypes.data_as(ctypes.POINTER(ctypes.c_int)) )


this works, and now I would like to try vbo's, but that can wait.
this get's ugly pretty soon and it seams this is the kind of tasks
pyglet should help with.
I'm using pyglet.graphics.draw_indexed now, but probably pyglet must
parse my lists at each frame.

Could someone point me to some examples of using for example an
IndexedVertexList?
I imagine I could create it once, and just call it's draw() method.

To drag the numpy thread a bit more:
What is the suggested approach to dealing with flattening lists? I
want my vertices as an array of arrays so I can use
all the vector operations on them, at the same time pyglet want's a
flat list.
If reshape it for the VertexList creation, can I reshape it back and
modify it's .vertices property without breaking anything?

--
best regards,
grzes

Alex Holkner

unread,
May 26, 2008, 7:29:32 PM5/26/08
to pyglet...@googlegroups.com

If the array is contiguous, then yes. The reshape functions return
arrays that share the same underlying data in this case, so you don't
need to continually reshape it for pyglet and then for yourself, just
once during initialisation.

If you're really serious about using numpy with pyglet.graphics, your
best bet is probably to subclass
pyglet.graphics.vertexbuffer.AbstractBuffer to use a numpy array as
the underlying storage (anything else, and you will need to always
copy data into pyglet's internal array or the VBO). If done
correctly, the rest of the pyglet.graphics abstractions should fit
over this numpy array/buffer without modification (I think). Hooking
your subclassed buffer into the Batch as the default class may require
a little hacking (I can provide hooks for this in future releases if
it turns out to be useful).

Alex.

Reply all
Reply to author
Forward
0 new messages