Cinema4Dメモ

Cinema4Dという3DCGソフトに関するメモ書きです。

Pythonスクリプト「AnimCamScript」の存在価値が根底から揺さぶられる

2015-04-23 13:53:39 | Python & Cinema4D

そういうわけで、自作のPythonスクリプトは

AnimCamScript.py

に置いてあります。よかったらどうぞお試し下さい。

「Ctrl + E」で「一般設定」フォルダを開いて、開いたウィンドウの「一般設定フォルダを開く」ボタンを押し、「library]

→「scripts」の中にスクリプトを保存します。

そしたらスクリプトマネージャを開き、「開く」で開いたウィンドウからAnimCamScript.pyを選んで開いて下さい。そして実行すればいいです。

一回スクリプトマネージャから開くと、次からは「ユーザスクリプト」から選択して実行できるようになるようです。

複数のカメラの位置、角度、焦点距離を一つのカメラのキーフレームに格納します。

CameraGroupという名前(全角ではダメ)のヌルを作って、その中にレンダリングしたいカメラを入れます。

そしてカメラを新規で一個作り、そのカメラを選択した状態でスクリプトを実行します。

なんでこのスクリプトをPythonスクリプトの勉強までして作ったかというと、複数のカメラを一つにまとめて「カメラアニメーションです」ってことにしてしまえば、GIを使ったレンダリングで、GIのキャッシュファイルを複数のカメラで使いまわせるんじゃないかと思ったんです。結論から言うと、うまく出来ているような気がします。ただし、キャッシュファイルを使いまわすためだったら、別にカメラアニメーションにする必要もなかったです。よーく観察すると、フツーにカメラ切り替えても既存のキャッシュを使って綺麗にレンダリングしてるし・・・

※そもそもなんでそんなことを考えたかというと、あるカメラで室内をGIでレンダリングして、その時のGIキャッシュを使って次に違うカメラで違う方向をレンダリングしたら、最初のレンダリング時に写っていた部分は綺麗だけど、写っていなかった部分は汚かったという事があった(これは後で「カスタムサンプル数」にしてサンプル数を増やしたらあっけなく解消しましたが)からです。最初のカメラに写っている範囲しかGIのデータが作られてないの?と思ったわけで。でも複数のカメラをまとめてカメラアニメーションですってことにすれば、全部のフレームで見えている場所はGIの計算をしてくれるだろうと思ったわけ(ライトマップの「カメラパスを使う」ってオプションはまさにそれだと思うんですが)。

しかも!ステージオブジェクトを使うと、同じことが出来ます!

https://www.youtube.com/watch?v=9AHS5y6avSg

とほほ!まぁ勉強になったからいいか(泣)


複数のカメラのパラメータを一つのカメラに集約するPythonスクリプトが概ね完成

2015-04-18 00:28:27 | Python & Cinema4D

そういうわけで、スクリプトがやっと満足に動きました。

このスクリプトは後日公開するつもりですが、シーン内に複数あるカメラの位置と角度と焦点距離を一つのカメラの複数のフレームにアニメーションとして納めるスクリプトです。例えば建築のインテリアのCGを作ってて、いろいろな部屋をいろんな構図でイメージしたいって時にたくさんのカメラを作ると思いますが、全部まとめて1アクションでレンダリング出来ます。は?レンダーキューに追加すればいいだけだが?と言われると、はい、そうですねとしか言い様がないんですけど(^^;)それくらい分かってるけど、別の理由があるのだ(意味深)

最後までわからなくて苦労したのが、100行目の

bt = c4d.BaseTime(frame,fps) の行で、当初は

bt = c4d.baseTime(frame) としていたんですが、0フレームの次に30フレームにキーが追加されて、その次は60フレームに追加される始末。

このframeという変数は、最初0で、for文の一通りの処理が終わると、1増えるようになってて(125行目)、この変数frameを使って、0フレーム、1フレーム、2フレーム・・・と、各カメラから取得した値を何フレーム目に書き込んでいくのかということ、つまり今何フレームなのかを保持する役割を持った重要な変数なんです。

間延びして配置されたキーフレーム・・・(笑)

