saveGif() で手軽に p5.js アニメーション

2022年11月5日土曜日

p5.js ツール 初心者向け

t f B! P L
p5.js で描いた軌道のイメージ図

p5.js の saveGif() は、スケッチを録画してアニメーション GIF を生成してくれる関数です。

私は、動画を作るには Processing のほうが扱いやすく、今まで動きのあるスケッチを p5.js で作るのは避けてきました。

p5.js バージョン 1.5.0 で導入されたこの新機能 saveGif() がどれぐらい使えるものか、確認したいと思います。

👉 Read this article in English.

 

まずは基本の使い方

まずはリファレンスを参考にコードを書いてみます。

saveGif() | reference | p5.js

これは、フレームレートを 30fps に設定し、's' キーが押されたら 1秒間分録画して 01.gif というファイルに書き出そうとするコードです。


/**
 * saveGif() test.
 * ref. https://p5js.org/reference/#/p5/saveGif
 * 
 * @author @deconbatch
 * @version 0.1
 * @license CC0
 * p5.js 1.5.0
 * created 2022.11.05
 */

const frmRate = 30;

function setup() {
  createCanvas(480, 480);
  smooth();
  frameRate(frmRate);
  fill(96);
  noStroke();
}

function draw() {
  const t = map(frameCount % frmRate, 0, frmRate, 0.0, 1.0);
  const x = width * 0.4 * cos(TWO_PI * t);
  const y = height * 0.4 * sin(TWO_PI * t);

  background(240);
  translate(width * 0.5, height * 0.5);
  circle(x, y, 50);
}

function keyPressed() {
  if (key === 's') {
    saveGif('01.gif', 1); // 1 sec
  }
}

p5.js のバージョンは 1.5.0 以上を指定しましょう。OpenProcessing であれば、モードの横にカーソルを持っていくと、使用する p5.js のバージョンが表示されます。そこをクリックすると選択肢が出ますので、ここで 1.5.0 以上を選択しましょう。

OpenProcessing で使われている p5.js バージョン

OpenProcessing で p5.js バージョンを選択

's' キーを押して録画してみると、このようなアニメーション GIF が生成されました。

アニメーションGIF例

とてもお手軽です!

秒数ではなく、フレーム数を指定して録画する場合は、このような書き方が可能です。


saveGif('01.gif', 30, {delay: 0, units : 'frames'});

 

いろいろ試してみる

リファレンスから離れて、いろいろ思いつくことを試していきます。

setup() に入れると?

setup() 中に saveGif() を入れれば、最初のフレームから自動的に動画生成してくれるのでは?と、思ってやってみましたが、真っ黒い GIF が生成されるだけでした。

真っ黒なGIF画像

リファレンスにも「正しく動作しない」と書いてありますし、これはしょうがない。

 

背景が clear() だと

background() の代わりに clear() を使うと、真っ黒背景の GIF になりました。

背景が黒くなった GIF アニメーション

 

秒数は小数でもいける?

いけます。


saveGif('01.gif', 0.5); // 0.5 sec

0.5秒のGIFアニメーション

 

複数書いたら?

この場合、保存ダイヤログが2つ出てきて、動作するように見えます。しかし、保存された動画はフレームが飛んだおかしな結果になっていました。


saveGif('01.gif', 0.5);
saveGif('02.gif', 1.0);

フレームが飛び飛びのアニメーション

 

描画にめちゃ時間がかかる場合はどうなる?

一枚の描画にとても時間がかかるようなスケッチの場合、動画はどのように録画されるでしょうか?

実時間約 1秒でチューリングパターンが 1フレーム描画されるスケッチで試してみました。

結論としては大丈夫!こちらが frameRate(30) で 2秒間、60フレーム分を録画したものです。

チューリングパターンの成長のアニメーション

GIF 生成まではたっぷり 3分以上かかりますが、ご覧の通り約 2秒の滑らかな動きのアニメーションが生成されました。これは画面録画系のツールでは実現できないことです。

 

開始をアニメーションの最初からにするには?

サンプルコードのように、saveGif() をキーが押されたタイミングから始めると、アニメーションの最初から録画をすることが難しいです。アニメーションの最初のフレームから録画を開始したい場合はどうしたらいいでしょうか?

先に試した setup() 中に saveGif() を書く方法では、真っ黒 GIF が生成されるだけでした。

draw() 中に下記を入れて、最初のフレームで saveGif() を開始するようにしても同様でした。


  if (frameCount === 1) {
    saveGif('01.gif', 1.0);
  }

せいぜい思いついたのは、キーを押されたタイミングがアニメーションの最初のフレームの描画時だったときにだけ saveGif() を実行するというものでした。


const frmRate = 1;
const gifLen = frmRate * 8;

function keyPressed() {
  if (
      key === 's' &&
      frameCount % gifLen == 1
     ) {
    saveGif('08.gif', gifLen, {delay: 0, units : 'frames'}); // no delay, gifLen frames
  }
}

しかし、これでも開始がぴったり最初のフレームにならなかったり、途中のフレームが抜けたりしてしまうようです。

フレームが抜けてしまっている例

 

saveGif() 使い方のまとめ

ご紹介した saveGif() の使い方のポイントは大体以下のとおりです。

  1. p5.js のバージョンは 1.5.0 以上を使う。
  2. 書き方
    秒数指定の場合
    saveGif('ファイル名', 秒数)
    フレーム数指定の場合
    saveGif('ファイル名', フレーム数, {delay: 0, units : 'frames'})
    録画開始前に待ちを入れたい場合
    リファレンスを見てね
  3. keyPressed() などの中に書くこと。setup() や draw() に書いちゃダメ。
  4. 背景は background() を使うこと。clear() はダメ。

saveGif() は書き方がシンプルで、コードに数行加えるだけで録画が可能になる、とても手軽に使える録画機能です。

録画の開始をアニメーションの最初からにするのが難しかったり、Processing のようにシェルと組み合わせて動画を自動生成できるような利便性はないものの、この手軽さは実に魅力的です。

そして、いわゆる「重い描画」の場合でも想定したフレームレートで再生される動画を撮ってくれるというのは大きいと思います。今後、 p5.js で書いた、あっと驚くようなアニメーション作品がどんどん出てくるのではないでしょうか。

 

参考:OpenProcessing だけで完結する動画保存

必要なスキルはファイルの保存だけ! p5.js 動きのある作品の録画方法

QooQ