使用 PyOpenGL 进行 2D 图形渲染总结

一、说明

OpenGL是一个广泛使用的开放式跨平台实时 3D 图形库,开发于二十多年前。它提供了一个低级API,允许开发人员以统一的方式访问图形硬件。在开发需要硬件加速且需要在不同平台上运行的复杂 2D 或 3D 应用程序时,它是首选平台。它可以在多种语言中使用,包括 C/C++、C#、Java、Objective-C(用于 iPhone 和 iPad 游戏)、Python 等。在本文中,我将展示如何将 OpenGL 与 Python 一起使用(感谢PyOpenGL 库)来高效渲染 2D 图形。

二、安装简介

需要带有 Numpy、 PyOpenGL和 PyQt4库的 Python。在 Windows 上,可以在此网页上找到二进制安装程序 。

此外,还需要系统显卡的最新驱动程序,以便可以使用最新的OpenGL实现。特别是,我们将利用 顶点缓冲对象 (VBO),从 OpenGL 版本 1.5(2003 年出现)开始,这些对象在核心实现中可用。在此日期之后发货的显卡应具有支持 VBO 的驱动程序。但是,系统上安装的驱动程序可能不支持最新版本的 OpenGL。

例如,在 Windows 上,我对 2009 年显卡的默认驱动程序存在一些问题:OpenGL 1.1 是唯一受支持的版本。 原因是当构造函数驱动程序未找到或不可用时,Windows(从 Vista 开始)可以使用一种基于 Windows 显示驱动程序模型 (WDDM)的通用驱动程序。现在,WDDM 驱动程序倾向于使用 DirectX(微软自己的图形库,与 OpenGL 并行)而不是 OpenGL,因此这些驱动程序仅支持非常旧的 OpenGL 版本。为了使事情正常进行,需要找到构造函数驱动程序并强制安装它们。可能会有点痛。

简而言之,如果在运行下面的脚本时出现提及 OpenGL 和缓冲区对象的错误消息,请确保显卡驱动程序正确。OpenGL Extensions Viewer是检查显卡 OpenGL 功能的一个非常有用的工具 。它适用于 Windows、Linux 和 iOS。

三、QGL控件

我们将定义一个 Qt 小部件,在窗口中的随机位置显示点。该小部件将派生自 QGLWidgetQt 小部件,它提供对 OpenGL API 进行渲染的访问。派生类中至少需要重写三个方法:initializeGL()、updateGL()和resizeGL(w, h)。

initializeGL():在这里调用 OpenGL 初始化命令。它也是创建顶点缓冲区对象并用一些数据填充它们的地方。

paintGL():在此处调用 OpenGL 渲染命令。每当需要重绘窗口时就会调用它。

resizeGL(w, h):在这里进行与相机和视口相关的调用。每当小部件的大小发生更改时都会调用它(新的小部件大小作为参数传递给此方法)。

顶点缓冲区对象
渲染数据最有效的方法是尽量减少从系统内存到 GPU 内存的数据传输,并尽量减少对 OpenGL 渲染命令的调用次数。执行此操作的一种便捷方法是使用 顶点缓冲区对象。它们允许在 GPU 上分配内存,在 GPU 上加载一次数据(如果数据发生变化则加载多次),并高效地渲染它,因为数据在连续调用之间保留在 GPU 上 paintGL()。PyOpenGL 集成了一个模块来轻松创建和使用 VBO:

import OpenGL.arrays.vbo as glvbo
# in initializeGL:
# create a VBO, data is a Nx2 Numpy array
self.vbo = glvbo.VBO(self.data)# in paintGL:
# bind a VBO, i.e. tell OpenGL we're going to use it for subsequent
# rendering commands
self.vbo.bind()

四、使用 VBO 绘画

OpenGL 可以渲染点、线和凸多边形等图元。 glEnableClientState 和 glVertexPointer 函数配置 VBO 进行渲染,glDrawArrays 函数从存储在 GPU 内存中的缓冲区中绘制图元。可以与 VBO 一起使用的其他绘图命令包括 glMultiDrawArrays,用于从单个 VBO 绘制多个独立图元(与使用多个 VBO 相比,效率更高,但灵活性较差)。索引绘图也是可能的,并允许以任意顺序使用顶点,并在渲染期间多次重用顶点。相关函数是glDrawElements和glMultiDrawElements。

