我想使用qt和pyopengl进行一些实时绘图,并了解一些关于OpenGL的知识,但是我甚至很难让我的initail测试数据显示出来。
其思想是将X坐标和Y坐标存储在不同的缓冲区中,因为X坐标很少更改,而Y坐标几乎会更改每个渲染。不幸的是,把它们放在不同的缓冲区会给我带来问题。
现在我没有错误,也没有任何东西出现,所以我不知道该去哪里。
以下是迄今为止我对绘图类的了解:

class GLWidget(QtOpenGL.QGLWidget):
    def __init__(self, parent=None):
        self.parent = parent
        QtOpenGL.QGLWidget.__init__(self, parent)
        self.current_position = 0

    def initializeGL(self):
        self.initGeometry()

        self.vertex_code = """
            #version 120
            attribute vec4 color;
            attribute float x_position;
            attribute float y_position;
            varying vec4 v_color;
            void main()
            {
                gl_Position = vec4(x_position, y_position, 0.0, 1.0);
                v_color = color;
            } """

        self.fragment_code = """
            #version 120
            varying vec4 v_color;
            void main()
            {
                //gl_FragColor = v_color;
                gl_FragColor = vec4(1,1,1,1);
            } """

        ## Build and activate program
        # Request program and shader slots from GPU
        self.program = GL.glCreateProgram()
        self.vertex = GL.glCreateShader(GL.GL_VERTEX_SHADER)
        self.fragment = GL.glCreateShader(GL.GL_FRAGMENT_SHADER)

        # Set shaders source
        GL.glShaderSource(self.vertex, self.vertex_code)
        GL.glShaderSource(self.fragment, self.fragment_code)

        # Compile shaders
        GL.glCompileShader(self.vertex)
        GL.glCompileShader(self.fragment)

        # Attach shader objects to the program
        GL.glAttachShader(self.program, self.vertex)
        GL.glAttachShader(self.program, self.fragment)

        # Build program
        GL.glLinkProgram(self.program)

        # Get rid of shaders (not needed anymore)
        GL.glDetachShader(self.program, self.vertex)
        GL.glDetachShader(self.program, self.fragment)

        # Make program the default program
        GL.glUseProgram(self.program)

        # Create array object
        self.vao = GL.glGenVertexArrays(1)
        GL.glBindVertexArray(self.vao)

        # Request buffer slot from GPU
        self.x_data_buffer = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.x_data_buffer)
        GL.glBufferData(GL.GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(self.x), self.x, GL.GL_DYNAMIC_DRAW)

        self.y_data_buffer = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.y_data_buffer)
        GL.glBufferData(GL.GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(self.y), self.y, GL.GL_DYNAMIC_DRAW)




        ## Bind attributes
        #self.stride = self.x.strides[0]
        #self.offset = ctypes.c_void_p(0)
        self.loc = GL.glGetAttribLocation(self.program, "x_position".encode('utf-8'))
        GL.glEnableVertexAttribArray(self.loc)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.x_data_buffer)
        GL.glVertexAttribPointer(self.loc, 1, GL.GL_FLOAT, GL.GL_FALSE, 0, 0)

        #self.stride = self.y.strides[0]
        #self.offset = ctypes.c_void_p(0)
        self.loc = GL.glGetAttribLocation(self.program, "y_position".encode('utf-8'))
        GL.glEnableVertexAttribArray(self.loc)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.y_data_buffer)
        GL.glVertexAttribPointer(self.loc, 1, GL.GL_FLOAT, GL.GL_FALSE, 0, 0)


    def resizeGL(self, width, height):
        if height == 0: height = 1

        GL.glViewport(0, 0, width, height)
        GL.glMatrixMode(GL.GL_PROJECTION)
        GL.glLoadIdentity()
        aspect = width / float(height)

        GLU.gluPerspective(45.0, aspect, 1.0, 100.0)
        GL.glMatrixMode(GL.GL_MODELVIEW)

    def paintGL(self):
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

        GL.glDrawArrays(GL.GL_LINE_STRIP, 0, self.bins)


    def initGeometry(self):
        self.bins = 1000

        self.x = np.linspace(-0.5,0.5,self.bins)
        self.y = np.array([np.sin(val*2*np.pi) for val in self.x])
        self.color = np.array([(1,1,1,1) for x in np.arange(self.bins)])


    def addPoint(self, point):
        #print('ADD POINT')
        self.y[self.current_position] = point
        if self.current_position < self.bins-1:
            self.current_position += 1
        else:
            self.current_position = 0

        return True

    def render(self):
        #print('RENDER')
        self.updateGL()
        return True

