基于GLUT的PyOpenGL的使用
1. GLUT概述
OpenGL只是一种规范,不仅语言无关,而且平台无关。规范只字未提获得和管理OpenGL上下文相关的内容,而是将这些作为细节交给底层的窗口系统。出于同样的原因,OpenGL纯粹专注于渲染,而不提供输入、音频以及窗口相关的API
OpenGL Utility Toolkit (GLUT) 是一个具有 ANSI C 和 FORTRAN 绑定的编程接口,用于编写独立于窗口系统的 OpenGL 程序。该工具包支持以下功能:
- 多个用于OpenGL渲染的窗口 
- 回调驱动的事件处理 
- 复杂的输入设备 
- 简单的级联弹出菜单 
- ...... 
参考:1 Introduction (opengl.org)
GLUT简化了使用OpenGL渲染的程序实现。GLUT 应用程序编程接口 (API) 只需要很少的例程来显示使用 OpenGL 渲染的图形场景。GLUT 根据其功能在逻辑上组织成多个子 API。子 API 包括:
- 初始化 - 命令行处理、窗口系统初始化和初始窗口创建状态由这些例程控制 
- 开始事件处理 - 此例程进入 GLUT 的事件处理循环。此例程永远不会返回,并且它会根据需要不断调用 GLUT 回调 
- 窗口管理 - 这些例程创建和控制窗口 
- 叠加管理 - 这些例程建立和管理窗口的叠加 
- 菜单管理 - 这些例程创建和控制弹出菜单 
- 回调注册 - 这些例程注册要由 GLUT 事件处理循环调用的回调 
- 颜色索引色彩映射表管 - 这些例程允许操作窗口的颜色索引色彩映射表 
- 状态检索 - 这些例程允许程序从 GLUT 中检索状态 
- 字体呈现 - 这些例程允许呈现笔画和位图字体 
- 几何形状渲染 - 这些例程允许渲染 3D 几何对象,包括球体、圆锥体、二十面体和茶壶 
2. GLUT的使用
笔者这里使用的是PyOpenGL包及其包含的GLUT绑定
PyOpenGL的安装参考:PyOpenGL的安装与错误解决 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)
本文的逻辑流程参考GLUT的API文档:Contents (opengl.org)
2.1 初始化
以 glutInit- 前缀开头的例程用于初始化 GLUT 状态。主要的初始化例程是 glutInit(),在 GLUT 程序中只应调用一次。在 glutInit() 之前,不应调用任何非 glutInit 前缀的 GLUT 或 OpenGL 例程
其他 glutInit- 例程可以在 glutInit() 之前调用。原因是这些例程可用于设置默认窗口初始化状态,这些状态可能由在 glutInit() 中完成的命令处理修改。例如, 可以在 glutInitInit 之前调用 glutInitWindowSize(400, 400),以指示 400 x 400 是程序的默认窗口大小。 在 glutInit() 之前设置初始窗口大小或位置允许 GLUT 程序用户使用命令行参数指定初始大小或位置
glutInit() 将初始化 GLUT 库,并与窗口系统建立会话
glutInit()还处理命令行选项,但特定选项解析取决于窗口系统
初始化的相关API有:
- glutInitWindowPosition - 初始窗口位置,初始值为 -1 和 -1。如果初始窗口位置的 X 或 Y 分量为负数,则实际窗口位置由窗口系统确定 
- glutInitWindowSize - 初始窗口大小,初始值为 300 x 300。 初始窗口大小组件必须大于零。这些初始信息可以使用回调函数修改 
- glutInitDisplayMode 
 设置初始显示模式,假定想要一个有单缓冲区,深度缓冲区的RGB窗口,用“或“(|)操作符来建立你想要的显示模式
		glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE|GLUT|DEPTH),更多可用参数见官方文档2.3 glutInitDisplayMode (opengl.org)
