跳轉到內容

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://: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 程式設計

瀏覽並下載 完整程式碼
華夏公益教科書