【OpenGL实践08】现代渲染管线在GLUT和Pygame和Qt.QOpenGLWidget上各自的实现代码

news2024/12/26 11:53:32

Qt.QOpenGLWidget进行现代渲染管线实验效果
在这里插入图片描述

一、说明

   据说QOpenGLWidget是用来取代QGLWidget的继承者,我们试图将GLUT上的旧代码改成QOpenGLWidget,本以为差别不大,轻易搞定,经实践发现要付出极大努力才能完成。经多次实验发现GLUT窗口、Pygame窗口、Qt.QOpenGLWidget上的实现方法无法兼容,甚至GL方法都不同,经好多天的百度查询,终于总结出各自的实现方法。作文以记录。

二、窗口和后台GL库的关系

   一种窗口是否能支持OpenGL,根本的一条设计是:窗口下对应的显示buffer能够指向GPU的buffer,这实际上是个底层驱动的问题。
   而检验这种关联关系是有方法:

       print("1 OK?", bool(gl.glGenBuffers))

   该方法能确定是否有窗口映射到GPUbuffer上面。这是渲染的第一个步骤,我将上述检测语句到处放置,终于找到最恰当的位置,在该处设置gl.glGenBuffers语句,用以生成VOB。

2.1 盲目使用glGenBuffers的后果

   我们经常不加检验地使用glGenBuffers函数:

global VBO
VBO = gl.glGenBuffers(1)

   会出现下列提示:

raise error.NullFunctionError( OpenGL.error.NullFunctionError: Attempt to call an undefined function glGenBuffers, check for bool(glGenBuffers) before calling

解决方法
   需要完整实现窗口,GL准备,一般需要先运行 glutInit、glutInitDisplayMode 和 glutCreateWindow。上述错误原因是OpenGL初始化尚未完成。这一点首先明白了!

2.2 在GLUT窗口初始化的检验

   在GLUT实现buffer映射时候,需要有三步铺垫,

  • glutInit、
  • glutInitDisplayMode 和
  • glutCreateWindow
       我们执行下面测试代码:
    def __init__(self):
        self.number = 0
        glutInit([])
        print("1 OK?",bool(glGenBuffers))
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)  # 显示模式 双缓存
        glutInitWindowPosition(100, 100)  # 窗口位置
        glutInitWindowSize(500, 500)  # 窗口大小
        print("2 OK?", bool(glGenBuffers))
        glutCreateWindow("sanjiao")  # 创建窗口
        print("3 OK?",bool(glGenBuffers))
        glutInitContextVersion(4, 3)  # 为了兼容
        glutInitContextProfile(GLUT_CORE_PROFILE)  # 为了兼容
        glutDisplayFunc(self.Draw)  # 回调函数
        glClearColor(0.0, 0.0, 0.0, 1.0)

        print("4 OK?",bool(glGenBuffers))
        self.CreateBuffer()
        self.Compile_Shader()
        glutIdleFunc(self.Draw)
        glutMainLoop()

   执行后提示:

1 OK? False

2 OK? False

3 OK? True

4 OK? True

   显然,我们验证了,只有

  • glutInit([])、
  • glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)
  • glutCreateWindow(“sanjiao”) # 创建窗口
       以上三个方面满足了,glGenBuffers函数的“使能”开关被触发。

2.3 在pygame窗口初始化的检验

   在pygame也需要初始化gl函数库,其代码如下:

    def _set_up_pygame(self) -> None:
        """
            Initialize and configure pygame.
        """

        pg.init()
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MAJOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_MINOR_VERSION, 3)
        pg.display.gl_set_attribute(pg.GL_CONTEXT_PROFILE_MASK, pg.GL_CONTEXT_PROFILE_CORE)
        pg.display.set_mode((640,480), pg.OPENGL|pg.DOUBLEBUF)

   同样,我们总结它的四个步骤是:

  • 初始化gl库
  • 初始化上下文
  • 设置显示模式
  • 窗口生成
       显然,与GLUT使用方法不同,而Qt5的方法更有不同。

2.4 在Qt.QOpenGLWidget窗下的初始化动作

   在Qt.QOpenGLWidget中嵌入了GL函数库,并且,不需要:

