OpenGL and VTK compatibility

Hey all,

I’m working with PyQt5 and OpenGL. In my application, I need to show a 3D model (STL) within the OpenGL widget, and I was wanting to see if its possible to draw the model using VTK and do the rotation handling with OpenGL (I already have the code set up and don’t want to transfer everything over to a new library). I can’t render the STL properly within OpenGL due to its large file size, and have memory issues when doing rotation handling with VTK.

Here are my current versions:

vtk 9.3.0
pyopengl 3.1.7
PyQt5 5.15.10

If you need anything explained better, let me know. Any advice/help is appreciated!

VTK uses OpenGL for rendering. Take a look at the ReadSTL example for how to read and render an STL file with VTK.

I am still a little confused. This is my current class which populates an OpenGL widget in PyQt5. (There’s an additional method that reads rotation data over serial, but it’s not included.) How would I be able to draw the STL using what I currently have? Currently I draw a cube within paintGL.

class OpenGLWidget(QOpenGLWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.roll = 0.0
        self.pitch = 0.0
        self.yaw = 0.0

    def initializeGL(self):
        glEnable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.0, 0.0, 1.0)

    def resizeGL(self, width, height):
        glViewport(0, 0, width, height)
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        aspect_ratio = width / height
        gluPerspective(45, aspect_ratio, 0.1, 100.0)
        glMatrixMode(GL_MODELVIEW)

    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        glTranslatef(0.0, 0.0, -10.0)
        glRotatef(self.pitch, -1.0, 0.0, 0.0)
        #glRotatef(self.yaw, 0.0, 1.0, 0.0)
        glRotatef(self.roll, 0.0, 0.0, -1.0)

        # Cube
        glBegin(GL_QUADS)

        glColor3f(1.0, 0.0, 0.0)
        glVertex3f(1.0, 1.0, -1.0)
        glVertex3f(-1.0, 1.0, -1.0)
        glVertex3f(-1.0, 1.0, 1.0)
        glVertex3f(1.0, 1.0, 1.0)

        glColor3f(0.0, 1.0, 0.0)
        glVertex3f(1.0, -1.0, 1.0)
        glVertex3f(-1.0, -1.0, 1.0)
        glVertex3f(-1.0, -1.0, -1.0)
        glVertex3f(1.0, -1.0, -1.0)

        glColor3f(0.0, 0.0, 1.0)
        glVertex3f(1.0, 1.0, 1.0)
        glVertex3f(-1.0, 1.0, 1.0)
        glVertex3f(-1.0, -1.0, 1.0)
        glVertex3f(1.0, -1.0, 1.0)

        glColor3f(1.0, 1.0, 0.0)
        glVertex3f(1.0, -1.0, -1.0)
        glVertex3f(-1.0, -1.0, -1.0)
        glVertex3f(-1.0, 1.0, -1.0)
        glVertex3f(1.0, 1.0, -1.0)

        glColor3f(0.0, 1.0, 1.0)
        glVertex3f(-1.0, 1.0, 1.0)
        glVertex3f(-1.0, 1.0, -1.0)
        glVertex3f(-1.0, -1.0, -1.0)
        glVertex3f(-1.0, -1.0, 1.0)

        glColor3f(1.0, 0.0, 1.0)
        glVertex3f(1.0, 1.0, -1.0)
        glVertex3f(1.0, 1.0, 1.0)
        glVertex3f(1.0, -1.0, 1.0)
        glVertex3f(1.0, -1.0, -1.0)

        glEnd()

        self.update()

All that opengl set up and context initialization is take care of by VTK. I suggest you start with EmbedInPyQt and build up your visualization there using the ReadSTL example.

I’ve been able to get the STL shown in my PyQt5 window, but I’m stuck on handling the rotations with the serial data. Additionally, I would like to disable the interactor so the user can’t rotate the visual, it must only be done through serial. Do you have any advice on how to do this?

You can Disable the interactor and use the camera to rotate the view programmatically.

Something like:

iren.Disable()
ren.getActiveCamera().azimuth(20)

I apologize for asking as I’m probably missing something obvious, but calling the disable method is not preventing mouse clicks and rotations on the window.

    self.vtkWidget = QVTKRenderWindowInteractor(self.uic.openGLViewer)
    self.vtkWidget.setGeometry(0, 0, 481, 341)
    self.ren = vtkRenderer()
    self.vtkWidget.GetRenderWindow().AddRenderer(self.ren)
    self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()
    self.iren.Disable()

For those wondering how I disabled the interactor, I created this class:

class NoneInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):
    def __init__(self):
        self.SetKeyPressActivation(False)
        self.SetMouseWheelMotionFactor(0)
        self.SetMotionFactor(0)

Then set the None interactor as the interactor using:

        self.vtkWidget = QVTKRenderWindowInteractor(self.uic.openGLViewer)
        self.vtkWidget.setGeometry(0, 0, 481, 341)
        self.ren = vtkRenderer()
        self.vtkWidget.GetRenderWindow().AddRenderer(self.ren)
        self.iren = self.vtkWidget.GetRenderWindow().GetInteractor()
        self.iren.SetInteractorStyle(NoneInteractorStyle())