我还把程序的完整工作版本放在这里:
import sys
from PyQt5.QtWidgets import QDesktopWidget, QMainWindow, QWidget, QAction, qApp, QApplication, QHBoxLayout, QVBoxLayout, QPushButton
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QIcon
from PyQt5 import QtOpenGL

from OpenGL import GL
from OpenGL import GLU
from OpenGL.arrays.arraydatatype import ArrayDatatype

import ctypes
import numpy as np
from threading import Timer, Thread, Event

class OxySensor(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.initActions()
        self.initMenuBar()
        self.initRenderTimer()
        self.start()

    def initUI(self):
        self.resize(800,600)
        self.center()
        self.setWindowTitle('OxySensor')

        okButton = QPushButton("OK")
        cancelButton = QPushButton("Cancel")


        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(okButton)
        hbox.addWidget(cancelButton)

        vbox = QVBoxLayout()
        #vbox.addStretch(1)
        self.gl_widget = GLWidget()
        vbox.addWidget(self.gl_widget)
        vbox.addLayout(hbox)

        mainWidget = QWidget(self)
        mainWidget.setLayout(vbox)

        self.setCentralWidget(mainWidget)


        self.show()

    def initActions(self):
        self.exitAction = QAction(QIcon('images/close20.png'), '&Exit', self)
        self.exitAction.setShortcut('Ctrl+W')
        self.exitAction.setStatusTip('Exit application')
        self.exitAction.triggered.connect(self.onExit)

    def initMenuBar(self):
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(self.exitAction)
        return True

    def initRenderTimer(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.gl_widget.render)
        self.timer.start(100)
        return True

    def start(self):
        self.stop_flag = Event()
        self.thread = SerialPort(self.onTimerExpired, self.stop_flag)
        self.thread.start()
        self.statusBar().showMessage('Ready')

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
        return True

    def onTimerExpired(self):
        data = np.random.uniform(-1,1)
        self.gl_widget.addPoint(data)
        return True

    def onExit(self):
        self.close()
        return None

    def closeEvent(self,event):
        self.stop_flag.set()
        event.accept()
        return None

class GLWidget(QtOpenGL.QGLWidget):
    def __init__(self, parent=None):
        self.parent = parent
        QtOpenGL.QGLWidget.__init__(self, parent)
        self.yRotDeg = 0.0
        self.current_position = 0

    def initializeGL(self):
        self.initGeometry()

        self.vertex_code = """
            #version 120
            attribute vec4 color;
            attribute float x_position;
            attribute float y_position;
            varying vec4 v_color;
            void main()
            {
                gl_Position = vec4(x_position, y_position, 0.0, 1.0);
                v_color = color;
            } """

        self.fragment_code = """
            #version 120
            varying vec4 v_color;
            void main()
            {
                //gl_FragColor = v_color;
                gl_FragColor = vec4(1,1,1,1);
            } """

        ## Build and activate program
        # Request program and shader slots from GPU
        self.program = GL.glCreateProgram()
        self.vertex = GL.glCreateShader(GL.GL_VERTEX_SHADER)
        self.fragment = GL.glCreateShader(GL.GL_FRAGMENT_SHADER)

        # Set shaders source
        GL.glShaderSource(self.vertex, self.vertex_code)
        GL.glShaderSource(self.fragment, self.fragment_code)

        # Compile shaders
        GL.glCompileShader(self.vertex)
        GL.glCompileShader(self.fragment)

        # Attach shader objects to the program
        GL.glAttachShader(self.program, self.vertex)
        GL.glAttachShader(self.program, self.fragment)

        # Build program
        GL.glLinkProgram(self.program)

        # Get rid of shaders (not needed anymore)
        GL.glDetachShader(self.program, self.vertex)
        GL.glDetachShader(self.program, self.fragment)

        # Make program the default program
        GL.glUseProgram(self.program)

        # Create array object
        self.vao = GL.glGenVertexArrays(1)
        GL.glBindVertexArray(self.vao)

        # Request buffer slot from GPU
        self.x_data_buffer = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.x_data_buffer)
        GL.glBufferData(GL.GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(self.x), self.x, GL.GL_DYNAMIC_DRAW)

        self.y_data_buffer = GL.glGenBuffers(1)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.y_data_buffer)
        GL.glBufferData(GL.GL_ARRAY_BUFFER, ArrayDatatype.arrayByteCount(self.y), self.y, GL.GL_DYNAMIC_DRAW)




        ## Bind attributes
        #self.stride = self.x.strides[0]
        #self.offset = ctypes.c_void_p(0)
        self.loc = GL.glGetAttribLocation(self.program, "x_position".encode('utf-8'))
        GL.glEnableVertexAttribArray(self.loc)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.x_data_buffer)
        GL.glVertexAttribPointer(self.loc, 1, GL.GL_FLOAT, GL.GL_FALSE, 0, 0)

        #self.stride = self.y.strides[0]
        #self.offset = ctypes.c_void_p(0)
        self.loc = GL.glGetAttribLocation(self.program, "y_position".encode('utf-8'))
        GL.glEnableVertexAttribArray(self.loc)
        GL.glBindBuffer(GL.GL_ARRAY_BUFFER, self.y_data_buffer)
        GL.glVertexAttribPointer(self.loc, 1, GL.GL_FLOAT, GL.GL_FALSE, 0, 0)


    def resizeGL(self, width, height):
        if height == 0: height = 1

        GL.glViewport(0, 0, width, height)
        GL.glMatrixMode(GL.GL_PROJECTION)
        GL.glLoadIdentity()
        aspect = width / float(height)

        GLU.gluPerspective(45.0, aspect, 1.0, 100.0)
        GL.glMatrixMode(GL.GL_MODELVIEW)

    def paintGL(self):
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)

        GL.glDrawArrays(GL.GL_LINE_STRIP, 0, self.bins)


    def initGeometry(self):
        self.bins = 1000

        self.x = np.linspace(-0.5,0.5,self.bins)
        self.y = np.array([np.sin(val*2*np.pi) for val in self.x])
        self.color = np.array([(1,1,1,1) for x in np.arange(self.bins)])


    def addPoint(self, point):
        #print('ADD POINT')
        self.y[self.current_position] = point
        if self.current_position < self.bins-1:
            self.current_position += 1
        else:
            self.current_position = 0

        return True

    def render(self):
        #print('RENDER')
        self.updateGL()
        return True