import OpenGL.GL as gl

   而是:

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

   因此,初始化GL库的代码如下:

    def initializeGL(self):
        version_profile = QOpenGLVersionProfile()
        version_profile.setVersion(2, 0)
        self.gl = self.context().versionFunctions(version_profile)
        self.gl.initializeOpenGLFunctions()

   除了上述Qt.QOpenGLWidget初始化方法外,还有一种方法,本篇着重介绍另一个方法。

三、另一种Qt.QOpenGLWidget的窗口设计

   因为这里用到着色器,因此,除了检验glGenBuffers,要检验glCreateShader,否则将再次出错。因此,下面将需要两个检验,查看函数是否可调用,分别是:
print(“create Shander”, bool(gl.glCreateShader))
print(“1 OK?”, bool(gl.glGenBuffers))

3.1 将Qt.QOpenGLWidget作为一般部件

   有两个办法用Qt.QOpenGLWidget类,其一,将其看成QmainWindow的部件,以函数指针赋值的方法指定三个虚函数。如下图所示:

在这里插入图片描述
   具体代码少有复杂,有兴趣的读者可以下载代码研究。

3.2 关键代码展现

3.2.1 基本库包含


from PyQt5 import QtCore
import OpenGL.GL as gl
import OpenGL.GLU as glu
import OpenGL.GLUT as glut
import sys
import os
import numpy as np
from PyQt5 import QtWidgets as qWidget
import math
from OpenGL.GL.shaders import compileProgram,compileShader

3.2.2 着色器编译

   这个着色器代码较为干净利索,建议以后编译着色器就照此法较为简单。

def create_shader(vertex_filepath: str, fragment_filepath: str) -> int:
    """
        Compile and link shader modules to make a shader program.

        Parameters:

            vertex_filepath: path to the text file storing the vertex
                            source code

            fragment_filepath: path to the text file storing the
                                fragment source code

        Returns:

            A handle to the created shader program
    """

    with open(vertex_filepath, 'r') as f:
        vertex_src = f.readlines()

    with open(fragment_filepath, 'r') as f:
        fragment_src = f.readlines()

    shader = compileProgram(compileShader(vertex_src, gl.GL_VERTEX_SHADER),
                            compileShader(fragment_src, gl.GL_FRAGMENT_SHADER))

    return shader

3.2.3 paintGL函数

   这里的关键函数是:gl.glUseProgram(self.Shader_Program)还有 self.loadScene(),此函数自己写的是关于相机的观察矩阵设定。其次, gl.glFlush() 不能有,加了反而黑屏,大概是QOpenGLWidget已经有了,不能重复。

def paintGL(self):
    self.loadScene()
    gl.glClear(gl.GL_COLOR_BUFFER_BIT)

    # gl.glPointSize(self.psize)
    gl.glLineWidth(self.psize)
    gl.glEnableVertexAttribArray(0)

    gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.VBO)
    # gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 12, None) #这里的None不能写为0
    gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 12, gl.ctypes.c_void_p(0))
    # gl.glDrawArrays(gl.GL_POINTS, 0, 401)
    gl.glUseProgram(self.Shader_Program)
    gl.glDrawArrays(gl.GL_LINE_STRIP, 0, 401)
    gl.glDisableVertexAttribArray(0)  #解析数据 例如一个矩阵里含有 位置 、颜色、多种信息

    # gl.glFlush()  # 此处不需要

3.2.3 initializeGL函数

此处关键是数据准备,费事费力。

def initializeGL(self):
    print("\033[4;30;102m INITIALIZE GL \033[0m")
    gl.glEnable(gl.GL_BLEND)
    gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
    gl.glEnable(gl.GL_DEPTH_TEST)
    self.prepareData()

3.2.4 resizeble的替代函数

def loadScene(self):
    gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
    gl.glMatrixMode(gl.GL_PROJECTION)
    gl.glLoadIdentity()
    x, y, width, height = gl.glGetDoublev(gl.GL_VIEWPORT)
    glu.gluPerspective(
        45,  # field of view in degrees
        width / float(height or 1),  # aspect ratio
        3,  # near clipping plane
        10,  # far clipping plane
    )

    gl.glMatrixMode(gl.GL_MODELVIEW)
    gl.glLoadIdentity()
    glu.gluLookAt(0, 0, 4, 0, 0,0, 0, 1, 0)