変数frameが1の時は30フレームにキーが作られて、変数frameが2の時は60フレームにキーが作られるのは、BaseTime()自体がドキュメントのFPSである30に影響を受けてるンだなーというのはわかるんだけど、じゃあ、どうすればいいのよ?って数時間苦しんだけど、SDKのBaseTime()のところを見ていると、()の中で , で区切ったりしてるのを発見して、やけくそでBaseTime(frame,fps)としたらうまくいったんだけど、疲れました。

追記 BaseTime(A,B)とあったら、分数の分子がAで分母がBになるとなるようです。つまり、A/Bなんだけど、BaseTime(A/B)と書くとエラーになります。math.ceilを使って切り上げしてもダメで・・・要するに割りたければ , で区切ればいいらしいです。


位置のベクターのX,Y,Z値を個別に取得

2015-04-17 14:50:16 | Python & Cinema4D

GetAbsPos()等で位置を取得すると、vector(634.11, 1172.49, 405.83)と感いうじでXYZが1つに纏めて保持されてまして、一方でアニメーションのトラックは、位置のX,Y,Zがそれぞれ一つのトラックを持つので分かれています。なので、GetAbsPos()のオプションかなんかでXだけ、Yだけ、Zだけと言ったふうに別々に取得する方法があるのかと思ったけど、なさそうなんで、いろいろ考えて・・・SDKにそういう機能が無いってことは、言語側でどうにかするしかないんじゃないかと思って調べたらありました。

タプルってのがそれで、上の画像の71行目~の

71     pos = cameraData.GetAbsPos()
72     # タプルから抽出
73     pos_X = pos[0]
74     pos_Y = pos[1]
75     pos_Z = pos[2]

と言う感じで・・・

GetAbsPos()はvector(Xの値, Yの値, Zの値)という、中をコンマで区切られた()を返すのですが、これはPythonのタプルそのものなので、[]大括弧をつけて中に0を入れると、1番目(一番左、つまりX)の要素だけを返してくれるンですよ奥さん!まぁ素敵ね![1]なら2番目だけを返します。

そしてこれら別々に取り出した値を使ってキーを追加すればいいんだよね・・・(続く)


DescIDって何

2015-04-14 00:01:00 | Python & Cinema4D

アニメーションを作るときってまず、オブジェクトの特定のパラメータにキーを追加しますよね。位置とか角度とか、カメラだったら焦点距離(Focal Length)とか。作業するユーザーからすると、複数の「キー」を補完しつつ繋いだものが「カーブ」で、そのカーブを格納するのが「トラック」なんじゃろうと思ってしまうンだけど、ソフトウェアからすると逆だそうで、「トラック」があって「カーブ」があって「キー」が存在できるンらしいんです。道路があるから車が走れるって感じですかそうですか。

それで、トラックやらカーブを取得するときに必要なのが、DescID (DescriptionID)ってやつで、Descriptionってここでは「説明」って意味だと思うわけで、要するに「僕ちゃんが欲しいのはアレです」って言ってもソフトウェアは分からんから細かく説明しなくてはならないのですね。

トラックを取得するとき、

    track = obj.FindCTrack(c4d.DescID(
                            c4d.DescLevel(c4d.ID_BASEOBJECT_POSITION,c4d.DTYPE_VECTOR,0),
                            c4d.DescLevel(c4d.VECTOR_X,c4d.DTYPE_REAL,0))
                            )

こういう風に書く必要があるんですが、上記は位置のトラックの取得なんだけど、c4d.DescLevelっていう、同じようなのが二つあります。これはDescIDのレベル1と2で、取得されるトラックとの関係は下の図のようになります(多分)。

位置トラックは更に位置のX、位置のY、位置のZに分かれるんで、2段階に分けて、最大3種類書かなくてはならないんですね。角度も角度のX、角度のY、角度のZに分けなくてはなりません。

なんで、そういう細かいことに気付いたかと言うと、SDKでいちいち名前とか調べなくても、画面のパラメータをエクスプレッションエディタに直接ドラッグ&ドロップすればいいよってことで、やってたら、ものによってごちゃごちゃ書かれてたり、単純だったりするわけです。途中でコンマで区切られてたり。

ああ、これがDescIDのレベルの複雑さと関係するんだろうなと思って、「焦点距離」トラックを作ってみると、

「焦点距離」だけで、その下位には何も作られません。やっぱりね。

そして、その「焦点距離」のトラックを取得する際は、

