« C4D Python R12 テスト:C4D ThinkingParticlesとC4D Pythonと試行錯誤-2 | トップページ | C4D Python R12 テスト:C4D ThinkingParticlesとC4D Pythonと試行錯誤-3 »

C4D Python R12 テスト:アニメーションでPythonを使うなら、c4d.BaseTimeの事も少しは理解しないといけないよね…

正直に言うと、まぁC.O.F.F.E.E.の時から、なんとなく使っていたけどね…

静止画だけなら、時間軸は全く関係ありませんね。
PythonやC.O.F.F.E.E.を使わないユーザも覚える必要もないか…

アニメーションでPythonを使うなら、PythonタグかPythonノードなんだろうけど、今回はスクリプトマネージャ(Python)でね。

まずは…

シーンファイルの時間を取得するには…
グローバル変数docからBaseTimeを取得すれば良いんだ。

BaseDocument.GetTime() #シーンファイルからBaseTimeの取得

そこから、フレームや秒を取得するわけだ。

Python
import c4d


def main():
    bt = doc.GetTime()

    print 'frame:', bt.GetFrame(30)
    print '秒:',  bt.Get()


if __name__=='__main__':
    main()
frame: 71
秒 2.36666666667

フレームを取得するには、GetFrame()メソッドにfps(1秒間のフレームレート)を指定して使うんだ。

BaseTime.GetFrame(fps) #フレームの取得

上のコードは30fps限定になるね。

だけど、どんなシーンファイルにも対応するなら、シーンファイルのfpsを取得しそれを使用した方がいいだろう。

BaseDocument.GetFps() #シーンファイルのフレームレートの取得

そうすると、シーンを示しているグローバル変数:docから、一気にフレームを取得するにはこんな具合になるだろう。

    frame = doc.GetTime().GetFrame(doc.GetFps())

秒の取得はGet()だ。

BaseTime.Get() #秒の取得

さて、アニメーションで時間を使う場合、複数の時間を記憶したり、比較したりする事があるだろう…

新規のBaseTimeを使って時間を記憶するためには…

Python
import c4d


def main():
    bt1 = c4d.BaseTime(10.0)
    bt2 = c4d.BaseTime(20.0)
    print 'bt1 秒:', bt1.Get()
    print 'bt2 秒:', bt2.Get()


if __name__=='__main__':
    main()
bt1 秒: 10.0
bt2 秒: 20.0

BaseTimeに秒数を指定して記憶させる。

c4d.BaseTime(sec)

秒数で設定するするなら、フレームの時はどうするんだ?

まさか10フレームを設定するには、こんな風にか?

c4d.BaseTime(1.0/3) #fps30限定 10フレーム設定?

これでも設定は可能だろ?、fps30限定だけどね。

Python
import c4d


def main():
    bt1 = c4d.BaseTime(1.0/3)
    bt2 = c4d.BaseTime(20.0)

    print '='*5, 'bt1', '='*5
    print '秒:', bt1.Get()
    print 'フレーム:', bt1.GetFrame(doc.GetFps())

    print '='*5, 'bt2', '='*5
    print '秒:', bt2.Get()
    print 'フレーム:', bt2.GetFrame(doc.GetFps())


if __name__=='__main__':
    main()
===== bt1 =====
秒: 0.333
フレーム: 9
===== bt2 =====
秒: 20.0
フレーム: 600

オイオイ、bt1は9フレームしかないじゃないか? 1フレームはドコへ?
にっこり笑って許されるなら、これでも良いのか?

BaseTimeには時間を設定する方法がもう一つある。

Python
import c4d


def main():
    bt1 = c4d.BaseTime(10.0, 30.0)
    bt2 = c4d.BaseTime(20.0)

    print '='*5, 'bt1', '='*5
    print '秒:', bt1.Get()
    print 'フレーム:', bt1.GetFrame(doc.GetFps())

    print '='*5, 'bt2', '='*5
    print '秒:', bt2.Get()
    print 'フレーム:', bt2.GetFrame(doc.GetFps())


if __name__=='__main__':
    main()
===== bt1 =====
秒: 0.333333333333
フレーム: 10
===== bt2 =====
秒: 20.0
フレーム: 600

これで、bt1には10フレームが記憶されたわけだ。

と言う事は、こう言う事なのか?

c4d.BaseTime(frame, fps)

と言う事は、

c4d.BaseTime(frame, doc.GetFps())

これでも良いわけだ…

でも、本当はこんな事の様だ。

c4d.BaseTime(分子, 分母)

だから、次のように2つとも同じフレーム数になる…

Python
import c4d