class SerialPort(Thread):
    def __init__(self, callback, event):
        Thread.__init__(self)
        self.callback = callback
        self.stopped = event
        return None

    def SetInterval(self, time_in_seconds):
        self.delay_period = time_in_seconds
        return True

    def run(self):
        while not self.stopped.wait(0.1):
            self.callback()
        return True

if __name__ == '__main__':
    app = QApplication(sys.argv)
    oxy_sensor = OxySensor()
    sys.exit(app.exec_())

最佳答案

问题很可能是“opengl.gl”函数的调用:

GL.glVertexAttribPointer(self.loc, 1, GL.GL_FLOAT, GL.GL_FALSE, 0, 0)

注意最后一个值是0(不幸的是,在(void *)0api中,它没有转换为C++,而是转换为一些高地址)。您最可能的意思是“偏移0”,而不是“0对象的地址”。也就是说,使用None代替(它确实转换为(void *)0):
GL.glVertexAttribPointer(self.loc, 1, GL.GL_FLOAT, GL.GL_FALSE, 0, None)

是的,这有点违反直觉。我花了半天的时间才弄明白这就是为什么输出在我自己的代码中变黑的原因。
还要注意,如果使用qt函数(通过OpenGL.GL获得)而不是gl = self.context().versionFunctions()函数,则它们提供的API稍有不同,当您的意思是“offset 0”时,实际上会传递0。

关于python - 用PyOpenGL绘制麻烦,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33505731/

10-09 05:23