そういうわけ、やりたいことがいっぱいありすぎて困ってます。
まず自作の車ゲームであるところのUntenkunをOculusRiftDK2で満喫しようと思ったわけですが、最初はうまく出来ませんでした。ただ単にカメラを差し替えるだけではダメかと思いましたが、別名で保存したシーンで作業してて、ビルド時にそっちを読み込んでないだけでした。早速やってみたけど、すごく酔う。1分保たなかった。死にそう。
そういうわけ、やりたいことがいっぱいありすぎて困ってます。
まず自作の車ゲームであるところのUntenkunをOculusRiftDK2で満喫しようと思ったわけですが、最初はうまく出来ませんでした。ただ単にカメラを差し替えるだけではダメかと思いましたが、別名で保存したシーンで作業してて、ビルド時にそっちを読み込んでないだけでした。早速やってみたけど、すごく酔う。1分保たなかった。死にそう。
そういうわけで、自作のPythonスクリプトは
に置いてあります。よかったらどうぞお試し下さい。
「Ctrl + E」で「一般設定」フォルダを開いて、開いたウィンドウの「一般設定フォルダを開く」ボタンを押し、「library]
→「scripts」の中にスクリプトを保存します。
そしたらスクリプトマネージャを開き、「開く」で開いたウィンドウからAnimCamScript.pyを選んで開いて下さい。そして実行すればいいです。
一回スクリプトマネージャから開くと、次からは「ユーザスクリプト」から選択して実行できるようになるようです。
複数のカメラの位置、角度、焦点距離を一つのカメラのキーフレームに格納します。
CameraGroupという名前(全角ではダメ)のヌルを作って、その中にレンダリングしたいカメラを入れます。
そしてカメラを新規で一個作り、そのカメラを選択した状態でスクリプトを実行します。
なんでこのスクリプトをPythonスクリプトの勉強までして作ったかというと、複数のカメラを一つにまとめて「カメラアニメーションです」ってことにしてしまえば、GIを使ったレンダリングで、GIのキャッシュファイルを複数のカメラで使いまわせるんじゃないかと思ったんです。結論から言うと、うまく出来ているような気がします。ただし、キャッシュファイルを使いまわすためだったら、別にカメラアニメーションにする必要もなかったです。よーく観察すると、フツーにカメラ切り替えても既存のキャッシュを使って綺麗にレンダリングしてるし・・・
※そもそもなんでそんなことを考えたかというと、あるカメラで室内をGIでレンダリングして、その時のGIキャッシュを使って次に違うカメラで違う方向をレンダリングしたら、最初のレンダリング時に写っていた部分は綺麗だけど、写っていなかった部分は汚かったという事があった(これは後で「カスタムサンプル数」にしてサンプル数を増やしたらあっけなく解消しましたが)からです。最初のカメラに写っている範囲しかGIのデータが作られてないの?と思ったわけで。でも複数のカメラをまとめてカメラアニメーションですってことにすれば、全部のフレームで見えている場所はGIの計算をしてくれるだろうと思ったわけ(ライトマップの「カメラパスを使う」ってオプションはまさにそれだと思うんですが)。
しかも!ステージオブジェクトを使うと、同じことが出来ます!
https://www.youtube.com/watch?v=9AHS5y6avSg
とほほ!まぁ勉強になったからいいか(泣)
そういうわけで、スクリプトがやっと満足に動きました。
このスクリプトは後日公開するつもりですが、シーン内に複数あるカメラの位置と角度と焦点距離を一つのカメラの複数のフレームにアニメーションとして納めるスクリプトです。例えば建築のインテリアの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を使って切り上げしてもダメで・・・要するに割りたければ , で区切ればいいらしいです。
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番目だけを返します。
そしてこれら別々に取り出した値を使ってキーを追加すればいいんだよね・・・(続く)
昨日の続きです。
まず、Unitychanは展望台みたいなオブジェクトの上に立っていまして、そこまでOculusRiftDK2を装着して、WASDキーで移動方向をコントロールし、マウスで向きを変えつつ階段を登っていくんです。(全部標準的な機能です)
階段を登ろうとすると引っかかってしまうため、板でコライダーを作って階段の傾斜に合わせて配置します。MeshRendererをOFFにして見えないようにします。これで引っかからずにすいすい登ります。展望台の上には落下防止のため、同じように見えないフェンスを配置します。
ところがいくつかのコライダーに接触すると引っかかってそれ以降移動できなくなりました。試行錯誤した結果、コライダーの向きの問題と分かりました。下の図のようにZ軸が向こうを向くようにすれば大丈夫でした。
カメラはOVRPlayerControllerていうのを使うみたいです。これはOculusのパッケージを読み込むと作られるOVRフォルダの中のPrefabsフォルダの中にあります。
設定項目はOVR PlayerController(Script)の中にあります。
WASDキーでの移動速度はAccelerationで設定します。マウスでの回転速度はRotationAmountで調整します。
RotationAmountは初期設定値よりかなり小さくして、ゆっくりカメラが回転するようにしました。
そういうわけで、3D酔いが怖くて全然触ってなかったOculusRiftDK2ですが、Unity5で作ったシーンにOculusRiftのパッケージを読み込んで使えるようになりました。Unitychanも読み込みました。
酔わないようにするには、時々目をつぶるとか、マウスで急に向きを変えないとか、階段やスロープを登り降りする時はゆっくり動くようにするとかでしょうか。
先月OculusRiftDK2を購入したわけですが、3D酔いがスゲーので触ってませんが、新型が発表されたそうです。Crescent Bayだそうです。
http://pc.watch.impress.co.jp/docs/news/event/20150413_697537.html
フレームレートが上がって、解像度も上がって?、更にスピーカーも付くらしいです。これが製品版のベースになるのかな。
3D酔いが酷いのは、PCのビデオカードの処理能力が低く、フレームレートが稼げないというのが最大の原因のようです。DK2の解像度は両眼合わせて1920×1080らしいので、その解像度で75FPS以上を常時維持するとなると、今買うなら、なるべく低消費電力なほうがいいからGeForce GTX 960搭載カードでしょうか。しかし3万円前後だからなー。
アニメーションを作るときってまず、オブジェクトの特定のパラメータにキーを追加しますよね。位置とか角度とか、カメラだったら焦点距離(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道場」でググって下さい。
for文を使って、リストの中のお寿司の金額を足していきます。
7行目の[ ]がリストで、その中の数字が一皿の値段なんです。
で、左から読み込んで足していって、全部足し終わると終わるんです。便利ですね。
自力で書いてはじめて満足したPythonスクリプトがこれとは(泣)
でも結構重要かつ実用的な概念が詰まっているような気も(笑)
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ありがとうございます。