在QGLWidget上绘画失败

时间:2016-01-19 13:48:19

标签: python qt opengl pyqt pyopengl

我试图通过QPainter绘制QGLWidget,如各种教程中所述。在我的paintGL()函数中,我有两个案例。实际上,如果在OpenGL中没有任何东西可以绘制,那么我只使用QPainter绘制2条线(这部分确实有用)。但是,当有一些东西可以用OpenGL绘制时,我首先使用一个OpenGL函数,比如drawElements()然后我用我的画家来重写小部件,但在这种情况下我只能显示我的OpenGL“对象”,这两行看不见。

这是我的paintGL方法的代码:

def paintGL(self): 


        glClearColor(0, 0, 0, 1)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)



        if np.array(self.objects).size:

            print('there are %i objects'%(len(self.objects)))
            #                


            # active shader program
            glUseProgram(self.shaderProgram)

            for i, obj in enumerate(self.objects):        

                loc_pos = glGetAttribLocation(self.shaderProgram, "position")
                glEnableVertexAttribArray(loc_pos)
                glBindBuffer(GL_ARRAY_BUFFER, obj.VBO[0])
                glVertexAttribPointer(loc_pos, 2, GL_FLOAT, False, 0,  ctypes.c_void_p(0))

                loc_col = glGetAttribLocation(self.shaderProgram, "color")
                glEnableVertexAttribArray(loc_col)

                glBindBuffer(GL_ARRAY_BUFFER, obj.VBO[1])
                glVertexAttribPointer(loc_col, 4, GL_FLOAT, False, 0,  ctypes.c_void_p(0))


                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj.VBO[2])
                glDrawElements(GL_TRIANGLES, obj.indices.size, GL_UNSIGNED_INT, ctypes.c_void_p(0))


            glUseProgram(0)


            painter = QtGui.QPainter()
            painter.begin(self)
            painter.setRenderHint(QtGui.QPainter.Antialiasing)
            print(painter.isActive())


            pen = QtGui.QPen(QtGui.QColor(255,0,0), 10)

            x = 100
            y= 100       

            # clean previous drawings        
            painter.fillRect(self.rect(),QtGui.QBrush(QtGui.QColor(0,0,0)) )
            painter.setPen(pen)

            currentFont = painter.font()
            currentFont.setPointSize(currentFont.pointSize()*4)
            painter.setFont(currentFont)
            painter.drawLine(x, 0, x, self.height())
            painter.drawLine(0, y, self.width(), y)    


            painter.end()

        else:

            print('No data in objects ==> no drawing')
            painter = QtGui.QPainter()
            painter.begin(self)
            painter.setRenderHint(QtGui.QPainter.Antialiasing)
            print(painter.isActive())


            pen = QtGui.QPen(QtGui.QColor(255,0,0), 10)

            x = 100
            y= 100       

            # clean previous drawings        
            painter.fillRect(self.rect(),QtGui.QBrush(QtGui.QColor(0,0,0)) )
            painter.setPen(pen)

            currentFont = painter.font()
            currentFont.setPointSize(currentFont.pointSize()*4)
            painter.setFont(currentFont)
            painter.drawLine(x, 0, x, self.height())
            painter.drawLine(0, y, self.width(), y)    


            painter.end()

更新

更确切地说,当我启动我的应用程序时,一切都很好。当我更新我的相机矩阵(通过鼠标事件)时,它的行为符合预期,因为我仍然可以看到QPainter绘图。但是,当我点击我的应用程序中的一个按钮(这样一个按钮触发一个方法,包括通过glBindBuffer()和glBufferData填充缓冲区),而我的paintGL()方法被调用时,不会出现QPainter的绘图,只有OpenGL数据。

更新第2期:

另外,我提供了一些代码:

我的GLWidget类:

import ctypes

import numpy
import numpy as np
from OpenGL.GL import *
from OpenGL.GL import shaders
import FN_functions as fn
from PyQt4 import QtGui, QtCore, QtOpenGL


VERTEX_SHADER = """
#version 440 core

uniform float scale;
uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;

in vec2 position;   
in vec4 color;     

out vec4 v_color;


void main()
{
    gl_Position =  Projection*View*Model*vec4(scale*position, 0.0, 1.0);
    v_color = color;

}
 """


FRAGMENT_SHADER = """
    #version 440 core

    in vec4 v_color;



    void main()
    {
        gl_FragColor = v_color;


    } """