颜色可以在调用渲染命令之前使用函数 glColor 指定,也可以通过为颜色创建一个特殊的 VBO(包含每个点的颜色)来指定。相关函数是glColorPointer和glEnableClientState(GL_COLOR_ARRAY)。一种变体是将颜色与顶点打包在一起,即在单个 VBO 中每个点有 5 个数字(x、y 坐标和 R、V、B 颜色分量)。请参阅此处的一些详细信息。

注意:显然,在OpenGL中,使用单精度浮点数比使用双精度浮点数更好。显卡可能确实不支持后一种格式。我在这篇文章的早期版本中使用了双精度,在特定情况下我遇到了一些令人讨厌的内存访问冲突崩溃。当我换成花车时它们就消失了。如果这对任何人有帮助…、

# in paintGL:
# set the color yellow
gl.glColor(1,1,0)
# enable the VBO
gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
# tell OpenGL that each vertex is made of 2 single precision floating
# numbers (x and y coordinates).
gl.glVertexPointer(2, gl.GL_FLOAT, 0, self.vbo)
# draw all points from the VBO
gl.glDrawArrays(gl.GL_POINTS, 0, len(self.data))

五、设置 2D 渲染的正交投影

该resizeGL方法设置用于 光栅化的几何投影。由于我们在本文中只对 2D 渲染感兴趣,因此我们 在该 函数中使用正交投影glOrtho。该 glViewport 函数允许指定用于后续渲染命令的屏幕部分。这里我们只是告诉 OpenGL 在整个窗口内进行绘制。

# paint within the whole window
gl.glViewport(0, 0, self.width, self.height)
# set orthographic projection (2D only)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
# the window corner OpenGL coordinates are (-+1, -+1)
gl.glOrtho(-1, 1, 1, -1, -1, 1)

六、设置 PyQt 小部件

这里我们使用 PyQt 作为 GUI 窗口系统。为了在屏幕上显示一个窗口并使用我们的 OpenGL 小部件,我们首先需要定义一个 Qt 主窗口,将 OpenGL 小部件放入其中,最后创建一个 Qt 应用程序来托管主窗口。

# paint within the whole window
gl.glViewport(0, 0, self.width, self.height)
# set orthographic projection (2D only)
gl.glMatrixMode(gl.GL_PROJECTION)
gl.glLoadIdentity()
# the window corner OpenGL coordinates are (-+1, -+1)
gl.glOrtho(-1, 1, 1, -1, -1, 1)

定义一个 Qt 窗口,其中包含 OpenGL 小部件

# define a Qt window with an OpenGL widget inside it
class TestWindow(QtGui.QMainWindow):def __init__(self):super(TestWindow, self).__init__()# initialize the GL widgetself.widget = GLPlotWidget()# [...] (set data for the OpenGL widget)# put the window at the screen position (100, 100)self.setGeometry(100, 100, self.widget.width, self.widget.height)self.setCentralWidget(self.widget)self.show()# create the Qt App and window
app = QtGui.QApplication(sys.argv)
window = TestWindow()
window.show()
app.exec_()

七、完整剧本

这是完整的脚本。