Python代码:
# 引入GLUT库
from OpenGL.GLUT import *
glutInit()
'''
进行各种初始化
'''
2.2 窗口管理
GLUT初始化以后,需要创建窗口,才能进行渲染
GLUT 支持两种类型的窗口:顶级窗口和子窗口。这两种类型都支持 OpenGL 渲染和 GLUT 回调
相关的API有:
- 4.1 glutCreateWindow
- 4.2 glutCreateSubWindow
- 4.3 glutSetWindow, glutGetWindow
- 4.4 glutDestroyWindow
- ......
对于初学者来说,glutCreateWindow应该是使用最多的函数
int glutCreateWindow(char *name)创建一个顶级窗口,需要注意的是,参数是用作窗口名称的 ASCII 字符串,不是string
Python代码:
#通过b前缀将字符串转换成 bytes
glutCreateWindow(b"First")
2.3 注册回调
GLUT 支持许多回调来响应事件。有三种类型的回调:窗口、菜单和全局。窗口回调指示何时重新显示或改变窗口的形状、窗口的可见性何时更改以及输入何时可用于窗口
支持回调函数的API有:
- 7.1 glutDisplayFunc
- 7.2 glutOverlayDisplayFunc
- 7.3 glutReshapeFunc
- 7.4 glutKeyboardFunc
- 7.5 glutMouseFunc
- ......
glutDisplayFunc算得上是使用最多的注册回调函数,图形的绘制离不开这个API
glutDisplayFunc(void (*func)(void)) 设置当前窗口的显示回调
当 GLUT 确定需要重新显示窗口的正常平面时,将调用窗口的显示回调
Python代码:
def drawFunc():
    '''
    绘制函数
    '''
#注册绘制函数为显示的回调函数,将会不停调用来绘制
glutDisplayFunc(drawFunc)
2.4 开始事件处理
在 GLUT 程序完成初始设置(如创建窗口和菜单)后,GLUT 程序通过调用 glutMainLoop() 进入 GLUT 事件处理循环
此例程在 GLUT 程序中最多应调用一次。一旦调用,此例程将永远不会返回。它将根据需要调用已注册的任何回调
Python代码:
glutMainLoop()
2.5 小结
虽然笔者只讲述了上述几个API,但是绘制图形已经足够,代码小结如下:
# 引入GLUT库
from OpenGL.GLUT import *
glutInit()
'''
进行各种初始化
'''
#通过b前缀将字符串转换成 bytes
glutCreateWindow(b"First")
def drawFunc():
    '''
    绘制函数
    '''
#注册绘制函数为显示的回调函数,将会不停调用来绘制
glutDisplayFunc(drawFunc)
glutMainLoop()
3. 渲染
渲染是OpenGL的任务,而GLUT是提供渲染的环境(包括窗体等)
上述步骤已经建立了渲染的环境,在这里,将完善渲染函数,渲染出图形
3.1 清除绘制
在每个新的渲染迭代开始的时候我们总是希望清屏,否则我们仍能看见上一次迭代的渲染结果(这可能是你想要的效果,但通常这不是)
我们可以通过调用glClear函数来清空屏幕的颜色缓冲,它接受一个缓冲位(Buffer Bit)来指定要清空的缓冲,可能的缓冲位有GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT和GL_STENCIL_BUFFER_BIT。由于现在我们只关心颜色值,所以我们只清空颜色缓冲
除了glClear之外,我们还调用了glClearColor来设置清空屏幕所用的颜色。当调用glClear函数,清除颜色缓冲之后,整个颜色缓冲都会被填充为glClearColor里所设置的颜色
Python代码:
glClearColor(0.2, 0.3, 0.3, 1)
glClear(GL_COLOR_BUFFER_BIT)
3.2 绘制图像
绘制流程终究不是几句话可以说完的,这里笔者使用GLUT自带的茶壶进行绘制
glutSolidTeapot(GLdouble size)和glutWireTeapot(GLdouble size)分别渲染固体或线框茶壶。生成茶壶的表面法线和纹理坐标。茶壶是使用 OpenGL 评估器生成的
参数size为茶壶的相对大小
Python代码:
glutSolidTeapot(0.5)
3.3 刷新缓冲
OpenGL是使用一条渲染管线线性处理命令的,一般情况下,我们提交给OpenGL的指令并不是马上送到驱动程序里执行的,而是放到一个缓冲区里面,等这个缓冲区满了再一次过发到驱动程序里执行;很多时候只有几条指令是填充不满那个缓冲区的,就是说这些指令根本没有被发送到驱动里
glFlush()是OpenGL中的函数,用于强制刷新缓冲,保证绘图命令将被执行,而不是存储在缓冲区中等待其他的OpenGL命令
Python代码:
glFlush()
# glFinish()也可
3.4 小结
利用上述所有步骤的代码,我们已经可以绘制一个图形
全部的Python代码:
# 引入GLUT、OpenGL库
from OpenGL.GLUT import *
from OpenGL.GL import *
glutInit()
'''
进行各种初始化
'''
#通过b前缀将字符串转换成 bytes
glutCreateWindow(b"First")
def drawFunc():
    '''
    绘制函数
    '''
    glClearColor(0.2, 0.3, 0.3, 1)
    glClear(GL_COLOR_BUFFER_BIT)
    glutSolidTeapot(0.5)
    glFlush()
