使用 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.hqwc.cn/news/562655.html

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

相关文章

文件上传二—WEB攻防-PHP应用文件上传中间件CVE解析第三方编辑器已知CMS漏洞

演示案例: PHP-中间件-上传相关-Apache&NginxPHP-编辑器-上传相关-第三方处理引用PHP-CMS源码-上传相关-已知识别到利用 #PHP-中间件-上传相关-Apache&Nginx 复现漏洞环境:vulhub (部署搭建看打包视频) 由于PHP搭建常用中…

CentOS系统部署YesPlayMusic播放器并实现公网访问本地音乐资源

文章目录 1. 安装Docker2. 本地安装部署YesPlayMusic3. 安装cpolar内网穿透4. 固定YesPlayMusic公网地址 本篇文章讲解如何使用Docker搭建YesPlayMusic网易云音乐播放器,并且结合cpolar内网穿透实现公网访问音乐播放器。 YesPlayMusic是一款优秀的个人音乐播放器&am…

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i 运行测试

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i 运行测试 1 Prerequisites1.1 C11 or C0x Compiler1.2 Pangolin1.3 OpenCV1.4 Eigen3 2 安装 Intel RealSense™ SDK 2.02.1 测试设备2.2 编译源码安装 (Recommend)2.3 预编译包安装 3 编译 ORB-SLAM34 使用 D435i …

深入理解Redis的Sentinel机制

Sentinel简述 Sentinel为了解决什么问题? Sentinel(哨岗、哨兵)是Redis的高可用性(high availability)解决方案。 我们知道Redis 的主从复制模式可以将主节点的数据改变同步给从节点,这样从节点就可以起…

K8S之DaemonSet控制器

DaemonSet控制器 概念、原理解读、应用场景概述工作原理典型的应用场景介绍DaemonSet 与 Deployment 的区别 解读资源清单文件实践案例 概念、原理解读、应用场景 概述 DaemonSet控制器能够确保K8S集群所有的节点都分别运行一个相同的pod副本; 当集群中增加node节…

SpringSecurity6.x

文章目录 一.什么是SpringSecurity二.SpringSecurity的特征三.SpringSecurity的第一个例子3.1 创建SpringBoot项目3.2 创建IndexController3.3 创建index.html3.4 启动项目3.5 Spring Security默认做了什么 四.SpringSecurity的整体架构4.1 Filter4.2 DelegatingFilterProxy4.3…

Java 基础学习(二十)Maven、XML与WebServer

1 Maven 1.1 什么是Maven 1.1.1 Maven概述 Maven是一种流行的构建工具,用于管理Java项目的构建,依赖管理和项目信息管理。它使用XML文件来定义项目结构和构建步骤,并使用插件来执行各种构建任务。Maven可以自动下载项目依赖项并管理它们的…

iOS模拟器 Unable to boot the Simulator —— Ficow笔记

本文首发于 Ficow Shen’s Blog,原文地址: iOS模拟器 Unable to boot the Simulator —— Ficow笔记。 内容概览 前言终结模拟器进程命令行改权限清除模拟器缓存总结 前言 iOS模拟器和Xcode一样不靠谱,问题也不少。😂 那就有病治…

探索超融合服务器:是否助力企业飞跃数字化挑战?

在数字化不断深化的今天,企业面临着前所未有的转型压力和机遇。IT基础设施作为支撑企业运营的重要基石,其性能、效率及可管理性都直接关系到企业的竞争力。超融合服务器作为一种创新的IT架构,被许多业内专家视为应对现代业务挑战的有效手段。…

【LabVIEW FPGA入门】FPGA不同传递数据方法比较

数据共享方法的选择应基于应用的需要。根据应用程序的重要特性,所讨论的任何一种方法都可能是合适的。 传输方法FPGA资源损耗?不同时钟源之间传递数据?新数据通知?常见用途变量逻辑片是是否提取最新数据存储器存储器是否否提取最新…

思腾合力受邀出席文化和旅游虚拟现实应用推广交流活动并作主题演讲

3月21日,由文化和旅游部产业发展司主办,中国信息通信研究院、北京市石景山区文化和旅游局、中国动漫集团有限公司承办的“数字赋能文旅场景建设行动——文化和旅游虚拟现实应用推广交流活动”在北京首钢一高炉SoReal科幻乐园成功举办。 思腾合力CMO徐莉受…

Kubernetes kafka系列 | Strimzi 快速部署kafka集群 (可外部通信)

一、Strimzi介绍 Strimzi 是一个用于 Apache Kafka 在 Kubernetes 上部署和管理的开源项目。它提供了一组 Kubernetes 自定义资源定义(Custom Resource Definitions,CRDs)、控制器和操作符,使得在 Kubernetes 环境中轻松地部署、管理和操作 Kafka 集群成为可能。Strimzi 项…