``

3.2.5 定时器

   为了定时刷屏,需要加定时器,在GLUT里面叫做 glutMainLoop();或者搞个死循环也可(不够酷!)

        glut.glutInit([])
        timer = QtCore.QTimer(self)
        timer.setInterval(20) # period, in milliseconds
        timer.timeout.connect(self.openGLWidget.update)
        timer.start()

   好了,这些地方均为要点。

3.3 实验效果

   见本文前部。

四、结论

   Qt.QOpenGLWidget编写渲染管线并不容易,需要处处理解正确,而且,需要对隐含的限定做种种尝试,但是一旦趟开一个路子,以后照喵画虎就成了可能。若需要完整代码,请从本文附加资源下载,非常值得收藏(我认为)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1606649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

对比实验系列:Efficientdet环境配置及训练个人数据集

一、源码下载 可以通过下方链接下载Efficientdet源码 GitHub - zylo117/Yet-Another-EfficientDet-Pytorch: The pytorch re-implement of the official efficientdet with SOTA performance in real time and pretrained weights.The pytorch re-implement of the official …

【3GPP】【核心网】【LTE】史上最全 闲时被叫CSFB 深度分析

3.2 闲时被叫CSFB 3.2.1 闲时被叫CSFB基本流程 被叫CSFB消息附近通常有一条Paging寻呼,然后进行CSFB流程: (1)UE向MME发起拓展服务请求,同时上报TMSI和承载状态,该条消息的服务类型字段中会区分主/被叫&a…

NASA数据集——2017 年 12 月圣巴巴拉山托马斯大火的烟雾和灰烬数据集

Across the Channel Investigating Diel Dynamics project 简介 圣巴巴拉海峡的 ACIDD(穿越海峡调查昼夜动态)项目最初旨在描述浮游植物种群的日变化,但随着 2017 年 12 月圣巴巴拉山托马斯大火的发生,该项目演变为一项研究&…

