PyQt5 OpenGL Cubemap-黑色窗口显示

时间:2019-09-02 10:35:07

标签: python opengl pyqt5 glsl pyopengl

标题说明了一切。关于这类事情的教程并不多。有经验的人可以帮我吗?

我尝试了很多事情。有趣的是,尽管在Qt世界之外,我已经能够获得OpenTK(C#)和OpenGL(C ++)版本的工作(我的老板希望使用Python)。我知道我已经接近了,但是我看不到上一期。

我只看到一个黑色的窗口。

代码:

Python:

import sys
import numpy as np
import OpenGL.GL as gl

import array

from PyQt5 import QtGui
from PyQt5.QtCore import QSize, QPoint, Qt, pyqtSignal
from PyQt5.QtWidgets import QApplication, QWidget, QOpenGLWidget, QHBoxLayout

#from framework import *


vertexDim = 3
nVertices = 3

cubemap = np.array([-1.0,  1.0, -1.0,
                    -1.0, -1.0, -1.0,
                    1.0, -1.0, -1.0,
                    1.0, -1.0, -1.0,
                    1.0,  1.0, -1.0,
                    -1.0,  1.0, -1.0,

                    -1.0, -1.0,  1.0,
                    -1.0, -1.0, -1.0,
                    -1.0,  1.0, -1.0,
                    -1.0,  1.0, -1.0,
                    -1.0,  1.0,  1.0,
                    -1.0, -1.0,  1.0,

                    1.0, -1.0, -1.0,
                    1.0, -1.0,  1.0,
                    1.0,  1.0,  1.0,
                    1.0,  1.0,  1.0,
                    1.0,  1.0, -1.0,
                    1.0, -1.0, -1.0,

                    -1.0, -1.0,  1.0,
                    -1.0,  1.0,  1.0,
                    1.0,  1.0,  1.0,
                    1.0,  1.0,  1.0,
                    1.0, -1.0,  1.0,
                    -1.0, -1.0,  1.0,

                    -1.0,  1.0, -1.0,
                    1.0,  1.0, -1.0,
                    1.0,  1.0,  1.0,
                    1.0,  1.0,  1.0,
                    -1.0,  1.0,  1.0,
                    -1.0,  1.0, -1.0,

                    -1.0, -1.0, -1.0,
                    -1.0, -1.0,  1.0,
                    1.0, -1.0, -1.0,
                    1.0, -1.0, -1.0,
                    -1.0, -1.0,  1.0,
                    1.0, -1.0,  1.0], dtype='float32')

class App(QWidget):

    def __init__(self):
        super(App, self).__init__()

        self.glWidget = GLWidget()

        mainLayout = QHBoxLayout()
        mainLayout.addWidget(self.glWidget)
        self.setLayout(mainLayout)

        self.title = 'OpenGL Window - PyQt5'
        self.left = 20
        self.top = 30
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)

        #self.setGeometry(self.left, self.top, self.width, self.height)