class MyWidget(QtOpenGL.QGLWidget):

    def __init__(self):

        super(MyWidget, self).__init__()
        self.objects = []
        self.camTarget = np.array([0,0,0])
        self.camEye = np.array([0,0,10])
        self.camUp = np.array([0, 1, 0])




        # by default, GLwidget does not accept any focus as there is no text input
        self.setFocusPolicy(QtCore.Qt.StrongFocus)

        # avoid blinking when repainting
        self.setAutoFillBackground(False)

        self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent)
        self.setAttribute(QtCore.Qt.WA_NoSystemBackground)

        self.setMouseTracking(True)



    def initializeGL(self):
        #glViewport(0, 0, self.width(), self.height())
        print('initializeGL')

        # compile shaders and program
        vertexShader = shaders.compileShader(VERTEX_SHADER, GL_VERTEX_SHADER)
        fragmentShader = shaders.compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
        self.shaderProgram = shaders.compileProgram(vertexShader, fragmentShader)
        print(self.shaderProgram)

        # Init uniforms    
        glUseProgram(self.shaderProgram)                        

        # Scale
        loc = glGetUniformLocation(self.shaderProgram, 'scale')
        glUniform1f(loc, 1)

        # Model matrix
        matModel = fn.translate((2*np.random.rand(1), 2*np.random.rand(1), 2*np.random.rand(1)))
        loc = glGetUniformLocation(self.shaderProgram, 'Model')
        glUniformMatrix4fv(loc, 1, True, np.asfortranarray(matModel))
        # View matrix
        matView = fn.lookat(np.array([0,0,0]), np.array([0,0,10]), np.array([0,1,0]))
        loc = glGetUniformLocation(self.shaderProgram, 'View')
        glUniformMatrix4fv(loc, 1, True, np.asfortranarray(matView))
        # Projection matrix
        matProj = fn.perspective(fovy=45, aspect=1.0, n=1.0, f=100000.0)
        loc = glGetUniformLocation(self.shaderProgram, 'Projection')
        glUniformMatrix4fv(loc, 1, True, np.asfortranarray(matProj))

        glUseProgram(0)





    def wheelEvent(self,  e):

        zStep = -e.delta()/10

        self.camEye[2] += zStep
        self.updateCamera()



    def keyPressEvent(self, e):

        xStep, yStep = (1, 1)          

        if e.key() == QtCore.Qt.Key_Z:
            self.camEye[1] += yStep
            self.camTarget[1] += yStep
        elif e.key() == QtCore.Qt.Key_S:
            self.camEye[1] -= yStep
            self.camTarget[1] -= yStep
        elif e.key() == QtCore.Qt.Key_Q:
            self.camEye[0] += xStep
            self.camTarget[0] += xStep
        elif e.key() == QtCore.Qt.Key_D:
            self.camEye[0] -= xStep
            self.camTarget[0] -= xStep

        self.updateCamera()



    def updateCamera(self):

        matView = fn.lookat(self.camEye, self.camTarget, self.camUp)
        glUseProgram(self.shaderProgram)
        loc = glGetUniformLocation(self.shaderProgram, 'View')
        glUniformMatrix4fv(loc, 1, True, np.asfortranarray(matView))

        self.updateGL()



#    def mouseMoveEvent(self, e):
#        
#        print(self.context())
#        
#        self.makeCurrent()
#        self.swapBuffers()
#        print('mouseMoveEvent')
#        print(e.pos())
#        x, y = e.pos().x(), e.pos().y()
#        
#        pen = QtGui.QPen(QtGui.QColor(255,0,0), 10)
#        
#        
#        self.painter.begin(self)     
#        
#        
#        # clean previous drawings        
#        self.painter.fillRect(self.rect(),QtGui.QBrush(QtGui.QColor(0,0,0)) )
#        self.painter.setPen(pen)
#
#        currentFont = self.painter.font()
#        currentFont.setPointSize(currentFont.pointSize()*4)
#        self.painter.setFont(currentFont)
#        #painter.fillRect(e.rect(), QtGui.QBrush(QtGui.QColor(64,32,64)))                
#        self.painter.drawLine(x, 0, x, self.height())
#        self.painter.drawLine(0, y, self.width(), y)       
#
#        self.painter.end()


