« ベジェの角を丸くする…XPressoでのtest2(半径を指定して角丸) | トップページ | 更新が… »

アニメーションとFPS(フレームレート)と数式

アニメーションを作成する時に、C.O.F.F.E.E.エクスプレッションやXPresso等で、オブジェクトの位置や回転などを数式で与える時の注意事項。

最終形態がビデオ(ビデオテープ/DVD-VIDEO)でテレビで見ることを前提に作成するならフレームレートは普通30fpsだろう。意図的に25だったり24/15/12とかに設定する事もあるけど…

では仮に、フレームレートは30fpsでz軸毎秒1回転するC.O.F.F.E.E.エクスプレッションを作ってみよう。

1回転は360°なので1フレームあたりの回転は 360°÷ 30fps = 12°となる。

C.O.F.F.E.E.エクスプレッションは…

/*
30fpsでz軸毎秒1回転のC.O.F.F.E.E.エクスプレッション
2009.5.7
*/


main(doc , op)
{
  var rot_z = 12.0;//1フレームあたりのZ軸回転
  var op_rot = op->GetRotation();//現在の回転の取得

  op_rot.z += Radians(rot_z);//現在のz軸回転に12°を足す

  op->SetRotation(op_rot);//回転を適用
}

単純に考えればこんな感じになるだろう。
これで再生ボタンを押してアニメーションを再生すると、間違いなくC.O.F.F.E.E.エクスプレッションが取り付けられているオブジェクトは、Z軸で毎秒1回転します。
レンダリングも問題ないだろう。

本当に問題が無いだろうか…

あるよね…

何度もプレビューしているうちに、z軸の回転数値が増えていきます。数値は増える一方です。
では、0フレームで初期化するのか…

/*
30fpsでz軸毎秒1回転のC.O.F.F.E.E.エクスプレッション
0フレームで初期化
2009.5.7
*/


main(doc , op)
{
  var rot_z = 12.0;//1フレームあたりのZ軸回転
  var op_rot = op->GetRotation();//現在の回転の取得

  if(doc->GetTime()->GetFrame(30) == 0){//0フレームで初期化
    op_rot.z = 0.0;
  }else{
    op_rot.z += Radians(rot_z);//現在のz軸回転に12°を足す
  }

  op->SetRotation(op_rot);//回転を適用
}

これで、0フレームでz軸が回転0に初期化されます。

さあ、これで問題は無いはず…

本当だろうか…

問題はある…

はじめに、フレームレート30fpsと条件を出されたからと言って30フレームに限定した作りにすると、フレームレートが変更になったときに一々書き換えなければならなくなります。
30フレームに決まっていようと無かろうと、フレームレートが必要ならば、まずDocumentのフレームレートをC.O.F.F.E.E.で取得する事。

ドキュメントのフレームレートの取得は、

BaseDocument->GetFps()

です。

回転角度の計算。
確かにフレームを移動するたびに角度を増やしていけば良いのだけど…この方法にも問題がある。

フレームを移動すると増分を現在の角度に加える。本当にそのように動作するのか…

C.O.F.F.E.E.エクスプレッションは、フレームを移動するとき(再生/レンダリング)のみ実行されるものではありません。
C4Dのイベントにも反応するように作られています。
この状態だと、逆再生しても逆回転はしません。
いきなり2秒先にタイムスライダーを移動させても12°しか回転しません。

そもそも、フレームに対応した回転角度を求める必要があります。

今回のC.O.F.F.E.E.エクスプレッションは、回転の速度も一定なので数式で与える。
時間と回転は比例関係にあります。

現在の回転角度 = 1秒間当たりの回転角度 × 秒数 + 初期値

これで、タイムスライダーを、どの位置に移動させても、その時間の回転角度が得られます。

数式はフレームベースではなく、秒ベースで計算する事。
Documentのフレームレートは変更が可能なので時間の単位にするには完全ではないからです。

Documentから時間(秒)を取得するには、DocumentからBaseTimeを取得し、そのBaseTimeから秒を取得します。

BaseDocument->GetTime()
BaseTime->GetSecond()

しかも今回は一定速で回転するだけで、秒ベースで算出するので、フレームレートを使う必要がありません。
フレームレートを使う必要がないという事はドキュメントのフレームレートを取得する必要が無いと言うことです。

回転を数式にした為に0フレームで初期化する必要がなくなります。

では、フレームレートが変更されても問題なく、より完璧に動作するようにしよう…

/*
z軸毎秒1回転のC.O.F.F.E.E.エクスプレッション
2009.5.7
*/


main(doc , op)
{
  var rot_z = 360.0;      //1秒あたりのZ軸回転
  var offset = 0.0;       //初期値
  var op_rot = op->GetRotation();       //現在の回転の取得
  var sec = doc->GetTime()->GetSecond();//現在の秒を取得

  op_rot.z = sec * Radians(rot_z) + Radians(offset);//z軸回転の数式

  op->SetRotation(op_rot);//回転を適用
}

さて本当に完璧だろうか…

1秒当たりの回転数に負の値を設定しても問題なく逆に回転します。
初期値に任意の数値を設定したら、回転の最初の角度を設定できます。

一定速で回転させる為に数式を使い各フレームに対応させる事については問題ないと思います。

ただし、途中で速度を変化させたり、他のオブジェクトとの当たり判定をさせるのであれば、数式では対応できないので、フレームで処理しなければいけません。

今回のファイルはありません。
今回は、C.O.F.F.E.E.エクスプレッションです。

注意
XPressoでのC.O.F.F.E.E.ノードの中で、フレームレートや時間を取得する為に

var doc = GetActiveDocument();
var fps = doc->GetFps();//フレームレートの取得
var sec = doc->GetTime()->GetSecond();//現在生成中の秒の取得

この様にしないでください。

時間に関する取得の方法は、一般ノードの「時間」ノードを使用してください。
時間ノードから出力した数値をC.O.F.F.E.E.ノードの入力ポートで受けてください。

理由は以下の通りです。
アニメーションをレンダリング中に、C4Dにシーンファイルが画面上に展開されていないと、docはnilになります。
レンダリング中に、、シーンファイル閉じてもレンダリングは続行されますが、docはnilになります。
この他に、レンダリング中にdocがnilになる状態は、複数のシーンファイルがC4Dに読み込まれていて、他のシーンファイルに切り替えると起こります。

今回は、偉そうに解説しましたが、今まで書いたXPressoは、大丈夫なのだろうか…
それが、そうでもないのだ。ごめんね…

|

« ベジェの角を丸くする…XPressoでのtest2(半径を指定して角丸) | トップページ | 更新が… »