朝花夕拾

轻飘飘的旧时光就这么溜走 转头回去看看时已匆匆数年

用 Python + glsl 制作 Reaction-Diffusion 动画

2016-03-01


这是我学习 OpenGL 渲染管线和 glsl 语言的第一个正式项目,算是我学习 OpenGL 的 “Hello World” 程序,代码在 Github 上。

Reaction-Diffusion 属于 shader 里面比较基础的项目,对初学者掌握如 texture, FrameBuffer 之类的概念很有帮助,当然它本身也有一定的趣味性。我的这个程序是受到了 pmneila 的 Javascript 项目 的启发而作。我那时还不懂 js,自认为用 js 现学现卖再写一遍肯定写不过人家,所以考虑写一个 Python 的版本。然而 Python 下面并没有公认好用的 OpenGL 封装,所以我这里只能手写了两个辅助类 ShaderFrameBuffer 来管理 shader 程序和分配 buffer,用 pyglet 这个库来提供 OpenGL 环境和 UI 界面。最终的效果如下,这里选取了几个好看一些的效果做成了视频:

  1. unstable 图案

  2. coral 图案

  3. pulsaing solitons 图案

效果还是不错的,美中不足的是 pyglet 不提供菜单,按钮之类的界面,自己写起来又甚是麻烦,所以姑且就用键盘操作吧。

这个 app 允许你:

  1. 在屏幕上点击和拖动鼠标来涂抹。
  2. 按 ctrl + s 更换图案 (s 代表 species,即种群),按 ctrl + p(p 代表 palette,即配色)更换染色方案。
  3. 按 enter 键保存截图。
  4. 按 ctrl + v 开启将动画保存到视频中,再次按 ctrl + v 停止保存视频。(需要安装 ffmpeg)
  5. 按 ctrl + s 保存当前设置,按 ctrl + o 加载已经保存的设置。
  6. 按 space 键清空屏幕。

代码的核心是那几个 glsl 文件,准确的说,是两段 fragment shader 代码 reaction.fragcolor.frag,一个用于计算并渲染到后端的 frame buffer 上,另一个用于将得到的结果染色并渲染到前端的 window buffer 上。其余一大坨 .py 代码只是为了设置怎样与 shader 程序交互而已。

用 Python 写 shader 的一个大坑是需要把 Python 的数据类型用 ctypes 转换为 OpenGL 的数据类型,此外 debug 的时候也非常痛苦。