Bash 的 OpenGL 绑定

一个最初只是玩笑的项目,对于想要学习 OpenGL 概念的人来说可能很有用。
336 位读者喜欢这个。
open envelope

Opensource.com。CC BY-SA 4.0。

在我之前的文章中,我描述了 Perl 5 的设计及其作为“胶水语言”的适用性,我提到我之前为 Bash 编写了 OpenGL 绑定。这可能是一个令人难以置信的说法,需要一些证据来证明,所以我回到我硬盘驱动器的角落里,把它挖出来,稍微修整了一下,改进了字体支持,编写了文档,并将其发布在我的网站GitHub上。(您需要一个同时支持 Bash 和 OpenGL 的系统才能亲身体验,但这里有一个视频。)

所以现在我要坦白:我在我的 DeLorean 运行 Perl 中描述的 DeLorean 仪表板中的 Perl 图形与我的 Bash OpenGL 项目有着共同的历史。有趣且具有讽刺意味的是,我最初在 13 年前开始这个项目,当时我看到了Frozen Bubble,并且我的技术敏感性受到了冒犯,因为有人用 Perl 编写了一个实时视频游戏。那时,我的主要语言是 C++,我正在学习 OpenGL 用于视频游戏目的。我向我的朋友们宣称,唯一更糟糕的事情是它是 3D 的并且是用 Bash 编写的。说出这个想法后,它一直困扰着我,我最终决定尝试一下,以超越使用 Perl 进行实时图形的“糟糕程度”。

扩展 Bash

将 OpenGL 支持添加到 Bash 最直接的方法是修改源代码,并将每个 OpenGL 函数添加为 shell“builtin”;但是,唯一能够体验到它的人将是那些愿意安装自定义 Bash 版本的人,而且可能没有人愿意这样做。这似乎也不符合“Bash 方式”的精神。

然后我想出了一个客户端-服务器的想法,其中每个 OpenGL 函数都将安装在路径中,并调用一个客户端来连接到 OpenGL 服务器,以传递消息来执行该函数。那将是一个非常“糟糕”的解决方案,但无论我如何努力优化,它仍然太慢了,我无法说我实现了总体目标。

最后,我确定了一个设计,即我将有一个“OpenGL 解释器”进程,它将在标准输入上读取 OpenGL 命令,并将任何用户输入事件写入标准输出。然后,Bash 脚本可以启动连接到管道的解释器,并且每个 OpenGL 命令都可以是一个写入管道的 Bash 函数。当我在做这件事的时候,我决定投入我所有的效率技巧,并用纯 C 编写解释器,并使用一些静态编译的哈希表红黑树

OpenGL 即时模式

OpenGL 的细节是这个项目开始与 DeLorean 仪表板项目相交的地方。首先,我将退后一步,回顾一下 OpenGL API。

OpenGL 的全部内容是编写一个程序,该程序以 3D 坐标和纹理来规划其图形,然后将该数据传输到图形卡以渲染到 2D 屏幕。简单来说,有一组数学运算用于描述正在绘制的屏幕区域,还有一组数学运算用于描述该区域中每个像素的颜色。

最常见的操作是描述虚拟 3D 空间中三角形的三个角,让 OpenGL 弄清楚它在 2D 屏幕上的位置,然后告诉它在该区域上拉伸 2D 图像,也可能与其他图像组合或通过一些亮度计算进行更改。程序的主循环通过擦除缓冲区、绘制每个可见的多边形并将其发送到屏幕来生成一帧视频。如果您在 16 毫秒或更短的时间内完成整个特技,您可以保持每秒 60 帧并获得流畅的图形。

我无法权威地谈论 OpenGL API 的起源,但它似乎很清楚它是围绕流媒体的想法构建的,可能是为了与 X11 显示协议兼容,但也仅仅是因为这是一个好主意。因此,大多数 OpenGL 函数没有返回值,这与其他 API 不同,在其他 API 中,每个函数调用都会返回一个状态,告诉您操作的结果。如果您将 OpenGL 函数(例如 glVertex3f(1,2,3))可视化为一个打印语句,该语句通过管道写入三个数字,那么您就很好地了解了它在幕后的工作方式。事实上,对于 Bash 绑定,当我执行 glVertex 1 2 3 时,我实际上是通过管道写入 glVertex 1 2 3。Bash 脚本盲目运行,不知道其图形命令是否按预期执行。