def main():
    bt1 = c4d.BaseTime(10.0, 30.0)
    bt2 = c4d.BaseTime(1 , 3)

    print '='*5, 'bt1', '='*5
    print '秒:', bt1.Get()
    print 'フレーム:', bt1.GetFrame(doc.GetFps())

    print '='*5, 'bt2', '='*5
    print '秒:', bt2.Get()
    print 'フレーム:', bt2.GetFrame(doc.GetFps())


if __name__=='__main__':
    main()
===== bt1 =====
秒: 0.333333333333
フレーム: 10
===== bt2 =====
秒: 0.333333333333
フレーム: 10

なるほどね。

それでね、この分子、分母は単独での取得/設定したりすることもできるらしい。

Python
import c4d


def PrintBaseTime(bt):
    print '秒:', bt.Get()
    print 'フレーム:', bt.GetFrame(doc.GetFps())
    print '分子:', bt.GetNumerator()
    print '分母:', bt.GetDenominator()


def main():
    bt1 = c4d.BaseTime(10.0, 30.0)
    bt2 = c4d.BaseTime(1 , 3)

    print '='*5, 'bt1', '='*5
    PrintBaseTime(bt1)

    print '='*5, 'bt2', '='*5
    PrintBaseTime(bt2)


if __name__=='__main__':
    main()
===== bt1 =====
秒: 0.333333333333
フレーム: 10
分子: 1.0
分母: 3.0
===== bt2 =====
秒: 0.333333333333
フレーム: 10
分子: 1.0
分母: 3.0

bt1には、分子:10.0、分母:30.0で設定したのに、取得し直すと1.0/3.0になってるね。
C4D Python SDK DocにはBaseTime内で分子、分母は最小値(約分なのか?)に変換され保持されるような事が書いてあった…

分子、分母の取得は…

BaseTime.GetNumerator() #分子の取得
BaseTime.GetDenominator() #分母の取得

分子、分母の設定は…

BaseTime.SetNumerator() #分子の設定
BaseTime.SetDenominator() #分母の設定

では、こう言う場合はどうだろう…
次のようにbt = c4d.BaseTime(28 , 30)として28フレームを設定し…
28フレームを変更して27フレームに設定し直そう…
既に分母は30フレームで設定しているので、分子のみの設定bt.SetNumerator(27)としても問題ないのだろうか?

ま、試してみればわかるね…

Python
import c4d


def PrintBaseTime(bt):
    print '秒:', bt.Get()
    print 'フレーム:', bt.GetFrame(doc.GetFps())
    print '分子:', bt.GetNumerator()
    print '分母:', bt.GetDenominator()


def main():
    bt1 = c4d.BaseTime(28.0, 30.0)

    print '='*5, 'bt1', '='*5
    PrintBaseTime(bt1)

    print '='*5, 'bt1  reset', '='*5
    bt1.SetNumerator(27.0)
    PrintBaseTime(bt1)


if __name__=='__main__':
    main()
===== bt1 =====
秒: 0.933333333333
フレーム: 28
分子: 14.0
分母: 15.0
===== bt1  reset =====
秒: 1.8
フレーム: 54
分子: 27.0
分母: 15.0

問題有りの状態だね。
約分された後に分子を変えるわけだから、分母に合った分子を設定しないとダメなんだね。

そうすると、SetNumerator()/SetDenominator()を使うのは難しくないだろうか?
分子だけとか分母だけの設定ではなく、分子、分母両方を設定しなおす必要があるね…
でも…
分子を設定すると、既存の分母と約分され、次に分母を設定すると約分された分子と更に約分されるんだから、思った値にはならないかと…

複雑に考えないで、新規でBaseTimeを取得すれば良いだけの話か…

そう言えば…
BaseTime同士の四則演算ができるようだ… フレームベースじゃないよ、秒でね…

足し算、引き算を確かめた…

Python
import c4d


def PrintBaseTime(bt):
    print '秒:', bt.Get()
    print 'フレーム:', bt.GetFrame(doc.GetFps())


def main():
    bt1 = c4d.BaseTime(10.0, 30.0)
    bt2 = c4d.BaseTime(2.0 , 30.0)
    bt3 = bt1 + bt2
    bt4 = bt1 - bt2

    print '='*5, 'bt1', '='*5
    PrintBaseTime(bt1)

    print '='*5, 'bt2', '='*5
    PrintBaseTime(bt2)

    print '='*5, 'bt3', '='*5
    PrintBaseTime(bt3)

    print '='*5, 'bt4', '='*5
    PrintBaseTime(bt4)


if __name__=='__main__':
    main()
