Hello,

We are trying to visualize some quite big brain white matter datasets with PyOpenGL. We have around a quarter of a million of trajectories where each trajectory consists of up to around 100 line segments. The goal application is to be able to pick/select and update some or all of the trajectories in real time in order to help practitioners find their way through the brain. We had quite a good progress selecting and picking trajectories using gluUnProject however we are not sure which design direction we should take from now on as far as vbos are concernced. According to the Red Book and the community blogs vertex buffer objects should be more preferable than display lists now and in the future and display lists have already being tagged as deprecated. We would very much like your thoughts and feedback about this.

We are testing this software on a Nvidia GeForce GTX 260 and use PyOpenGL 3.0.1

The following class shows what we tried to do. The input of the class as shown in __init__() is data which is a list of trajectories where every trajectory is represented by numpy arrays of shape (N,3) , colors is the similar but a list of arrays of shape (N,4) (where N is different from trajectory to trajectory) and if the lists parameter is True then we use display lists with vbo eitherwise we use vbos only.

Surprisingly, when using lists=True we get more than 30fps and when lists=False we get between 1-2 fps. Any ideas what is the reason for this dramatic change? Shouldn't vbos be the same or faster than dls?

class Tracks():

    def __init__(self,data,colors,line_width=3.,lists=False):

        Actor.__init__(self)
       
        self.data=data
        self.cdata=None
        self.colors=colors
        self.line_width=line_width
        self.list_index = None
        self.vbo = None
        self.lists = lists
       
    def init(self):
        self.init_default()       

    def init_default(self):

        self.counts=[len(d) for d in self.data]
        cdata=np.concatenate(self.data)
        first=np.array(self.counts).cumsum()
        self.first=list(np.hstack((np.array([0]),first[:-1])))       
        ccolors=np.concatenate(self.colors)
        self.min=np.min(cdata,axis=0)
        self.max=np.max(cdata,axis=0)
        self.mean=np.mean(cdata,axis=0)       
        cdata = cdata - self.mean
        self.cdata = cdata
       
        stack=np.hstack((cdata,ccolors))
        stack=stack.astype('float32')
        self.vbo = vbo.VBO(stack,usage='GL_STATIC_DRAW')
        #self.vbo = vbo.VBO(np.hstack((cdata,ccolors)),usage=gl.GL_DYNAMIC_DRAW)

        if self.lists:

            self.list_index = gl.glGenLists(1)
            gl.glNewList( self.list_index,gl.GL_COMPILE)
            self._execute_vbos()
            gl.glEndList()


    def _execute_vbos(self):

        gl.glDisable(gl.GL_LIGHTING)
        gl.glDisable(gl.GL_DEPTH_TEST)
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA,gl.GL_ONE_MINUS_SRC_ALPHA)
        gl.glLineWidth(self.line_width)
       
        self.vbo.bind()
        try:       
            gl.glEnableClientState(gl.GL_VERTEX_ARRAY)       
            gl.glEnableClientState(gl.GL_COLOR_ARRAY)
            #gl.glVertexPointerf(cdata)
            gl.glVertexPointer(3, gl.GL_FLOAT, 28, self.vbo )
            gl.glColorPointer(4, gl.GL_FLOAT, 28, self.vbo+12 )
            gl.glMultiDrawArrays(gl.GL_LINE_STRIP,\
                                 self.first,self.counts,len(self.counts))
        finally:
            self.vbo.unbind()
                       
        gl.glDisableClientState(gl.GL_COLOR_ARRAY)
        gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
        gl.glDisable(gl.GL_BLEND)
        gl.glEnable(gl.GL_LIGHTING)
        gl.glEnable(gl.GL_DEPTH_TEST)


    def display(self):
       
        gl.glPushMatrix()
        x,y,z = self.position
        gl.glTranslatef(x,y,z)

        if self.lists:
            gl.glCallList(self.list_index)
        else:
            self._execute_vbos()      
        
        gl.glPopMatrix()


The Tracks.display function is called from glutDisplayFunc from another file after the object has been initialized using the init function.  We would be very happy to hear about your ideas to make this visualization better and ideas about how to update the datasets using the vbo from OpenGL.arrays or a different method in a nice efficient way.

We would be more than happy to continue using PyOpenGL and contribute to the list in the future. PyOpenGL fits very well with a new project we have created found at nipy.org/dipy .We are more than eager at the moment to switch from python-vtk or mayavi to pyopengl for all our visualization needs as we think that it can deal better with big datasets.

Best wishes,
Eleftherios & Ian