Slicer3:Python:ScriptedActor
After a conversation with Gordon Kindlmann, I (Steve Pieper) decided to try an experiment...
Question
Can python be used to tie non-VTK-aware OpenGL C++ code into VTK?
Answer
I checked in some code to make this possible. The C++ class, vtkOpenGLScriptedActor, allows you to specify a script that should be executed inside the VTK render process. This calls out to python, where arbitrary code can be run (something like a callback).
The example script shows how to draw some simple OpenGL shapes in the same window with a VTK managed sphere. The example relies on having PyOpenGL installed in Slicer's python.
The result is shown in the image to the right.
The excerpt of code below shows how the actor is instanced and used.
sactor = s.vtkOpenGLScriptedActor() sactor.SetMapper(mapper) # not really used, but needed so actor is called sactor.SetScript('Render()') ren1.AddActor(sactor) def Render(): glDisable( GL_CULL_FACE ) ## Moves the drawing origin 1.5 units to the left glTranslatef(-1.5,0.0,0.0) ## Starts the geometry generation mode glBegin(GL_TRIANGLES) glVertex3f( 0.0, 1.0, 0.0) glVertex3f(-1.0, -1.0, 0.0) glVertex3f( 1.0, -1.0, 0.0) glEnd()
Considerations
Making individual vertex calls through python is not advised for efficiency, however that doesn't mean this is simply a demo. In particular, there are some ways this could be applied:
- OpenGL is moving to Vertex Buffer Objects and these are interoperable with numpy arrays, so large amounts of data can be manipulated with single calls.
- The python code can invoke arbitrary C or C++ code through various mechanisms. If this code isn't VTK-aware, then the python code may be able to provide the needed compatibility glue.
- Additional experiments and research will be needed to determine how much OpenGL state needs to be explicitly saved and restored in order to ensure that VTK assumptions are met. Mike Halle points out that OpenGL state saving/restoring can be expensive, so care should be taken.
- The python code can be passed references to VTK objects (like vtkImageData or vtkPolyData) from which the data arrays can be made available as numpy arrays to feed into custom rendering code. Similarly, a vtkProperty can be used to store rendering parameters.