【问题标题】:Draw multiple objects using VBOs with PyQt5 and OpenGL?使用带有 PyQt5 和 OpenGL 的 VBO 绘制多个对象?
【发布时间】:2020-12-26 05:54:33
【问题描述】:

我正在尝试使用 pyqt5 在 pyopengl 中渲染多个对象。在遵循教程之后,我创建了一个 3D 网格,它上传了一个波前 obj 文件并用纹理渲染它。这对我有用:

class Model:
    def __init__(self, file_name, texture_name):
        self.object = ObjectLoader()
        self.object.load_model(file_name)

        //creating and compiling shaders

        glUseProgram(shader)

        vertex_buffer_object = GLuint(0)
        glGenBuffers(1, vertex_buffer_object)
        glBindBuffer(GL_ARRAY_BUFFER,  vertex_buffer_object)
        glBufferData(GL_ARRAY_BUFFER, len(self.object.model) * 4, self.object.c_model, GL_DYNAMIC_DRAW) 
        glDrawArrays(GL_TRIANGLES, 0, len(self.object.vertex_index))
        # vertices
        vertex_offset = 0
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 3, ctypes.c_void_p(vertex_offset))
        glEnableVertexAttribArray(0)

        # textures
        texture_offset = len(self.object.vertex_index) * 12
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 2, ctypes.c_void_p(texture_offset))
        glEnableVertexAttribArray(1)

        # normals
        normal_offset = texture_offset + len(self.object.texture_index) * 8
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 3, ctypes.c_void_p(normal_offset))
        glEnableVertexAttribArray(2)

        texture = GLuint(0)
        glGenTextures(1, texture)
        glBindTexture(GL_TEXTURE_2D, texture)
        # texture wrapping
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        # texture filtering
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)

        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        image = Image.open(texture_name)
        flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
        image_data = image.convert("RGB").tobytes()
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data)
      // setting the view, projection etc matrix     

由于我使用的是 PyQt5,所以如果我加载对象,我就有这个类:

class Obj(QOpenGLWidget):
    def __init__(self, parent):
        QOpenGLWidget.__init__(self, parent)
           
    def initializeGL(self):
        glClearColor(82/255, 95/255, 107/255, 1.0)
        glEnable(GL_DEPTH_TEST)         
        
        self.model = Model("....obj", "texture.png")     
            
        
    def paintGL(self):
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glDrawArrays(GL_TRIANGLES, 0, len(self.model.object.vertex_index))
        
   
        self.update()
        
        
    def resizeGL(self, width, height):
        glViewport(0, 0, width, height)

我正在努力在Obj 类中创建另一个Model。我尝试在initializeGL 中创建它并在paintGL 中使用另一个glDrawArrays 调用进行渲染,但没有发生任何事情,或者没有任何预期......知道我做错了什么吗?

【问题讨论】:

    标签: python opengl pyqt5 vao


    【解决方案1】:

    您必须使用Vertex Array Object。顶点数组对象存储提供顶点数据所需的所有状态。

    模型的构造函数只创建所有需要的 OpenGL 对象。着色器程序不是模型的一部分。对所有型号使用相同的程序:

    class Model:
        def __init__(self, file_name, texture_name):
            self.object = ObjectLoader()
            self.object.load_model(file_name)
    
            # create vertex array object
            self.vao = glGenVertexArrays(1)
            glBindVertexArray(self.vao)
    
            vertex_buffer_object = GLuint(0)
            glGenBuffers(1, vertex_buffer_object)
            glBindBuffer(GL_ARRAY_BUFFER,  vertex_buffer_object)
            glBufferData(GL_ARRAY_BUFFER, len(self.object.model) * 4, self.object.c_model, GL_DYNAMIC_DRAW) 
            glDrawArrays(GL_TRIANGLES, 0, len(self.object.vertex_index))
    
            # vertices
            vertex_offset = 0
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 3, ctypes.c_void_p(vertex_offset))
            glEnableVertexAttribArray(0)
    
            # textures
            texture_offset = len(self.object.vertex_index) * 12
            glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 2, ctypes.c_void_p(texture_offset))
            glEnableVertexAttribArray(1)
    
            # normals
            normal_offset = texture_offset + len(self.object.texture_index) * 8
            glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, self.object.model.itemsize * 3, ctypes.c_void_p(normal_offset))
            glEnableVertexAttribArray(2)
    
            # create texture
            self.texture = GLuint(0)
            glGenTextures(1, self.texture)
            glBindTexture(GL_TEXTURE_2D, self.texture)
            # texture wrapping
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
            # texture filtering
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    
            image = Image.open(texture_name)
            flipped_image = image.transpose(Image.FLIP_TOP_BOTTOM)
            image_data = image.convert("RGB").tobytes()
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width, image.height, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data)
    

    向绑定OpenGL对象(VAO和纹理)并绘制网格的类添加一个方法:

    class Model:
        # [...]
    
        def draw(self):
    
            // bind texture
            glBindTexture(GL_TEXTURE_2D, self.texture)
    
            // create vertex array object
            glBindVertexArray(self.vao)
    
            // draw object
            glDrawArrays(GL_TRIANGLES, 0, len(self.object.vertex_index))
    

    通过此设置,您可以绘制多个模型:

    class Obj(QOpenGLWidget):
        def __init__(self, parent):
            QOpenGLWidget.__init__(self, parent)
    
        def initializeGL(self):
            glClearColor(82/255, 95/255, 107/255, 1.0)
            glEnable(GL_DEPTH_TEST)
            glEnable(GL_BLEND)
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    
            self.model1 = Model("....obj", "texture.png") 
            self.model2 = Model("....obj", "texture2.png")  
            # [...] 
    
        def paintGL(self):
            
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
            
            # install program
            glUseProgram(self.shader)
    
            # setting the view, projection etc matrix
            # [...]
            
            self.model1.draw()
            self.model2.draw()
            # [...] 
            
            self.update()
            
        def resizeGL(self, width, height):
            glViewport(0, 0, width, height)
    

    模型也可以组织成一个列表:

    class Obj(QOpenGLWidget):
       # [...]
    
        def initializeGL(self):
            # [...]
    
            self.models = [
                Model("....obj", "texture.png"),
                Model("....obj", "texture2.png")  
                # [...]
            ] 
    
        def paintGL(self):
            # [...]
    
            for model in self.models:
                model.draw()
    
            # [...] 
    

    【讨论】:

    • 所以我应该只在 QOpenGLWidget 而不是模型中编译和加载着色器?
    • @user1234352 你有多少着色器?每个模型都有单独的着色器程序吗? - 我不建议这样做)。如果您只有一个着色器程序,那么没有充分的理由为每个模型创建一个着色器。
    猜你喜欢
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-30
    • 1970-01-01
    • 2020-07-21
    • 2011-06-22
    • 1970-01-01
    相关资源
    最近更新 更多