# PyQt4 imports
from PyQt4 import QtGui, QtCore, QtOpenGL
from PyQt4.QtOpenGL import QGLWidget
# PyOpenGL imports
import OpenGL.GL as gl
import OpenGL.arrays.vbo as glvboclass GLPlotWidget(QGLWidget):# default window sizewidth, height = 600, 600def set_data(self, data):"""Load 2D data as a Nx2 Numpy array."""self.data = dataself.count = data.shape[0]def initializeGL(self):"""Initialize OpenGL, VBOs, upload data on the GPU, etc."""# background colorgl.glClearColor(0,0,0,0)# create a Vertex Buffer Object with the specified dataself.vbo = glvbo.VBO(self.data)def paintGL(self):"""Paint the scene."""# clear the buffergl.glClear(gl.GL_COLOR_BUFFER_BIT)# set yellow color for subsequent drawing rendering callsgl.glColor(1,1,0)# bind the VBOself.vbo.bind()# tell OpenGL that the VBO contains an array of verticesgl.glEnableClientState(gl.GL_VERTEX_ARRAY)# these vertices contain 2 single precision coordinatesgl.glVertexPointer(2, gl.GL_FLOAT, 0, self.vbo)# draw "count" points from the VBOgl.glDrawArrays(gl.GL_POINTS, 0, self.count)def resizeGL(self, width, height):"""Called upon window resizing: reinitialize the viewport."""# update the window sizeself.width, self.height = width, height# paint within the whole windowgl.glViewport(0, 0, width, height)# set orthographic projection (2D only)gl.glMatrixMode(gl.GL_PROJECTION)gl.glLoadIdentity()# the window corner OpenGL coordinates are (-+1, -+1)gl.glOrtho(-1, 1, 1, -1, -1, 1)if __name__ == '__main__':# import numpy for generating random data pointsimport sysimport numpy as npimport numpy.random as rdn# define a Qt window with an OpenGL widget inside itclass TestWindow(QtGui.QMainWindow):def __init__(self):super(TestWindow, self).__init__()# generate random data pointsself.data = np.array(.2*rdn.randn(100000,2),dtype=np.float32)# initialize the GL widgetself.widget = GLPlotWidget()self.widget.set_data(self.data)# put the window at the screen position (100, 100)self.setGeometry(100, 100, self.widget.width, self.widget.height)self.setCentralWidget(self.widget)self.show()# create the Qt App and windowapp = QtGui.QApplication(sys.argv)window = TestWindow()window.show()app.exec_()

在这里插入图片描述

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

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

相关文章

liunx centos7 下通过yum删除安装已经安装的php

执行下面命令查看php相关的包 rpm -qa | grep php 只需要卸载几个名为common的包即可,其他同版本依赖会被全部删除,删除php71w-common,71w版本的依赖包全部会被删除。 查看php包的命令 rpm -qa | grep php 或 yum list installed | gre…

unity编辑器扩展高级用法

在PropertyDrawer中,您不能使用来自GUILayout或EditorGUILayout的自动布局API,而只能使用来自GUI和EditorGUI的绝对Rect API始终传递相应的起始位置和维度。 你需要 计算显示嵌套内容所需的总高度将此高度添加到public override float GetPropertyHeig…

实用工具推荐:适用于 TypeScript 网络爬取的常用爬虫框架与库

随着互联网的迅猛发展,网络爬虫在信息收集、数据分析等领域扮演着重要角色。而在当前的技术环境下,使用TypeScript编写网络爬虫程序成为越来越流行的选择。TypeScript作为JavaScript的超集,通过类型检查和面向对象的特性,提高了代…

Linux :环境基础开发工具

目录: 1. Linux 软件包管理器 yum 1. 什么是软件包 2. 查看软件包 3. 如何安装软件 4. 如何卸载软件 2. Linux开发工具 1. Linux编辑器-vim的基本概念 2. vim使用 3. vim的基本操作 4. vim正常模式命令集 5. vim末行模式命令集 6. 简单vim配置 3. Linux编译器-gcc/…

常用相似度计算方法总总结

一、欧几里得相似度 1、欧几里得相似度 公式如下所示: 2、自定义代码实现 import numpy as np def EuclideanDistance(x, y):import numpy as npx np.array(x)y np.array(y)return np.sqrt(np.sum(np.square(x-y)))# 示例数据 # 用户1 的A B C D E商品数据 [3.3…

知识管理软件那么多,怎么挑选才适合初创企业?

对于初创企业来说,资源有限,效率显得尤其重要。此时,一个强大的知识管理软件就显得必不可少。它不仅利于信息的录入、查找和共享,还可以帮助团队更好的组织和协作,提高工作效率。那么,在众多的知识管理软件…

SQL-Labs靶场“34-35”关通关教程

君衍. 一、34关 POST单引号宽字节注入1、源码分析2、联合查询注入3、updatexml报错注入4、floor报错注入 二、35关 GET数字型报错注入1、源码分析2、联合查询注入3、updatexml报错注入4、floor报错注入 SQL-Labs靶场通关教程: SQL注入第一课 SQL注入思路基础 SQL无列…