#注册绘制函数为显示的回调函数,将会不停调用来绘制
glutDisplayFunc(drawFunc)
glutMainLoop()
绘制的结果:

4. 参考文档
[2]PyOpenGL的安装与错误解决 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)
[3]OpenGL---GLUT教程(二) GLUT初始化 - 杨溪 - 博客园 (cnblogs.com)
[5]【OpenGL】glFinish()和glFlush()函数详解-转 - vranger - 博客园 (cnblogs.com)
基于GLUT的PyOpenGL的使用的更多相关文章
- VS2012下基于Glut 矩阵变换示例程序2:
		在VS2012下基于Glut 矩阵变换示例程序:中我们在绘制甜圈或者圆柱时使用矩阵对相应的坐标进行变换后自己绘制甜圈或者圆柱.我们也可以使用glLoadMatrixf.glLoadMatrixd载入变 ... 
- VS2012下基于Glut 矩阵变换示例程序:
		也可以使用我们自己的矩阵运算来实现OpenGL下的glTranslatef相应的旋转变换.需要注意的是OpenGL下的矩阵是列优先存储的. 示例通过矩阵运算使得圆柱或者甜圈自动绕Y轴旋转,可以单击鼠标 ... 
- VS2012下基于Glut OpenGL glEdgeFlag示例程序:
		glEdgeFlag (GLboolean flag)表示一个顶点是否应该被认为是多边形的一条边界边的起点.flag为GL_TRUE后面的点都被认为是边界上的点,flag为GL_FALSE则之后的点不 ... 
- VS2012下基于Glut OpenGL glDepthMask示例程序:
		glDepthMask (GLboolean flag)函数可以决定将他之后的数据不写入深度缓冲区.当flag为GL_TRUE时之后的数据不写入深度缓冲区,即使启用了深度缓冲区测试功能. 使用上一个D ... 
- VS2012下基于Glut OpenGL glScissor示例程序:
		剪裁测试用于限制绘制区域.我们可以指定一个矩形的剪裁窗口,当启用剪裁测试后,只有在这个窗口之内的像素才能被绘制,其它像素则会被丢弃.换句话说,无论怎么绘制,剪裁窗口以外的像素将不会被修改.有的朋友可能 ... 
- 跟我学Python图像处理丨带你入门OpenGL
		摘要:介绍Python和OpenGL的入门知识,包括安装.语法.基本图形绘制等. 本文分享自华为云社区<[Python图像处理] 二十七.OpenGL入门及绘制基本图形(一)>,作者:ea ... 
