2016-02-10

PrefとPworldからデフォームアニメーションするジオメトリの特定の点の座標を求める(ただしそれは、画面上に常に見えている)

デフォームアニメーションしているジオメトリの特定の点の座標をPrefとPworldから求める方法をきかれたので、ココにメモしておきます。まぁまぁニッチです。
ちなみに、mayaでPoint Constraint(Point on Poly)でやるのが一番よさそうです・・・
ただ、PrefとPworldからそれが出来ると、ディスプレイスメントが施されてレンダリングされたものでも求めることができるってメリットがあります。

PworldとPrefが下の感じです。


Pworld
Pref

Prefはデフォームしているジオメトリでもreference poseでのpworldが出力される優れものです。Vray, mtoa, RISだとデフォルトで出力可能なAOVです。他のレンダラは調べてないので、ちょっと分かりません・・・

まずは、Prefをつかって、特定の点がスクリーン座標上でどこを通るか求めます。
Prefのカラーはジオメトリにへばりついているので、特定の点はPref上では、常に同じRGB値になります。ここではそれが、(0.49121, 10.54687,1.92187) だったとします。
そうすると、この点から、Pref上の各ピクセル(rgb)までの距離は

√((r - 0.49121)^2 + (g - 10.54687)^2 + (b - 1.92187)^2)

となります。これをExpressionノードで再現すると・・・



こんな感じです。
ちなみに、


分かりやすく色つけてます


とちゃんと同じ点にへばりついてるのが確認出来ます。
使いづらいので、これを1からマイナスしてクランプしました。


Rチャンネルのみ表示の結果

これをCurveToolを使って明るさが最大値のピクセルを追いかけます。
上で述べた「まずは、Prefをつかって、特定の点がスクリーン座標上でどこを通るか求めます」に当たります。
さっきのExpressionノードではRチャンネルのみをしょりしたので、shuffleとか使って、全部完全に白黒画像にしています。r r rです。




こんな感じで、CurveTool加えて、Max Luma Pixel で [Go!] です。
そうすると、



こんなです。

これで、ジオメトリ上の特定の点がスクリーン座標上のどこを通ったかが分かったので、この2D座標をつかって、Pworldのカラー(rgb)をサンプルすると、そのrgb値がそのまま、その特定の点が通る(x,y,z)となります。
サンプルする方法は、tclの

[sample node channel x y]

 を用いるか、pythonの

nuke.sample(node, 'channel', x, y)

になります。簡単なのは、Axisだしてtclでtranslateに上のエクスプレションをはれば一応にくるんですが、nukeはこの手のエクスプレッションを毎フレーム評価するのが結構苦手です。
なので、そういう場合は毎フレーム計算実行するノードでかつpythonタブのついているもので、そのpython使って毎フレームAxisノードに座標をsetValueしていくのが回避策とされてます。CurveToolハックと呼ばれる手法です。

CurveToolが2回でてきているのでややこしいですが、今回のはpythonを毎フレーム実行してAxisノードのtranslateにsetValueするためのモノです。

Axisノードと新たに、CurveToolを作って、




CurveToolのpythonタブの[before each frame]にAxis2のtranslateに、Pworldの特定の点をsampleして得た値をsetValueするようなpythonを書きます。

nuke.toNode("Axis2")['translate'].setValue([r,g,b])

って具合です。[r,g,b]のところはコードが長いので、下記のように展開します。
[r,g,b] のところはたとえば実際にはrを書いてみると・・・

nuke.sample(nuke.toNode(Read4"), "Pworld.red", parent.CurveTool2.maxlumapixdata.x, parent.CurveTool2.maxlumapixdata.y)

この場合だと、nuke.toNode(Read4"), "Pworld.red" の代わりに、Shuffle17を使って、

nuke.sample(nuke.toNode("Shuffle17"), "red", parent.CurveTool2.maxlumapixdata.x, parent.CurveTool2.maxlumapixdata.y)

でも可能です。チャンネルは""でくるむ必要があるので注意を。rgbaは省略できます。

これをあとg,b分かいて、[]でくるんで、setValue()の中に入れます。
また、Axis2のtranslateには、アニメーションさせるため予め適当なフレームで「空(から)キーフレーム」を打っておきます。

これで、CurveTool3の[Go!]すると、



ってな感じでAxisのtranslateで特定の点の座標を得ることができます。

実際には、こんなこと毎回するの面倒なので、ツール化するのが良いと思います。
これらをひとまとまりでやると、他では使えないツールになるので、前半と後半と分けてツールにするのが良いかと。実際ボクは前半部分はツール化したものを割と使っています。後半は、結構ニッチなのと、mayaから持って来た方が確実なので、そこまでやったことは無かったです:)