2015-11-03 17 views
17

Tôi muốn sử dụng Qt và PyOpenGL để làm một số thời gian thực âm mưu và tìm hiểu một chút về OpenGL, nhưng gặp khó khăn ngay cả khi nhận được dữ liệu thử nghiệm initail của tôi để hiển thị.Khó lập kế hoạch với PyOpenGL

Ý tưởng là lưu trữ tọa độ x và tọa độ y trong các bộ đệm khác nhau vì tọa độ x sẽ hiếm khi thay đổi trong khi các điều phối y sẽ thay đổi gần như mọi kết xuất. Thật không may, có chúng trong bộ đệm khác nhau là cho tôi vấn đề.

Hiện tại tôi không có lỗi và không có gì hiển thị nên tôi không biết phải đi đâu.

Dưới đây là những gì tôi có cho đến nay cho lớp âm mưu:

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 

Tôi cũng đặt một phiên bản làm việc đầy đủ của chương trình tại đây:

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

Phương thức 'updateGL()' ở đâu? Mã được đăng cho đến nay không bao giờ thực sự cập nhật nội dung VBO sau khi bắt đầu tạo chúng. – derhass

+0

'updateGL()' nằm trong phương thức 'render()' – user2027202827

+0

Vâng, tôi có thể thấy rằng nó được _called_ ở đó. Có lẽ tôi hiểu lầm một cái gì đó, và điều này 'updateGL' là một số phương pháp của widget OpenGL pthon. Nếu vậy, sau đó bình luận của tôi áp dụng nhiều hơn, mặc dù: bạn không bao giờ thực sự cập nhật những VBOs sau đó (mà tôi giả định được thực hiện trong 'updateGL'). – derhass

Trả lời

3

Vấn đề là khả năng nhất mà tiếng gọi của chức năng 'OpenGL.GL':

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

Lưu ý giá trị cuối cùng là 0 (tiếc là không chuyển đổi trễ đến (void *)0 trong API C++, nhưng thay vào đó là một số địa chỉ cao). Bạn có nhiều khả năng có nghĩa là "bù đắp 0" như trái ngược với "địa chỉ của đối tượng 0". I E. sử dụng None thay vì (mà không dịch để (void *)0):

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

Vâng, nó kinda phản trực giác. Tôi mất nửa ngày để tìm ra đó là những gì làm cho đầu ra màu đen trong mã của riêng tôi.

Cũng lưu ý rằng nếu thay vì OpenGL.GL chức năng bạn sử dụng Qt người (mà bạn nhận được qua gl = self.context().versionFunctions()), họ cung cấp một API hơi khác nhau và ở đó bạn thực sự vượt qua 0 khi bạn có nghĩa là "Offset 0".

+0

Hey, tôi đã không được trên trang web này một lúc nhưng chỉ muốn cảm ơn bạn cho rằng bắt briliant đi qua 'None' để' GL.glVertexAttribPointer() ':) Cảm ơn bạn đã chia sẻ. – user2027202827

-1

Bạn nên xem chương trình Avogadro
http://avogadro.cc/wiki/Main_Page dựa trên chức năng OpenGL.

Mã nguồn miễn phí và có thể hữu ích.

+1

Liên kết đến giải pháp tiềm năng luôn được chào đón, nhưng vui lòng thêm ngữ cảnh xung quanh liên kết để người dùng của bạn sẽ có một số ý tưởng về nó và lý do tại sao nó ở đó. Luôn trích dẫn phần có liên quan nhất của một liên kết quan trọng, trong trường hợp trang web mục tiêu không thể truy cập được hoặc sẽ vĩnh viễn ngoại tuyến. – Exaqt

+0

... đặc biệt là kể từ khi liên kết bị hỏng! – uhoh

Các vấn đề liên quan