p5.js の様々な関数の使い方をおさらいして、作例コードを書くことで、自身の知識の定着を図っています。
今回は frameRate() 関数と、それに関係の深い frameCount 変数を取り上げます。説明やコードに誤り、勘違いがあるかもしれません。何かあれば、ご指摘をいただけると嬉しいです。
p5.js は、バージョン 1.5.0 を使用しています。
frameRate() 関数の意味と使い方
frameRate() | p5.js 公式リファレンス
説明
主に、一秒間に何枚のフレームを描画するかの指定を行うのに使います。現在の fps値(frames per second:一秒間あたりのフレーム数)を得ることにも使えます。
CPU が遅くて描画が追いつかない等で、frameRate() で指定した値に実際の fps値が達しない場合もあります。よって、指定できるのは一秒間に何枚のフレームを描画するかの”上限”と考えたほうがよいでしょう。
コード中に frameRate(fps) の記載が無い場合、多くの環境ではデフォルト値 60fps が使用されます。
24fps以上あれば十分スムーズなアニメーションになるそうですが、24fps と 30fps では滑らかさに明らかな違いが出ることが多いと思います。
設定は setup() 中で行うのがよいでしょう。
書き方
パラメータ有りの場合
frameRate(fps)
パラメータ
- fps:一秒間あたりの描画フレーム数、小数の指定も可能(0.2 なら 5秒に 1枚描画)です。
パラメータ無しの場合
frameRate()
返り値
- 現在の一秒間あたりの描画フレーム数を返します。
- これは、frameRate(fps) でセットした fps の値になるとは限りません。計算量の多い、いわゆる重い描画であるほど fps の値より小さい値になるでしょう。
- setup() 中や、初回の draw() 中では値は 0 となるようです。
p5.js 公式リファレンスのコード例の補足
赤い四角形は 30fps で進み、青い四角形は 10fpsで進む。画面の端まで来たら赤と青が入れ替わる。というアニメーションです。
実際に動かしてみる場合、動きがまどろっこしいので、5倍速にしましょう。
rectX += 5; // Move Rectangle
draw() の最後に下記を入れると、動作がより分かりやすくなると思います。
text(frameRate(), 10, 10);
frameCount 変数の意味と使い方
frameCount | p5.js 公式リファレンス
説明
プログラム実行開始から何枚目のフレームを描画しているかを格納しているシステム変数です。
その値は setup() 内で 0、その後 draw() 内に入ると 1、その後 draw() が繰り返されるごとに 1カウントアップされます。途中で noLoop()、redraw() が入ってもこの関係は崩れません。
変数なので、値を代入することもできます。setup() 内で -1 を代入しておけば、draw() での frameCount を 0 から始めることができます。
どこまでカウントしてくれるのか?最大値は?
2^53 - 1 = 9007199254740991 では?
9,247,568までは実際にカウントしてみました。30fps で 3日半動かし続けても大丈夫! 代入もできるので、心配なら途中でリセットするようにコードを書くとよいでしょう。
p5.js 公式リファレンスのコード例の補足
変数 frameCount の値を画面に表示するコードです。
frameRate(30) を frameRate(1) にすると、frameCount が 1 から始まるのが見えるでしょう。
frameRate(0.25) とすると、4秒に一回 frameCount がカウントアップされることになります。このとき注目したいのが、最初のフレームが描画されるタイミングです。実行してみると、実行から 4秒経過後に最初のフレームが描画されることがわかります。
これからすると、frameRate(n) は一秒間に n枚のフレームを描画するというより、1枚のフレーム描画に 1/n秒かけるというのが正しいのかもしれません。
frameRate() と frameCount を使った作例
frameRate() と frameCount を使って、指定の秒数でループするアニメーションを作ります。
何かオブジェクトが動くアニメーションなら、オブジェクトの指定秒数後の位置を開始時と合わせればループになります。実現には、TWO_PI で値が一巡する三角関数を使って動きを制御すると簡単です。
ループアニメーション:回転
cNum 個の円がそれぞれ異なるスピードで回転するアニメーションです。cycleSec 秒でループします。
/**
* p5.js frameRate() 関数と frameCount 変数を用いた作例
* 回転するオブジェクトのループアニメーション
*
* @author @deconbatch
* @version 0.1
* @license CC0
* p5.js 1.5.0
* created 2023.01.31
*/
const w = 640;
const h = w;
const cNum = 6;
const frmRate = 24; // fps
const cycleSec = 5; // ループの秒数
const cycleFrm = frmRate * cycleSec;
function setup() {
createCanvas(w, h);
colorMode(HSB, 360, 100, 100, 100);
noStroke();
frameRate(frmRate);
}
function draw() {
// ここで周期を生み出す
const ratio = map(frameCount % cycleFrm, 0, cycleFrm, 0.0, TWO_PI);
background(240);
translate(w * 0.5, h * 0.5);
for (let cCnt = 1; cCnt <= cNum; cCnt++) {
let cR = map(cCnt, 1, cNum, 0.1, 0.4) * min(w, h);
let cX = cR * cos(ratio * cCnt);
let cY = cR * sin(ratio * cCnt);
fill(360 * cCnt / cNum, 40, 60, 100);
circle(cX, cY, 30);
}
}
円の座標計算時にランダム要素(円ごとの noise())を加えると、滅茶苦茶な動きをしてるように見えてちゃんとループするアニメーションにもできます。
let phaseX = noise(10, cCnt) * TWO_PI;
let phaseY = noise(20, cCnt) * TWO_PI;
let cX = cR * cos(ratio * cCnt + phaseX);
let cY = cR * sin(ratio * cCnt + phaseY);
ループアニメーション:サインカーブ
cNum 本のサインカーブがそれぞれ異なるスピードで揺れるアニメーションです。回転のコードの x 軸の計算を変えたものです。
cNum や xDiv の値を変えてみるといろんな表情が見られると思います。
/**
* p5.js frameRate() 関数と frameCount 変数を用いた作例
* サインカーブのループアニメーション
*
* @author @deconbatch
* @version 0.1
* @license CC0
* p5.js 1.5.0
* created 2023.01.31
*/
const w = 640;
const h = 320;
const cNum = 9;
const xDiv = 20;
const frmRate = 24; // fps
const cycleSec = 6; // ループの秒数
const cycleFrm = frmRate * cycleSec;
function setup() {
createCanvas(w, h);
frameRate(frmRate);
}
function draw() {
const ratio = map(frameCount % cycleFrm, 0, cycleFrm, 0.0, TWO_PI);
background(255);
translate(0, h * 0.5);
for (let cCnt = 1; cCnt <= cNum; cCnt++) {
let cR = map(cCnt, 1, cNum, 0.05, 0.2) * min(w, h);
for (let cX = 0; cX < w; cX += xDiv) {
let phaseY = TWO_PI * cX / w;
let cY = cR * sin(ratio * cCnt + phaseY);
circle(cX, cY, cCnt);
}
}
}