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

news/2024/5/1 0:25:25

一、说明

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.cpky.cn/p/11472.html

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

相关文章

WEB安全测试通常要考虑的测试点

1、问题:没有被验证的输入 测试方法: 数据类型(字符串,整型,实数,等) 允许的字符集 最小和最大的长度 是否允许空输入 参数是否是必须的 重复是否允许 数值范围 特定的值(枚举型&a…

WIFI驱动移植实验:WIFI从路由器动态获取IP地址与联网

一. 简介 前面两篇文章,一篇文章实现了WIFI联网前要做的工作,另一篇文章配置了WIFI配置文件,进行了WIFI热点的连接。文章如下: WIFI驱动移植实验:WIFI 联网前的工作-CSDN博客 WIFI驱动移植实验:连接WIF…

路径规划——搜索算法详解(五):Dynamic A Star(D*)算法详解与Matlab代码

昨天休息了一天,今天继续学习搜索算法!前几天已经分别介绍了Dijkstra算法、Floyd算法、RRT算法、A*算法,无独有偶,上述算法都只适用于静态环境下两点规划的场景,但是大部分场景是实时变化的,这对规划算法提…

【中文视觉语言模型+本地部署 】23.08 阿里Qwen-VL:能对图片理解、定位物体、读取文字的视觉语言模型 (推理最低12G显存+)

项目主页:https://github.com/QwenLM/Qwen-VL 通义前问网页在线使用——(文本问答,图片理解,文档解析):https://tongyi.aliyun.com/qianwen/ 论文v3. : 一个全能的视觉语言模型 23.10 Qwen-VL: A Versatile…

Could not initialize class java.awt.Font

项目场景: 项目场景:java项目在web端导出Excel、Word、PDF等文档 问题描述 在Windows系统中开发以及运行文件导出正常,单机部署到Linux中或者使用docker部署后,导出报错。 异常: eleasing transactional SqlSession…

Linux系统下安装jdk与tomcat【linux】

一、yum介绍 linux下的jdk安装以及环境配置,有两种常用方法: 1.使用yum一键安装。 2.手动安装,在Oracle官网下载好需要的jdk版本,上传解压并配置环境。 这里介绍第一种方法,在此之前简单了解下yum。 yum 介绍 yum&…