class GLWidget(QOpenGLWidget):



    clicked = pyqtSignal()

    def __init__(self, parent=None):
        super(GLWidget, self).__init__(parent)

        self.profile = QtGui.QOpenGLVersionProfile()
        self.profile.setVersion( 2, 1 )

        self.xRot = 0
        self.yRot = 0
        self.zRot = 0
        # self.program = None

        self.lastPos = QPoint()

    def getOpenglInfo(self):
        info = """
            Vendor: {0}
            Renderer: {1}
            OpenGL Version: {2}
            Shader Version: {3}
        """.format(
            gl.glGetString(gl.GL_VENDOR),
            gl.glGetString(gl.GL_RENDERER),
            gl.glGetString(gl.GL_VERSION),
            gl.glGetString(gl.GL_SHADING_LANGUAGE_VERSION)
        )

        return info


    def rotateBy(self, xAngle, yAngle, zAngle):
        print(str(xAngle) + ", " + str(yAngle) + ", " + str(zAngle))
        self.xRot += xAngle
        self.yRot += yAngle
        self.zRot += zAngle
        self.update()


    def minimumSizeHint(self):
        return QSize(600, 400)

    def initializeGL(self):
        print(self.getOpenglInfo())

        self.gl = self.context().versionFunctions( self.profile )

        # Vertex Array Object
        self.vao = QtGui.QOpenGLVertexArrayObject( self )
        self.vao.create()

        # Set up and link shaders
        self.program = QtGui.QOpenGLShaderProgram( self )
        self.program.addShaderFromSourceFile( QtGui.QOpenGLShader.Vertex, 'shader.vert' )
        self.program.addShaderFromSourceFile( QtGui.QOpenGLShader.Fragment, 'shader.frag' )
        self.program.link()

        self.vao.bind()


        self.vertices = np.array([ 0.0, 0.0, 0.0, # x, y, z
                                   1.0, 0.0, 0.0, 
                                   0.5, 1.0, 0.0 ], dtype='float32')
        self.vbo_vertices = self.setVertexBuffer( cubemap, 3, self.program, "position" )

        self.colors = np.array([ 1.0, 0.0, 0.0, 1.0, # r, g, b, a
                                 0.0, 1.0, 0.0, 1.0, 
                                 0.0, 0.0, 1.0, 1.0 ], dtype='float32')
        self.vbo_colors = self.setVertexBuffer( self.colors, 4, self.program, "texture" )
        self.vao.release()

        self.program.bind()


        self.program.release()


    def resizeGL(self, width, height):
        gl.glViewport(0, 0, width, height)

    def setVertexBuffer( self, data_array, dim_vertex, program, shader_str ):
        vbo = QtGui.QOpenGLBuffer( QtGui.QOpenGLBuffer.VertexBuffer )
        vbo.create()
        vbo.bind()

        vertices = np.array( data_array, np.float32 )
        vbo.allocate( vertices, vertices.shape[0] * vertices.itemsize )

        attr_loc = program.attributeLocation( shader_str )
        program.enableAttributeArray( attr_loc )
        program.setAttributeBuffer( attr_loc, gl.GL_FLOAT, 0, dim_vertex )
        vbo.release()

        return vbo


    def paintGL(self):
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
        gl.glClearColor(0.0, 0.0, 0.2, 0.0)


        self.program.bind()

        self.texture = QtGui.QOpenGLTexture(QtGui.QOpenGLTexture.TargetCubeMap)
        self.texture.create()
        print(self.texture.isCreated())

        img = QtGui.QImage("C:\\Users\\path\\to\\image.jpg")

        self.texture.bind()
        self.texture.setSize(1024, 1024)
        self.texture.setFormat(QtGui.QOpenGLTexture.RGBAFormat)

        self.texture.allocateStorage()


        self.texture.setData(0, 0, QtGui.QOpenGLTexture.CubeMapNegativeX, QtGui.QOpenGLTexture.RGBA, QtGui.QOpenGLTexture.UInt16, img.bits())
        self.texture.setData(0, 0, QtGui.QOpenGLTexture.CubeMapNegativeY, QtGui.QOpenGLTexture.RGBA, QtGui.QOpenGLTexture.UInt16, img.bits())
        self.texture.setData(0, 0, QtGui.QOpenGLTexture.CubeMapNegativeZ, QtGui.QOpenGLTexture.RGBA, QtGui.QOpenGLTexture.UInt16, img.bits())
        self.texture.setData(0, 0, QtGui.QOpenGLTexture.CubeMapPositiveX, QtGui.QOpenGLTexture.RGBA, QtGui.QOpenGLTexture.UInt16, img.bits())
        self.texture.setData(0, 0, QtGui.QOpenGLTexture.CubeMapPositiveY, QtGui.QOpenGLTexture.RGBA, QtGui.QOpenGLTexture.UInt16, img.bits())
        self.texture.setData(0, 0, QtGui.QOpenGLTexture.CubeMapPositiveZ, QtGui.QOpenGLTexture.RGBA, QtGui.QOpenGLTexture.UInt16, img.bits())


        self.texture.setMinMagFilters(QtGui.QOpenGLTexture.Linear, QtGui.QOpenGLTexture.Linear)
        self.texture.setWrapMode(QtGui.QOpenGLTexture.ClampToEdge)



        # initialise Camera matrix with initial rotation
        m = QtGui.QMatrix4x4()
        m.ortho(-0.5, 0.5, 0.5, -0.5, 4.0, 15.0)
        m.translate(0.0, 0.0, -10.0)
        m.rotate(self.xRot / 16.0, 1.0, 0.0, 0.0)
        m.rotate(self.yRot / 16.0, 0.0, 1.0, 0.0)
        m.rotate(self.zRot / 16.0, 0.0, 0.0, 1.0)

        self.program.setUniformValue('mvp', m)
        self.program.setUniformValue('texture', 0)

        self.vao.bind()
        gl.glDrawArrays( gl.GL_TRIANGLES, 0, 36 )
        self.vao.release()      


        self.program.release()

    def mousePressEvent(self, event):
        self.lastPos = event.pos()


    def mouseMoveEvent(self, event):
        dx = event.x() - self.lastPos.x()
        dy = event.y() - self.lastPos.y()

        if event.buttons() & Qt.LeftButton:
            self.rotateBy(8 * dy, 8 * dx, 0)
        elif event.buttons() & Qt.RightButton:
            self.rotateBy(8 * dy, 0, 8 * dx)

        self.lastPos = event.pos()
        self.paintGL()

    def mouseReleaseEvent(self, event):
        self.clicked.emit()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = App()
    ex.show()
    sys.exit(app.exec_())

着色器:

shader.vert

#version 430 core

in vec3 position;

out vec3 texCoords;
uniform mat4 mvp;


void main(void)
{
    texCoords = position;
    gl_Position = mvp * vec4(position, 1.0);    
}

shader.frag

#version 430 core
in vec3 texCoords;

uniform sampler2D texture;

void main(void)
{
    gl_FragColor = texture2D(texture, texCoords.xy);
}

1 个答案:

答案 0 :(得分:3)

由于self.texture是一个立方体贴图(QtGui.QOpenGLTexture.TargetCubeMap),因此相应的纹理采样器统一类型必须为samplerCube,而不是sampler2D

将立方体贴图的纹理坐标视为从立方体中心发出的方向向量。
由于立方体模型的中心是(0,0,0),因此方向矢量或纹理坐标等于片段的模型位置。

更改片段着色器以解决该问题:

#version 430 core
in vec3 texCoords;

uniform samplerCube texture;

void main(void)
{
    gl_FragColor = texture(texture, texCoords.xyz);
}

注意,texture2DtextureCube分别是兼容性配置文件功能。您必须使用功能texture,该功能与核心配置文件的兼容性一样。