跳转到内容

OpenGL 编程/视频录制

来自维基教科书,自由的教科书

apitrace 是一个不错的 调试 工具。

它具有保存/回放功能,可以捕获您对显卡的所有指令,并在以后重现,甚至可以将结果保存为一系列图片。

我们将使用它来创建一个适合上传到维基共享资源的视频!

编译 (GNU/Linux 指令)

[编辑 | 编辑源代码]

获取源代码

cd /usr/src/
git clone https://github.com/apitrace/apitrace.git
cd apitrace/

安装 cmake 和依赖项

apt-get install cmake libx11-dev

编译!

cmake -H. -Bbuild
cd build
make

注意:对于 64 位主机上的 32 位构建

CFLAGS="-m32" CXXFLAGS="-m32" cmake -H. -Bbuild

让我们使用简单的波浪后处理效果进行测试

cd wikibooks-opengl-modern-tutorials/obj-viewer/
LD_PRELOAD=/usr/src/apitrace/build/wrappers/glxtrace.so ./obj-viewer

运行程序几秒钟,旋转物体,缩放等,然后退出程序。

这将创建一个 obj-viewer.trace 二进制文件。如果文件已经存在,它将创建 obj-viewer.1.trace,等等。

您可以使用 glretrace 命令,将跟踪文件作为参数传递给它

/usr/src/apitrace/build/glretrace suzanne.trace

当然,这不再是交互式的,这只是一个回放。

转换为视频

[编辑 | 编辑源代码]

让我们安装 ffmpeg

apt-get install ffmpeg

注意:我们尝试使用 ffmpeg 的缩放过滤器来减小屏幕尺寸 (-vf scale=200:150),但遗憾的是,无论我们如何尝试[1],它都会导致段错误。因此,我们只是重新编译了应用程序,并直接指定了更小的屏幕尺寸。

ffmpeg 的选项按以下方式组织

ffmpeg <input options> -i source <output options> destination
  • 我们将使用 .ogg 输出,因为这是维基共享资源唯一接受的格式(如果您知道谁可以获得对免费且更好的 .webm 格式的支持,请与他/她联系!)。
  • 教程中使用的屏幕的刷新率为 75Hz,但视频通常为 25 帧/秒,因此我们将降低速率(双倍输入和输出 -r 参数)
  • 我们将使用一个固定、高质量的 (-qscale)
  • 我们将覆盖目标文件 (-y)

我们得到

/usr/src/apitrace/build/glretrace -s - suzanne.trace \
  | ffmpeg -r 75 -f image2pipe -vcodec ppm -i pipe: -r 25 -qscale 31 -y output.ogg

我们已经得到了我们的视频 - 并且不需要额外的代码。

这是结果!

WebGL 变体

[编辑 | 编辑源代码]

在运行 WebGL 应用程序时,捕获浏览器对我们来说效果不佳:性能很差,它捕获了整个 Firefox 窗口 - 而不是仅仅是动画。

因此,我们实现了一个内部捕获系统

时间控制

[编辑 | 编辑源代码]

手动捕获的一项优点是,您可以根据需要控制时间流,从而避免在捕获过程中出现任何性能问题。我们通过在时间函数(在我们的例子中是 threejs)周围添加一个小包装器来做到这一点

    var capture_rate = 30;
    var capture_frame = 0;
    ...
    function getElapsedTime() {
        if (capture) {
            return capture_frame/capture_rate;
        } else {
            return clock.getElapsedTime();
        }
    }
    ...
    function render() {
        ...
        var angle = getElapsedTime() * 10;  // 10° per second
        ...
        if (capture) {
            capture_frame++;
        }
    }

我们决定使用 30FPS 帧率,这在视频中很常见(截至 2013 年)。

复制 WebGL 帧

[编辑 | 编辑源代码]

使用您的 WebGL 画布的 toDataURL 方法 

var base64_encoded_image = renderer.domElement.toDataURL();

这将返回一个以 base64 编码的图像,格式为 data:image/png;base64,iVBORw0KGgoAAAA...

使用 AJAX 导出

[编辑 | 编辑源代码]

JavaScript 无法直接保存本地文件,因此我们将使用 Ajax 将这些图像导出到 web 服务器 

    if (capture) {
        capture_frame++;
        r = XMLHttpRequest();
        r.open('POST', 'https://127.0.0.1:1337/' + capture_frame);
        r.send(renderer.domElement.toDataURL().substr("data:image/png;base64,".length));
    }

最小 web 服务器

[编辑 | 编辑源代码]

我们可以编写一个最小 web 服务器,它将使用 NodeJS 存储我们导出的图像

var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
    var idx = req.url.split('/')[1];
    var filename = "capture/" + ("0000" + idx).slice(-5)+".png";
    var img = '';
    req.on('data', function(chunk) { img += chunk });
    req.on('end', function() {
        f = fs.writeFileSync(filename, Buffer(img));
        res.end();
    });
    console.log('Wrote ' + filename);
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

您可以使用以下命令运行它 

mkdir capture/
nodejs save_capture.js

组装视频

[编辑 | 编辑源代码]

此步骤类似于上面使用 glretrace 的步骤。我们将只使用特殊语法来获取所有 PNG 文件

avconv -r 30 -i capture/%05d.png -y capture/output.webm

(顺便说一下,avconv 是 ffmpeg 的一个分支/替代品,具有几乎相同的命令行选项。)

我们完成了:我们获得了 WebGL 动画的完美同步捕获!

更进一步

[编辑 | 编辑源代码]

欢迎贡献如何捕获同步应用程序音频流 :)

参考文献

[编辑 | 编辑源代码]
  1. 此错误可能与 https://ffmpeg.org/trac/ffmpeg/ticket/397 相关

< OpenGL 编程

浏览并下载 完整代码
华夏公益教科书