2010-03-20

Nuke 3DComposit

基本的なことばかりやっていたので、「Nukeって結局何にも出来ないのね・・・」と思われてもアレなので、少し複雑なことを。ただし最初に断っておきます、今回は「コレって意味あるの?」的なことです。


でも小技を幾つかちりばめてます。

Nukeの強みである3DCompositを行ってみようと思う。
で、3DCompositってどういう利点があるかと訊かれたら、Projectionが一番の利点じゃないかなぁ~と思う。リライティングのようなこともできるけど、現状Nukeで準備されているシェーダーなどは、凄く強力とは言いがたく、標準のモノだと「ハイライトを入れる」程度のこと止まりになってしまう。MergeExpressionで画像演算を行えばもっと細かく出来るだろうというのは分かってるのだけど、それ以上はボク自身の知識では・・・ "katana"に期待といったところでしょうか。

3DCompositは通常、CameraNode、SceneNode、ScanlineRenderNodeそしてオブジェクト(ジオメトリ)のノードとBGイメージがあれば組む事ができる。



基本的にはCameraNodeとオブジェクト、場合によってはLightNodeなどをSceneNodeにコネクトして、SceneNodeからScanlineRenderNodeへコネクトする。そして、画像を生成したいカメラをScanlineRenderNodeにコネクトする。



ちなみに、オブジェクトが一つの場合はSceneNodeを介さず、直接ScanlineRenderNodeでまとめても可能である。あとは、ScanlineRenderNodeにBGイメージをコネクトすればOK。

[tab]キーで切り替え

さらに、[tab]キーを押すとViewerを3D view、2D viewと切り替えることができる。

今回は3dsmaxから  Nuke'Em というスクリプトを使って.nk(Nukeのファイル)を出力している。色々と試したけど、これが一番楽チンでした。で、コレを使って出力したファイルをNukeで開くと、このシーンの場合、カメラとオブジェクトが既に作成されているのが確認できる。


オブジェクト、この場合teapotと床オブジェクトなのですが、それらはReadGeoNode→TransformGeoという構成になっています。そして、ConstantNode(AEでいうところの平面)で色を指定しています。UVが存在していて、ConstantNodeのかわりにReadNodeをもちいれば、その画像をテクスチャマッピングすることができます。また、この場合ReadGeoNodeで.objファイルを読み込んで、TransformGeoで.chanファイル(Nukeで読めるSTR情報)が読み込まれています。



Nuke'Emをつかうとここまでが自動的に作成されています(.chanファイルも読み込まれキーフレームがついている)。

小技なのですが、外部から読み込むファイルは.nkの保存先より下の階層であれば、.nkの保存先のファイルディレクトリを [file dirname [value root.name]] というもので置き換えることができ、ディレクトリ構造を一緒にしてとやれば、別の場所で作業しても問題ありません。これは、たとえば、ローカルで作業して、ネットワークレンダリングをかける場合などに役立ちます。



ちなみに3dsmaxでそのシーンをレンダリングすると


こんなです。

で、このムービーをNuke上で再現したシーンに投影してみることにします。使用するノードはProject3DNodeです。プロジェクションだとかプロジェクションマップだとかカメラマップと呼ばれるものと大体同じです。
手順は、今ConstantNodeでテクスチャを指定しているところにProject3Dで置き換えます。Project3Dには投影するテクスチャをしているimgのinと、投影するカメラをしてするcamのinがあります。


左がScanlineRenderNodeで生成される画、こんな感じで当たり前だけど同じ結果になります。
右が3Dviewでみたシーンの様子です。カメラから外れると、こんな感じでクリッピングされてます。



で、物凄く出来るケースは少ないですが、コレをカメラパスを変えてみようと思います。
実際にはオブジェクトの形状などでバレなどが生じるので、あまり実用的ではありません。ただ、色々と小技を習得するには丁度だと思います。
原理としては、CameraAでオブジェクトに投影し、それをCameraBで撮影するといった感じです。
新たにCameraNodeを追加してそれをCameraBとしています。CameraAとCameraBの差位がおおきくなるほどバレが生じて破綻するので、バレが生じない、もしくは目立たない程度に動きを変更しようと思います。