多年来,OpenGL API 经历了几个大的修订,人们在他们的书中用整章的篇幅来写关于“保留”模式与“即时”模式,但这一切都归结为两个概念

  • 每帧都通过管道重新发送所有这些数据太慢了,所以让我们在另一端缓存一些数据。
  • 我们永远无法用内置的数学运算满足所有人的需求,所以让我们给人们一种语言来描述他们自己的自定义数学运算。

也就是说,虽然新的 OpenGL API 提供的缓存和自定义数学运算效率更高,而且对于顶级视频游戏来说肯定是需要的,但它们也更费力地设置和使用(和学习),并且可能对业余爱好者弊大于利。除非您正在进行高级图形效果或高细节模型,否则它们也是不必要的。

因此,尽管 Bash OpenGL 绑定仅处理“已弃用”的 API,但我仍然鼓励人们出于教育和修补目的来研究它。

显示列表

幸运的是,原始的 OpenGL API 有一些缓存机制,而且它们很容易使用。它们大致按照以下顺序工作

“嘿 OpenGL,我希望你在远程端创建对象 37”

“这是描述对象 37 的一些数据”

“在下一个渲染步骤中使用对象 37”

为了使其更简单,Bash 绑定允许您使用名称而不是数字。

第一种主要的对象类型是纹理,您可以在其中将 2D 图像加载到图形卡中,然后用它“绘制”多边形。第二种是“显示列表”,您可以在其中记录一系列 OpenGL 命令,然后像它们是单个 OpenGL 命令一样回放它们。

显示列表非常适合临时原型设计。您可以使用简单的顶点命令绘制一些描述您的 3D(或 2D)模型的点,然后将该点序列记录为显示列表,现在您可以使用单个命令渲染该模型。

有关此功能的示例,请查看Examples 目录中的 Robot.sh。 它在启动时为机器人身体的每个部分创建一个显示列表,并且在运行时,它每帧仅发出 58 行文本来渲染机器人。Bash 可以很容易地在 16 毫秒内生成 58 行文本(甚至在 12 年前也可以),因此该演示能够在常见的硬件上全速运行。

显示列表是我在 DeLorean 仪表板软件中使用的 Perl 图形的主要技巧。与 C 相比,Perl 函数调用有点昂贵,特别是对于像 OpenGL 1.4 这样函数密集的 API,但通过将事物组合到显示列表中,Perl 每个视频帧的工作量并不大。如果我没有为 Bash 项目学习这个技巧,Perl 项目就不会那么成功。

为什么我没有在 12 年前发布它?

虽然我能够在 Bash 中创建一些花哨的动画演示,但我实际的目标是用它创建一个完整的游戏。我的目标是克隆旧的飞行模拟游戏Terminal Velocity,我做到了让宇宙飞船可以在立方体场中飞行(请参阅Examples中的 Flight.sh),但下一个问题是碰撞检测。Bash 中可用的原语是变量名称和数组变量的全局“关联数组”(尽管版本 4 现在具有关联数组变量),并且所有数学都是整数。虽然我能够在定点整数数学中完成 3D 矩阵旋转,但实现碰撞检测看起来是一个太大的障碍。我对我的字体 API 也不满意。在思考这些问题的解决方案时,该项目逐渐从我的列表中消失了。

这就是我得出的结论(正如我写的),“Bash 是一种糟糕的胶水语言。” 虽然这个项目开始和结束都是一个玩笑(或者可能是教育工具),但 Perl 中相同的程序风格被证明对于实际应用程序非常有用。如果我在 13 年前更认真地考虑 Frozen Bubble,我可能已经能够在 Perl 上抢先一步,Perl 是我现在最喜欢的语言。

除了错误修复之外,我没有任何增强此项目的计划,但我想它至少可能对想要学习 OpenGL 概念的人或有大量空闲时间和强烈愿望用M4编写 Doom 克隆的人有用。

享受吧!并尽情转发此链接,否则没人会相信你。

标签
User profile image.
IntelliTree Solutions 的软件工程师。Michael 专注于 Web 应用程序、嵌入式系统和性能调优。

2 条评论

我希望这是 100% 真实的,因为这是世界现在需要的。

你在 BASH 中得到了非常好的 OpenGL。现在让我们看看你用 COBOL 做这件事。

知识共享许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.