- H5游戏开发之多边形碰撞检测
		2D多边形碰撞检测介绍这是一篇论证如何在2D动作游戏中执行碰撞检测的文章(Mario,宇宙入侵者等),为了保证它的高效性和精确性,碰撞检测是以多边形为基础的,而不是以sprite为基础.这是两种不同的 ... 
- Mac使用Xcode配置openGL
		Mac使用Xcode配置openGL 博主这学期有图形学课要用到OpenGL,于是首先就开始配置开发环境了.应该说网上Windows上配置OpenGL教程比较多,Mac版的比较少.博主特来分享配置过程 ... 
- Start from here: <<OpenGL的基本程序解析>>
		这是我的第一篇学习OpenGL的笔记,也是博主的第一篇博客,希望能够在这里和大家一起成长. 下面的代码是<OpenGL超级宝典(第五版)>中的示例代码,基本程序如下: #include & ... 
- 二进制格式 PLY 模型文件的读取与渲染
		PLY 文件头部信息: ply format binary_little_endian 1.0 comment VCGLIB generated element vertex 13469 proper ... 
随机推荐
- 【每日一题】【双端降序队列Deque】2021年12月28日-239. 滑动窗口最大值
			给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 来源:力扣(L ... 
- NavigationDuplicated Navigating to current location (“/XXX”) is not allowed
			导航不允许导航到当前位置https://stackoverflow.com/questions/57837758/navigationduplicated-navigating-to-current- ... 
- uniapp 打包app 引入高德地图
			一.高德地图注册key值 二.项目中添加配置 三.项目中引用 <view class="home-btom-box" > <view class="ho ... 
- js将数组内属性值相同的项合并成二维数组
			var ary=[ {"RaDate":'2021-09-08',"Type":'Morning1','title':'测试1'}, {"RaDate ... 
- 「Goravel 上新」验证表单的三种新姿势,估计你只用过一种
			验证用户输入的数据是我们开发中最常见的需求,Goravel 提供三种验证姿势,个个简单好用! 第一种:简单直接式 根据表单内容直接校验: func (r *PostController) Store( ... 
- BBS项目(二): 登录功能 首页导航条搭建 首页主体部分 个人站点页面搭建 文章分类与标签 日期归档
			目录 登录功能 pillow模块生成验证码 前端发送ajax请求 后端auth模块校验 sweetalert弹窗提示登录失败 首页导航条搭建 修改密码 退出登录 首页主体部分 首页前端框架搭建 adm ... 
- [常用工具] C++环境下Qt的安装
			文章目录 1 Qt(C++)版本的选择 2 Qt 安装 2.1 Qt 6.3.1的安装 2.2 Qt 5.14.2的安装 3 Qt 其他版本安装 1 Qt(C++)版本的选择 Qt(C++)是一个跨平 ... 
- JAVA中使用最广泛的本地缓存?Ehcache的自信从何而来 —— 感受来自Ehcache的强大实力
			大家好,又见面了. 本文是笔者作为掘金技术社区签约作者的身份输出的缓存专栏系列内容,将会通过系列专题,讲清楚缓存的方方面面.如果感兴趣,欢迎关注以获取后续更新. 作为<深入理解缓存原理与实战设计 ... 
- 求和【第十三届蓝桥杯省赛C++A/C组 , 第十三届蓝桥杯省赛JAVAA组】
			求和 给定 \(n\) 个整数 \(a1,a2,⋅⋅⋅,an\),求它们两两相乘再相加的和,即 \(S=a1⋅a2+a1⋅a3+⋅⋅⋅+a1⋅an+a2⋅a3+⋅⋅⋅+an−2⋅an−1+an−2⋅a ... 
- iOS如何实现自动化打包
			iOS如何实现自动化打包 前言 在我们的日常开发工作中,避免不了会出现这样的场景:需求迭代开发完成之后,需要提供ipa包给QA同学进行测试,一般会执行如下流程:1.执行Git Pull命令,拉最新的代 ... 