JS绘制电流闪烁流动效果

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>电流闪动动效</title><style>.sd1 {dis…

传统外呼吃力不讨好?AI智能外呼降低85%人力成本!

前几天有电商的客户来咨询&#xff0c;他们每逢大促客服压力就激增&#xff0c;主要原因就是客服人员少&#xff0c;遇到这种高峰期根本来不及打电话&#xff0c;招新人的话培训时间长&#xff0c;算下来人力成本相当高。因此他们想借助智能外呼看能否解决这个难题。这种时候就…

CTFshow-PWN-前置基础(pwn21-pwn22)

关于 RELRO 保护的基础知识可以参考我上一篇博客 pwn20&#xff1a; https://myon6.blog.csdn.net/article/details/137935702?spm1001.2014.3001.5502 目录 1、pwn21 2、 pwn22 1、pwn21 提交ctfshow{【.got表与.got.plt是否可写(可写为1&#xff0c;不可写为0)】,【.got的…

2024-4-15-ARM作业

实现字符串数据收发函数的封装 源代码&#xff1a; main.c #include "gpio.h"#include "uart4.h"int main(){uart4_config();while (1){// char agetchar();// putchar(a1);char s[20];gets(s);puts(s);//putchar(\n);putchar(\r);}return 0;}uart4.c …

开发一个农场小游戏需要多少钱

开发一个农场小游戏的费用因多个因素而异&#xff0c;包括但不限于游戏的规模、复杂性、功能需求、设计复杂度、开发团队的规模和经验&#xff0c;以及项目的时间周期等。因此&#xff0c;无法给出确切的费用数字。 具体来说&#xff0c;游戏的复杂程度和包含的功能特性数量会直…

Claude和chatgpt的区别

ChatGPT是OpenAI开发的人工智能的聊天机器人&#xff0c;它可以生成文章、代码并执行各种任务。是Open AI发布的第一款大语言模型&#xff0c;GPT4效果相比chatgpt大幅提升。尤其是最新版的模型&#xff0c;OpenAI几天前刚刚发布的GPT-4-Turbo-2024-04-09版本&#xff0c;大幅超…

Redis几种常见的应用方式

1.登录认证 redis最常见的应用就是&#xff0c;登录认证把。再首次登录返回给前端token&#xff0c;把用户名和登录状态缓存到redis一段时间&#xff0c;每次其他请求进来过滤器那这token解析出来的用户名或其他关键的key值&#xff0c;再redis里面查询缓存&#xff0c;有则直…

【Linux】—管理、设置防火墙规则(firewalld详解)

【Linux】—管理、设置防火墙规则&#xff08;firewalld详解&#xff09; 一、firewalld1.1 服务的启动、停止1.2 查看和设置默认区域1.3 使用firewalld进行规则配置1.4 重新加载防火墙配置1.5 查询已开放的端口、已允许的服务 &#x1f496;The Begin&#x1f496;点点关注&am…

OCR文字识别在物联网中的应用

在科技飞速发展的时代&#xff0c;OCR识别与物联网技术的结合为我们带来了前所未有的便利与革新。OCR&#xff0c;即光学字符识别技术&#xff0c;是一种将纸质文档上的文字、数字等信息转化为计算机可编辑的文本格式的技术。而物联网技术则是通过网络将各种物品连接起来&#…

eBay、亚马逊自养号测评如何避免风控账号关联选择合适网络IP环境

在自养号下单中选择适合的网络环境至关重要。经过多次实践与测试&#xff0c;积累了大量的经验&#xff0c;希望能够与大家分享&#xff0c;帮助大家避开陷阱&#xff0c;顺利前行。 市面上的网络环境种类繁多&#xff0c;从纯IP类的Luminati、Rola&#xff0c;到纯环境类的VM…

024——驱动、server、client、GUI全功能联调

目录 一、本次修改 二、GUI和Client之间联调 2.1 工程结构修改 2.2 将TCP程序修改为可被其它程序调用 2.3 优化显示界面 2.4 解决GUI通过tcp send的问题 2.5 处理服务器数据 时间不是很多了&#xff0c;我想压缩一下快点把属于毕设的这部分搞完&#xff0c;俺要出去旅游…

[算法] 动态规划

对这个算法的原有印象就是非常难理解&#xff0c;而且怎么都感觉这个算法名称有些误导&#xff1b;或者是要引申着看&#xff1f;因为里面的动态是怎么个动态&#xff1f; 这里的动态是指每一次的计算结果会影响下一次&#xff0c;或者再次的运算效率&#xff0c;也就是说下一次…

记录ubuntu20.04安装nvidia-525.85.05显卡驱动(学习笔记2024.4.15、4.16)

电脑&#xff1a;华硕天选X2024 显卡&#xff1a;4060Ti i5-14400F 架构&#xff1a;x86_64 我需要使用Linux系统使用IsaacSim进行仿真&#xff0c;所以安装的都是IsaacSim中的推荐版本。 一.对新鲜的电脑进行分盘 电脑刚到手&#xff0c;900多个G全在C盘里&#xff0c;给它…

历史遗留问题1-Oracle Mysql如何存储数据、索引

在学习到Oracle redo和undo时&#xff0c;涉及到很多存储结构的知识&#xff0c;但是网上的教程都不是很详细&#xff0c;就去复习了一下mysql&#xff0c;感觉是不是开源的问题&#xff0c;Mysql的社区和知识沉淀远高于Oracle&#xff0c; 对于初学者很友好&#xff0c;我想请…

Python文件处理--进阶

Python标准库文件操作相关模块&#xff1a; 1.使用pickle序列化 序列化指的是&#xff1a;将对象转化成“串行化”数据形式&#xff0c;存储到硬盘或通过网络传输到其他地方。反序列化是指相反的过程&#xff0c;将读取到的“串行化数据”转化成对象。我们可以使用pickle模块…

vivo怎么录屏?玩转手机新体验!(2024最新)

“最近新入手了一款vivo手机&#xff0c;感觉用起来真的很顺手&#xff0c;各种功能都很强大。昨天和朋友一起打游戏&#xff0c;突然想到要记录下精彩瞬间&#xff0c;但是找遍了手机&#xff0c;都没有找到录屏功能。我想请教一下各位vivo手机用户&#xff0c;你们通常在哪里…

亚马逊Bedrock凭借Anthropic的开创性Claude 3系列扩展了AI产品组合

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…