Skip to main content
 首页 » 编程设计

python之PyQt5 OpenGL Cubemap之黑色窗口显示

2024年08月13日36haluo1

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

我试过很多东西。有趣的是,我已经能够获得此工作的 OpenTK (C#) 和 OpenGL (C++) 版本,尽管是在 Qt 世界之外(我的老板想要在 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); 
} 

请您参考如下方法:

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

立方体贴图的纹理坐标被视为从立方体中心发出的方向向量。
由于立方体模型的中心点为(0, 0, 0),方向向量和纹理坐标等于片段的模型位置。

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

#version 430 core 
in vec3 texCoords; 
 
uniform samplerCube texture; 
 
void main(void) 
{ 
    gl_FragColor = texture(texture, texCoords.xyz); 
} 

请注意,texture2D 和 textureCube 都是兼容性配置文件函数。您必须使用函数 texture,它与核心配置文件兼容。