===== bt1 =====
秒: 0.333333333333
フレーム: 10
===== bt2 =====
秒: 0.0666666666667
フレーム: 2
===== bt3 =====
秒: 0.4
フレーム: 12
===== bt4 =====
秒: 0.266666666667
フレーム: 8

足し算、引き算は秒でもフレームでも結果は同じだけど…

掛け算、割り算も試してみる。

Python
import c4d


def PrintBaseTime(bt):
    print '秒:', bt.Get()
    print 'フレーム:', bt.GetFrame(doc.GetFps())


def main():
    bt1 = c4d.BaseTime(45.0, 30.0)
    bt2 = c4d.BaseTime(60.0, 30.0)
    bt3 = bt1 * bt2
    bt4 = bt1 / bt2

    print '='*5, 'bt1', '='*5
    PrintBaseTime(bt1)

    print '='*5, 'bt2', '='*5
    PrintBaseTime(bt2)

    print '='*5, 'bt3', '='*5
    PrintBaseTime(bt3)

    print '='*5, 'bt4', '='*5
    PrintBaseTime(bt4)


if __name__=='__main__':
    main()
===== bt1 =====
秒: 1.5
フレーム: 45
===== bt2 =====
秒: 2.0
フレーム: 60
===== bt3 =====
秒: 3.0
フレーム: 90
===== bt4 =====
秒: 0.75
フレーム: 22

わざわざ、秒やフレームを取得してから演算しなくても良いから便利…
だろうか?

比較は、BaseTimeのままで普通にできるのか?

Python
import c4d


def PrintBaseTime(bt):
    print '秒:', bt.Get()
    print 'フレーム:', bt.GetFrame(doc.GetFps())


def main():
    bt1 = c4d.BaseTime(45.0, 30.0)
    bt2 = c4d.BaseTime(60.0, 30.0)

    print '='*5, 'bt1', '='*5
    PrintBaseTime(bt1)

    print '='*5, 'bt2', '='*5
    PrintBaseTime(bt2)

    print '='*15
    print 'bt1 < bt2', bt1 < bt2
    print 'bt1 > bt2', bt1 > bt2
    print 'bt1 == bt2', bt1 == bt2
    print 'bt1 != bt2', bt1 != bt2


if __name__=='__main__':
    main()
===== bt1 =====
秒: 1.5
フレーム: 45
===== bt2 =====
秒: 2.0
フレーム: 60
===============
bt1 < bt2 True
bt1 > bt2 False
bt1 == bt2 False
bt1 != bt2 True

わざわざ秒やフレームを取得してから比較しないで良い分、らくだね…

これで、ほとんど試しただろうか…

もう1個…
量子化…

BaseTime.Quantize(fps) #fpsで量子化

時間の操作…時間を掛けたり割ったりすると、フレームで端数が出るよね、1.33フレームとか。
0.33ずれていたりするのを、整数のフレーム値になるように秒数を変更する…
あ、そうそう。GetFrame()で取得すると整数値になるので勘違いしないようにね…

例えば、BaseTime(11, 60)で設定する。これは30fpsの場合だと5.5フレームにあたる。
秒で言えば、0.18333333秒
これを、30fpsで量子化すると、1.0 / 30 = 0.03333333秒刻みになるんだね。
0.18333333秒 / 0.03333333秒 = 5.50000045フレーム
答えのフレームを小数点以下切捨て5として…
5 * 0.03333333秒 = 0.16666666秒

簡単に言うと「フレームにスナップさせる」みたいな…

じゃぁ試してみよう…

Python
import c4d


def PrintBaseTime(bt):
    print '秒:', bt.Get()
    print 'フレーム:', bt.GetFrame(doc.GetFps())


def main():
    bt1 = c4d.BaseTime(11.0, 60.0)

    print '='*5, 'bt1', '='*5
    PrintBaseTime(bt1)

    bt1.Quantize(doc.GetFps())
    print 'Quantize(', doc.GetFps(), ')'
    PrintBaseTime(bt1)


if __name__=='__main__':
    main()
===== bt1 =====
秒: 0.183333333333
フレーム: 5
Quantize( 30 )
秒: 0.166666666667
フレーム: 5

問題ないね…

|

« C4D Python R12 テスト:C4D ThinkingParticlesとC4D Pythonと試行錯誤-2 | トップページ | C4D Python R12 テスト:C4D ThinkingParticlesとC4D Pythonと試行錯誤-3 »

コメント

コメントを書く



(ウェブ上には掲載しません)




« C4D Python R12 テスト:C4D ThinkingParticlesとC4D Pythonと試行錯誤-2 | トップページ | C4D Python R12 テスト:C4D ThinkingParticlesとC4D Pythonと試行錯誤-3 »