#    def paintEvent(self, e):
#        print('paintEvent')
#
#        
#        print(self.context())
#        
#        self.makeCurrent()
#        self.swapBuffers()
#        print(e.pos())
#        x, y = e.pos().x(), e.pos().y()
#        
#        pen = QtGui.QPen(QtGui.QColor(255,0,0), 10)
#        
#        
#        self.painter.begin(self)     
#        
#        
#        # clean previous drawings        
#        self.painter.fillRect(self.rect(),QtGui.QBrush(QtGui.QColor(0,0,0)) )
#        self.painter.setPen(pen)
#
#        currentFont = self.painter.font()
#        currentFont.setPointSize(currentFont.pointSize()*4)
#        self.painter.setFont(currentFont)
#        #painter.fillRect(e.rect(), QtGui.QBrush(QtGui.QColor(64,32,64)))                
#        self.painter.drawLine(x, 0, x, self.height())
#        self.painter.drawLine(0, y, self.width(), y)       
#
#        self.painter.end()




    def paintGL(self): 
        print('paintGL CALL')

        glClearColor(0, 0, 0, 1)

        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glDisableClientState(GL_VERTEX_ARRAY)
        glDisableClientState(GL_COLOR_ARRAY)

        if np.array(self.objects).size:

           print('there are %i objects'%(len(self.objects)))
           #


           # active shader program
           glUseProgram(self.shaderProgram)

           for i, obj in enumerate(self.objects):

               print(i)
               loc_pos = glGetAttribLocation(self.shaderProgram, "position")
               glEnableVertexAttribArray(loc_pos)
               glBindBuffer(GL_ARRAY_BUFFER, obj.VBO[0])
               glVertexAttribPointer(loc_pos, 2, GL_FLOAT, False, 0,  ctypes.c_void_p(0))

               loc_col = glGetAttribLocation(self.shaderProgram, "color")
               glEnableVertexAttribArray(loc_col)

               glBindBuffer(GL_ARRAY_BUFFER, obj.VBO[1])
               glVertexAttribPointer(loc_col, 4, GL_FLOAT, False, 0,  ctypes.c_void_p(0))


               glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj.VBO[2])
               glDrawElements(GL_TRIANGLES, obj.indices.size, GL_UNSIGNED_INT, ctypes.c_void_p(0))


           glUseProgram(0)


           painter = QtGui.QPainter()
           painter.begin(self)
           painter.setRenderHint(QtGui.QPainter.Antialiasing)
           print(painter.isActive())


           pen = QtGui.QPen(QtGui.QColor(255,0,0), 10)

           x = 100
           y= 100

           # clean previous drawings
           painter.fillRect(self.rect(),QtGui.QBrush(QtGui.QColor(0,0,0)) )
           painter.setPen(pen)

           currentFont = painter.font()
           currentFont.setPointSize(currentFont.pointSize()*4)
           painter.setFont(currentFont)
           painter.drawLine(x, 0, x, self.height())
           painter.drawLine(0, y, self.width(), y)


           painter.end()

        else:

            print('No data in objects ==> no drawing')
            painter = QtGui.QPainter()
            painter.begin(self)
            painter.setRenderHint(QtGui.QPainter.Antialiasing)
            print(painter.isActive())


            pen = QtGui.QPen(QtGui.QColor(255,0,0), 10)

            x = 100
            y= 100

            # clean previous drawings
            painter.fillRect(self.rect(),QtGui.QBrush(QtGui.QColor(0,0,0)) )
            painter.setPen(pen)

            currentFont = painter.font()
            currentFont.setPointSize(currentFont.pointSize()*4)
            painter.setFont(currentFont)
            painter.drawLine(x, 0, x, self.height())
            painter.drawLine(0, y, self.width(), y)


            painter.end()

然后,每次按下GUI上的按钮,它都会触发此功能:

    def addAnObject(self):
     obj = geometricShape.GeometricShape()
     obj.sendToBuffer()
     self.widgetGL.objects.append(obj)
     self.widgetGL.updateGL()

GeometricShape类是:

import numpy as np
from OpenGL.GL import *
from scipy.spatial import Delaunay


class GeometricShape():
    def __init__(self):

        #self.vertices = np.random.rand(4,2)
        self.vertices = np.array([[1,1], [-1,1], [1,-1], [-1,-1]])
        tmp = np.random.rand(self.vertices.shape[0],3)
        tmp2 = np.ones(shape=(self.vertices.shape[0],1))
        tmp = np.hstack((tmp, tmp2 ))
        self.colors = tmp
        self.indices = Delaunay(self.vertices).simplices


    def sendToBuffer(self):

      # create VBO
        print('sendBuffer')
        glUseProgram(3)

        self.VBO = glGenBuffers(3)

        # fill it
        glBindBuffer(GL_ARRAY_BUFFER, self.VBO[0])
        glBufferData(GL_ARRAY_BUFFER, self.vertices.nbytes, np.ascontiguousarray(self.vertices.flatten(), dtype=np.float32), GL_STATIC_DRAW)
#
        glBindBuffer(GL_ARRAY_BUFFER, self.VBO[1])
        glBufferData(GL_ARRAY_BUFFER, self.colors.nbytes, np.ascontiguousarray( self.colors.flatten(), dtype=np.float32), GL_STATIC_DRAW)
#
# #        # INDEX ARRAY
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.VBO[2])
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, self.indices.nbytes, np.ascontiguousarray(self.indices.flatten(), dtype=np.uint32), GL_STATIC_DRAW)

        glUseProgram(0)

1 个答案:

答案 0 :(得分:1)

解决!我不得不补充道:

glBindBuffer(GL_ARRAY_BUFFER, 0)

在使用QPainter执行绘图之前解压缩paintGL()函数中的缓冲区。

我也摆脱了:

painter.fillRect(...)

不要隐藏我的GL渲染。

因此可以注意到,没有必要绘制QImage(尽管它有效)。