まずは、一旦CameraAの動きをCameraBにExpressionで関連付けてます。「ショートカット」の記事にも書いていますように、関連付けはCameraAの各パラメーターのボックスフィールドから関連付けたい先にctrlを押しながらドラッグ&ドロップです。ちなみにボックスフィールド上で[=]キー(イコールキー)を押すと、関連付けられたExpressionを確認することができます。





これだけだとCameraBは常にCameraAと同じ動きになるので、さらにノードを追加してCamereAのカメラパスから離れるようにします。そのためにまずはAxisNodeを追加して、このAxisNode(Axis1)のpivotをCamereAのtranslateとリンクさせます。これはさっきの手順と同じ(ctrlを押しながらドラッグ&ドロップ)。関連付けが行われると図のように緑のラインが引かれ、参照先が分かるようになります。




これで現状CamereAとCameraBとAxis1が同じ位置にいることになります。ここでCameraBはCamereAの位置と回転を基準として、Axis1の移動回転分だけオフセットされるようにExpressionに記述を足します。たとえばAxis1の位置のx座標の値は「parent.CameraA.translate.main.x + parent.Axis1.translate.main.x」であらわされます。
CameraAの位置のx座標(CameraA.translate.main.x)にAxis1のオフセット分である位置のx座標(Axis1.translate.main.x)を足しています。Axis1はpivotでCameraAの位置を指定しているので、Axis1のtranslateの値はCameraAからのオフセット分になります。
ParentでなくKnobというのもあるのですが、それはどうやら明示的に宣言したパラメーター名でないとダメみたいです。このあたり詳しくなくて・・・


でさらに欲ばって、カメラパスのアニメーションカーブにタイムリマップのようなものを引っ掛けたいと思います。CameraAに新たなアトリビュートを設けます。CameraAのプロパティーの何処でもいいので、右クリックで「Manage User Knobs」とし、「add」で「Floating Point Slider」を選びます。nameとlabelは適当にframeとしておきます。ココでタイムリマップのカーブを制御します。








すると、float の数値の扱えるアトリビュートがUserタブに追加されます。


さらに、たとえばCameraAのtranslate xなどのキーフレームが打たれているパラメーターを[=]キーでExpression エディターで見てみると・・・「curve」となっています。




おそらく現在付いているキーフレームのカーブを参照しているということでしょう(当たり前ですが・・・)。さらにcurve(n) (nは数字)とすると、そのカーブでのnフレーム目の値を返してくれます。




とココまで書けば、もうお分かりでしょうが、さっき追加したuser knob(さっき追加したアトリビュート)にこいつを引っ掛けます。




記述は「curve(knob.frame.main)」となります。これで、このuser knobでCameraAのキーフレームアニメーションをタイムリマップできます。「frame」の方にもキーフレームを打ってアニメーションをつける必要があります。




さらに、そのタイムリマップをプロジェクション側にも反映させる必要があるので、CG側からのレンダリング画像のReadNodeとProject3DNodeの間にTimeWarpNodeを加えます。そしてそのTimeWarpNodeの「input frame」に、同じくさっきのuser knobを引っ掛けます。これで、CameraAのアニメーションとCameraAから投影される画像がリンクされます。




で、user knobによるタイムリマップとAxis1によるカメラパスの変更を利用して、カメラの動きを変えました。キーフレームはtranslate.xやuser knobのframe のボックスフィールド上で右クリックしてSet Keyです。大体のCGアプリケーションと同じで一つキーフレームが打たれると、あとは変更するたびにキーフレームが打たれていきます。適当に「Curve Editor」などで編集します。









最後に床オブジェクトがなくなってしまったので、影を加えることにします。Nukeは標準機能では影が落とせない(はず)です。フリーのプラグインで出来たと思いますが、今回折角プロジェクションをやったので、それを使って擬似的な影を落とそうと思います。


原理は光源となる方向にカメラを置き、床を白、teapotを黒にし、そのカメラとScanlineRenderNodeで得れる画像を、そのカメラから床にプロジェクションするといった手法です。




周りくどいですが、やってみればやってることはいたって単純。ただのShadowMap的なことだと思います。





適度にぼかしてやればOK








エッジが目立っているのは、レンダリングをケチってアンチを落としている所為です・・・

と長々と書いたけど。ちょっと説明雑ですね・・・ 特に最後が乱暴すぎる。 ごめんなさい。
小技は随所にちりばめております。使えるかどうかは知りません!

No comments:

Post a Comment