focusTrack = obj.FindCTrack(c4d.DescID(c4d.DescLevel(c4d.CAMERA_FOCUS)))

という風になり、DescIDはレベル1まであればいいので、位置トラックの取得と比べるとずいぶん簡単です。

つづく

※ Cinema4DでPythonスクリプトを勉強するにあたっては、「Cinema4D道場」で「Pythonスクリプト習得」編を購入してがんばってます。何故かリンクが張れない(ブログの編集画面で「不正な書式が~」と出てアップできない)ので、興味がある方は「Cinema4D道場」でググって下さい。

 


Pythonスクリプトサンプル「お寿司会計プログラム」

2015-04-13 17:32:29 | Python & Cinema4D

for文を使って、リストの中のお寿司の金額を足していきます。

7行目の[ ]がリストで、その中の数字が一皿の値段なんです。

で、左から読み込んで足していって、全部足し終わると終わるんです。便利ですね。

自力で書いてはじめて満足したPythonスクリプトがこれとは(泣)

でも結構重要かつ実用的な概念が詰まっているような気も(笑)


Pythonスクリプトの使い方自体を知らなかったけどわかった

2015-04-13 16:48:38 | Python & Cinema4D

Pythonスクリプトの使い方をwebで検索していると、ほとんど必ず「村人とC4D」さんのページが表示されまして、ああ、この方は本当にすごいなあ。と思いつつ、そのサンプルのコードや、PythonSDKや、ネットの他の情報等々を参考になんとか自分の目標を達成しようとしているんですが、出来ません!一度あきらめて(早いか)匙を投げましたが。気を取り直して、じっくり考えていると、「このコードってPythonタグで使うもんなのか??」という疑問が湧きました。というのも、動くとされているコードが動かなくて、仕方なく、わずかな知識で動くように部分的にコードを書き直したりしていたんですが、挙動が根本的におかしい。自分が今悩んでいるのは、オブジェクトにアニメーション用のトラックを追加して、そのトラックにカーブを追加して、キーを追加することなんですが、何かの操作をするたびにドンドン(要するにC4Dのなんかの動作をするたびに)トラックが際限なく追加されていくンです。トラックを追加するのは1回だけでいいんだけど。ボタンなりコマンドなりを一回押して使うんじゃないの??と思ったわけで。

やっぱりそうでした。^^;

まずメインメニューの「スクリプト」から「スクリプトマネージャ」を開いて・・・

スクリプトマネージャにコードを書くなりコピペするなりしたら、スクリプトマネージャのメニューの「ファイル」→「名前を付けて保存」とかで、好きな場所に保存します。

シーンファイルなんかを保存してる近くに「Python」ってフォルダを作ってあるんで、そこに保存しました。

※追記 好きな場所に保存するんじゃなくて、ユーザーの「一般設定」フォルダのlibrary→scriptsの中のほうが良さそうです。というか、基本的に自動でそこに保存されるようです。

 

そうすると、メニューの「スクリプト」→「ユーザースクリプト」から選べるようになってます(自動的に)。

わーい!本当に動いたよ。

ちなみに何度もスクリプトを適用すると、やはり容赦なくトラックが追加されます(笑)

コードは

http://villager-and-c4d.cocolog-nifty.com/blog/2011/05/c4d-python-r1-9.html

からお借りしました。m(__)mありがとうございます。


Pythonスクリプトで複数のオブジェクトのパラメーターを取得

2015-04-11 22:26:24 | Python & Cinema4D

Pythonスクリプトですが、目標に徐々に近づいてきました。

AnimCameraという(適当に名付けた)オブジェクトにくっつけたPythonスクリプトタグが、まずCameraGroupという名前のオブジェクトを検索し、その子オブジェクト(カメラ)の位置と角度とカメラのFocal Length値を取得するというものです。GetChildren()で取得すると、複数のオブジェクトをリスト(配列)で持ってくれるので、for文で一個づつ読み出せるンだね!そんで、それを繰り返せると・・・

俺にでも出来るってスゲーッス!マジ感動。

Pythonってすげー気楽な感じでいいかも。行末にいちいち;を付けなくていいし、ブロックに{ }を使わなくていいし。文字列を挟むのは" " でも' ' でもどっちでもいいとか適当。ブロックはTabで下げてけばいいし。

つづく