基于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 几何对象,包括球体、圆锥体、二十面体和茶壶

    参考:1.2 Design Philosophy (opengl.org)

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有:

对于初学者来说,glutCreateWindow应该是使用最多的函数

int glutCreateWindow(char *name)创建一个顶级窗口,需要注意的是,参数是用作窗口名称的 ASCII 字符串,不是string

Python代码:

#通过b前缀将字符串转换成 bytes
glutCreateWindow(b"First")

2.3 注册回调

GLUT 支持许多回调来响应事件。有三种类型的回调:窗口、菜单和全局。窗口回调指示何时重新显示或改变窗口的形状、窗口的可见性何时更改以及输入何时可用于窗口

支持回调函数的API有:

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()

绘制的结果:

image-20220706000724202

4. 参考文档

[1]Contents (opengl.org)

[2]PyOpenGL的安装与错误解决 - 当时明月在曾照彩云归 - 博客园 (cnblogs.com)

[3]OpenGL---GLUT教程(二) GLUT初始化 - 杨溪 - 博客园 (cnblogs.com)

[4]glFlush_百度百科 (baidu.com)

[5]【OpenGL】glFinish()和glFlush()函数详解-转 - vranger - 博客园 (cnblogs.com)

posted @ 2022-07-05 23:56  当时明月在曾照彩云归  阅读(766)  评论(0编辑  收藏  举报