from PyQt5 import QtWidgets as qtw from PyQt5 import QtGui as qtg import sys class MainWindow(qtw.QMainWindow): def __init__(self): super().__init__() # Your code goes here self.resize(800, 600) main = qtw.QWidget() self.setCentralWidget(main) main.setLayout(qtw.QVBoxLayout()) oglw = GlWidget() main.layout().addWidget(oglw) # Animation controls btn_layout = qtw.QHBoxLayout() main.layout().addLayout(btn_layout) for direction in ('none', 'left', 'right', 'up', 'down'): button = qtw.QPushButton( direction, autoExclusive=True, checkable=True, clicked=getattr(oglw, f'spin_{direction}') ) btn_layout.addWidget(button) zoom_layout = qtw.QHBoxLayout() main.layout().addLayout(zoom_layout) zoom_in = qtw.QPushButton('zoom in', clicked=oglw.zoom_in) zoom_layout.addWidget(zoom_in) zoom_out = qtw.QPushButton('zoom out', clicked=oglw.zoom_out) zoom_layout.addWidget(zoom_out) self.show() class GlWidget(qtw.QOpenGLWidget): """A widget to display our OpenGL drawing""" def initializeGL(self): super().initializeGL() # Fetch version-specific functions gl_context = self.context() version = qtg.QOpenGLVersionProfile() version.setVersion(2, 1) self.gl = gl_context.versionFunctions(version) # Configure self.gl.glEnable(self.gl.GL_DEPTH_TEST) self.gl.glDepthFunc(self.gl.GL_LESS) self.gl.glEnable(self.gl.GL_CULL_FACE) # Create the program self.program = qtg.QOpenGLShaderProgram() self.program.addShaderFromSourceFile( qtg.QOpenGLShader.Vertex, 'vertex_shader.glsl') self.program.addShaderFromSourceFile( qtg.QOpenGLShader.Fragment, 'fragment_shader.glsl') self.program.link() # Get variable locations self.vertex_location = self.program.attributeLocation('vertex') self.matrix_location = self.program.uniformLocation('matrix') self.color_location = self.program.attributeLocation('color_attr') # Create transformation matrix self.view_matrix = qtg.QMatrix4x4() self.view_matrix.perspective( 45, # Angle self.width() / self.height(), # Aspect Ratio 0.1, # Near clipping plane 100.0 # Far clipping plane ) self.view_matrix.translate(0, 0, -5) self.rotation = [0, 0, 0, 0] def paintGL(self): # Fill the window with dark violet self.gl.glClearColor(0.1, 0, 0.2, 1) self.gl.glClear( self.gl.GL_COLOR_BUFFER_BIT | self.gl.GL_DEPTH_BUFFER_BIT) self.program.bind() # Drawing front_vertices = [ qtg.QVector3D(0.0, 1.0, 0.0), # Peak qtg.QVector3D(-1.0, 0.0, 0.0), # Bottom left qtg.QVector3D(1.0, 0.0, 0.0) # Bottom right ] face_colors = ( qtg.QColor('red'), qtg.QColor('orange'), qtg.QColor('yellow'), ) gl_colors = [ self.qcolor_to_glvec(color) for color in face_colors ] self.program.setUniformValue( self.matrix_location, self.view_matrix) self.program.enableAttributeArray(self.vertex_location) self.program.setAttributeArray(self.vertex_location, front_vertices) self.program.enableAttributeArray(self.color_location) self.program.setAttributeArray(self.color_location, gl_colors) # Draw the front self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, 3) # Draw the back back_vertices = [ qtg.QVector3D(x.toVector2D(), -0.5) for x in front_vertices] self.program.setAttributeArray( self.vertex_location, reversed(back_vertices)) # If you try the line below instead, the back side # will not show unless you disable face culling #self.vertex_location, back_vertices) self.gl.glDrawArrays(self.gl.GL_TRIANGLES, 0, 3) # draw the sides sides = [(0, 1), (1, 2), (2, 0)] side_vertices = list() for index1, index2 in sides: side_vertices += [ front_vertices[index1], back_vertices[index1], back_vertices[index2], front_vertices[index2] ] side_colors = [ qtg.QColor('blue'), qtg.QColor('purple'), qtg.QColor('cyan'), qtg.QColor('magenta'), ] gl_colors = [ self.qcolor_to_glvec(color) for color in side_colors ] * 3 self.program.setAttributeArray(self.color_location, gl_colors) self.program.setAttributeArray(self.vertex_location, side_vertices) self.gl.glDrawArrays(self.gl.GL_QUADS, 0, len(side_vertices)) self.program.disableAttributeArray(self.vertex_location) self.program.disableAttributeArray(self.color_location) self.program.release() # Animation # rotate self.view_matrix.rotate(*self.rotation) self.update() def qcolor_to_glvec(self, qcolor): return qtg.QVector3D( qcolor.red() / 255, qcolor.green() / 255, qcolor.blue() / 255 ) def spin_none(self): self.rotation = [0, 0, 0, 0] def spin_left(self): self.rotation = [-1, 0, 1, 0] def spin_right(self): self.rotation = [1, 0, 1, 0] def spin_up(self): self.rotation = [1, 1, 0, 0] def spin_down(self): self.rotation = [-1, 1, 0, 0] def zoom_in(self): self.view_matrix.scale(1.1, 1.1, 1.1) def zoom_out(self): self.view_matrix.scale(.9, .9, .9) if __name__ == '__main__': app = qtw.QApplication(sys.argv) mw = MainWindow() app.exec_()