2015-11-03 17 views
17

Ich möchte Qt und PyOpenGL verwenden, um etwas Echtzeitplotten zu machen und ein wenig über OpenGL zu lernen, habe aber Probleme, meine initail-Testdaten zu zeigen.Trouble Plotten mit PyOpenGL

Die Idee ist, die x-Koordinaten und y-Koordinaten in verschiedenen Puffern zu speichern, da sich die x-Koordinaten selten ändern, während die y-Koordinaten fast jedes Render ändern. Leider gibt es Probleme, wenn ich sie in verschiedenen Puffern habe.

Im Moment habe ich keine Fehler und nichts wird angezeigt, so dass ich nicht sicher bin, wohin ich gehen soll. Hier

ist, was ich bisher für die Plotten Klasse:

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 

ich auch eine vollständige Version des Programms setzen sich hier:

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_()) 
+0

Wo ist die 'updateGL()' Methode? Der bisher veröffentlichte Code aktualisiert die VBO-Inhalte nie wirklich, nachdem sie sie erstellt haben. – derhass

+0

'updateGL()' ist in der 'render()' Methode – user2027202827

+0

Nun, ich kann sehen, dass es _called_ dort ist. Vielleicht verstehe ich etwas falsch, und diese 'updateGL' ist eine Methode des pthon OpenGL-Widgets. Wenn das so ist, gilt mein Kommentar noch mehr: Sie aktualisieren diese VBOs dann nie wirklich (was ich in 'updateGL' getan hätte). – derhass

Antwort

3

Das Problem ist sehr wahrscheinlich, dass Anruf von die 'OpenGL.GL' Funktion:

Beachten Sie, dass der letzte Wert 0 ist (was leider nicht trans spät zu (void *)0 in der C++ API, aber stattdessen zu einer hohen Adresse). Sie meinen wahrscheinlich "Offset 0" im Gegensatz zu "die Adresse des Objekts 0". I. e. verwenden None statt (die (void *)0 nicht übersetzen):

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

Ja, es irgendwie eingängig ist. Ich brauchte einen halben Tag, um herauszufinden, dass das die Ausgabe in meinem eigenen Code schwarz machte.

Beachten Sie auch, dass, wenn anstelle der OpenGL.GL Funktionen verwenden Sie die Qt diejenigen (die Sie über gl = self.context().versionFunctions() bekommen), sie eine etwas andere API zur Verfügung stellen und Sie dort passieren tatsächlich 0 wenn du meinst „0 Offset“.

+0

Hey, ich war nicht auf dieser Seite es eine Weile, aber wollte nur, um Ihnen für diese brilliant zu danken, die Übergabe 'None' zu ​​'GL.glVetexAttribPointer()' :) Dank für das Teilen. – user2027202827

-1

Sie sollten einen Blick auf das Programm Avogadro
http://avogadro.cc/wiki/Main_Page , die auf OpenGL-Funktionen basiert.

Der Quellcode ist kostenlos und kann nützlich sein.

+1

Ein Link zu einer möglichen Lösung ist immer willkommen, aber fügen Sie bitte Kontext um den Link hinzu, damit Ihre Mitbenutzer eine Idee haben, was es ist und warum es da ist. Zitiere immer den relevantesten Teil eines wichtigen Links, falls die Zielseite nicht erreichbar ist oder permanent offline geschaltet wird. – Exaqt

+0

... vor allem, da die Verbindung jetzt unterbrochen ist! – uhoh