第 6 章 ROS-xacro练习(自学二刷笔记)

重要参考: 课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ 讲义链接:Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 6.4.3 Xacro_完整使用流程示例 需求描述: 使用 Xacro 优化 URDF 版的小车底盘模型实现 结果演示: 1.编写 X…

使用Dockerfile打包java项目生成镜像部署到Linux

1、Dockerfile 介绍 如果说容器就是“小板房”,镜像就是“样板间”。那么,要造出这个“样板间”,就必然要有一个“施工图纸”,由它来规定如何建造地基、铺设水电、开窗搭门等动作。这个“施工图纸”就是“Dockerfile”。 比起容…

VUE3.0(一):vue3.0简介

Vue 3 入门指南 什么是vue Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界…

0基础 三个月掌握C语言(13)-下

数据在内存中的存储 浮点数在内存中的存储 常见的浮点数:3.141592、1E10等 浮点数家族包括:float、double、long double类型 浮点数表示的范围:在float.h中定义 练习 关于(float*)&n: &n:这是一…

53、Qt/信号与槽、QSS界面设计20240322

一、使用手动连接,将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中,在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中,在槽函数中判断ui界面上输入的账号是否为"admin",密码是…

yolov6实现遥感影像目标识别|以DIOR数据集为例

1 目标检测是计算机视觉领域中的一项重要任务,它的目标是在图像或视频中检测出物体的位置和类别。YOLO(You Only Look Once)是一系列经典的目标检测算法,最初由Joseph Redmon等人于2016年提出。YOLO算法具有快速、简单、端到端的特…

证书(公钥):网络安全的关键

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

YOLOv5全网首发改进: 注意力机制改进 | 上下文锚点注意力(CAA) | CVPR2024 PKINet 遥感图像目标检测

💡💡💡本文独家改进:引入了CAA模块来捕捉长距离的上下文信息,利用全局平均池化和1D条形卷积来增强中心区域的特征,从而提升检测精度,CAA和C3进行结合实现二次创新,改进思路来自CVPR2024 PKINet,2024年前沿最新改进,抢先使用 💡💡💡小目标数据集,涨点近两个…

【亚马逊云AI课程上新】「生成式 AI 精英速成计划」 即刻成为炙手可热 AI 人才

文章目录 1. 生成式 AI 精英速成计划介绍2. 重磅课程 增亮你的职业生涯3. 多种身份 全面赋能4. 关于「商业应用技能」课程5. 关于「技术开发技能」课程介绍6. 化身学霸得好礼 好礼双周送附:亚马逊云科技海外账号注册流程 1. 生成式 AI 精英速成计划介绍 &#x1f4…

公司调研 | Agility | 网红人形机器人Digit | 商业化情况

最近做的一些公司 / 产品调研没有从技术角度出发,而更关注宏观发展:主营方向、产品介绍、商业化落地情况、融资历程、公司愿景、创始人背景等。部分调研放在知乎上,大部分在飞书私人链接上 最近较关注人形Robot的发展情况,欢迎感兴…

在云上部署我的个人博客!!!

这和上一篇是连起来的,大家先整体看一遍,不要跟,前面有些弯路!!! 【这是按时计费的,欠费不能用,交了好几次哈哈哈哈 】 【我买的域名是:128.1.61.228】 【把域名这个位置…

鸿蒙Harmony应用开发—ArkTS(@Link装饰器:父子双向同步)

子组件中被Link装饰的变量与其父组件中对应的数据源建立双向数据绑定。 说明: 从API version 9开始,该装饰器支持在ArkTS卡片中使用。 概述 Link装饰的变量与其父组件中的数据源共享相同的值。 限制条件 Link装饰器不能在Entry装饰的自定义组件中使用…

优化选址问题 | 模拟退火算法求解物流选址问题含Matlab源码

目录 问题代码问题 模拟退火算法(Simulated Annealing, SA)是一种概率性的全局优化算法,用于求解大规模组合优化问题。在物流选址问题中,模拟退火算法可以用来寻找成本最低、效率最高的仓库或配送中心位置。下面是一个简化的模拟退火算法求解物流选址问题的描述,并附带有…