2014-10-03

ディレクトリをOSのファイルブラウザから開く

nukeは、ファイルブラウズにOSのファインダーやエクスプロラーなどといったものを使わずにnuke独自のものを使ってファイルを読み込んだりする。
が、時にこれが不便だったりする。特にReadノードのファイルパスの階層を開きたいとか、同じくWriteノードで指定しているファイルパスの階層にいきたいとか・・・

そんなときに長方するスクリプトです。

dirOpen.py
import nuke
import os
def main():
    sn = nuke.selectedNode()
    fP = sn['file'].value()
    dirP = os.path.dirname(fP)
    dirP = dirP.replace("/", "\\")
    dirP = dirP + "\\"
    
    #print dirP
    os.popen("explorer.exe" + " " + os.path.dirname(dirP))

dirOpen,pyとか適当に名前をつけて保存して、nukeのpluginPathに保存します。
ちなみにmacの場合は・・・

import nuke
import os
def main():
    sn = nuke.selectedNode()
    fP = sn['file'].value()
    dirP = os.path.dirname(fP)
    os.popen("open" + " " + os.path.dirname(dirP))

あとは、menu.pyに登録します。

menu.py
import dirOpen
m = nuke.menu("Nodes")
m.addCommand("dirOpen", "dirOpen.main()", "ctrl+shift+o") 

この場合、ctrl + shift + o ってショートカットを当ててます。
ReadノードやWriteノードを選んで、そのショートカットを実行するとOSのファイルブラウザでその階層が開けます。

2014-10-01

ノードにあるpythonタブの活用 とか諸々

ノードによってはPropertyにPythonタブがあるものがある。
たとえば、Writeノードとか。


ここにpythonを読み込むと、たとえば、Writeノードのファイルパス(指定のファイルパスのフォルダディレクトリ/フォルダ)がなければ、レンダー時にそのディレクトリを作成するといったことも可能だ。
具体的には、まずこのWriteノード( nuke.thisNode() )のファイルパス( ['file'].value() )が、存在しなければ( if not os.path.exists() )そのディレクトリを作成する( os.makedirs() )、って言う具合なpythonを書く。


import os
sn = nuke.thisNode()
fp = sn['file'].value()
dirP = os.path.dirname(fp)

if not os.path.exists(dirP):
    os.makedirs(dirP)

こんな感じ。
これをファンクションとして定義して、.pyで保存する。

makeDir.py
import os
import nuke
def main():
    sn = nuke.thisNode()
    fp = sn['file'].value()
    dirP = os.path.dirname(fp)

    if not os.path.exists(dirP):
        os.makedirs(dirP)


これを、プラグインパスとして読み込むことのできる場所においてやる。
ちなみに、プラグインパス の調べ方は、スクリプトエディタで nuke.pluginPath() とやればOKです。


こんな感じででます。もし、この際あたらしいパスを追加したいって場合は、こちらを参照してください。

ともあれ、その場所に上記 makeDir.py をおいたらWriteノードのPythonタブのbefore renderのところに、



import makeDir;makeDir.main()



という具合に書けば、あとは、Writeノードのファイルパスがなければ、自動的にそのフォルダ構造をつくってくれます。
その一行の中にある ; (セミコロン)は改行をしめしている。
つまり、本当は、



import makeDir
makeDir.main()

って二行を表現している。 プラグインパス内にあるmakeDir.pyを読んできて、そのmakeDir.pyのmain()って関数を実行する makeDir.main() という意味だ。

もどって、Writeノードのファイルパスに適当なパスを入れてみて、


これで、このパスは実際には(このA/B/Cって3つのフォルダが)存在しないのだけど・・・


レンダリングすると、


バージョンアップ(v001→v002)とかだと結構便利に使えます。ファイルパスのバージョンアップには最適です。
ちなみに、/test.v001/test.v001.%04d.exr だとか、/test_v001/test_v001_%04d.exr ってなファイルパスを含むReadノードやWriteノードを選択した状態で、alt+キーボードの矢印の上下(↑↓)で、バージョンを上げ下げできます。

また、こういうのはWriteノード作るたびにPythonタブのところに、上記の一行をいれるのは非常に面倒なので、menu.pyに

nuke.knobDefault("Write.beforeRender", "import makeDir;makeDir.main()")

の一行を書き加えておく。そうすると起動時にWriteノードにデフォルトでクダンの一行が書き加わり、今後新しく作るWriteノードにはその処理がなされる。

ちなみに、WriteノードのPythonタブに書き加えた

import makeDir;makeDir.main()

は二行であらわさないといけないから ; (セミコロン)が入っているが、menu.pyに

import makeDir

の一行がはいっていれば、

makeDir.main()

だけでよい。

2014-09-08

NaN の話

いろいろ作業をしていると[NaN]という数値(?)を持ったピクセルに出くわすことがある。NaN → http://en.wikipedia.org/wiki/NaN



原因はいろいろだけど、expressionなどで 0÷0(0割る0) みたいな計算があるとなるし、一見expression等がなくてもGizmoに含まれていることもある。
これがナカナカ厄介で、これをblurなどのピクセル拡張系のノードで処理すると拡大する。




これを回避する方法がnukepediaにも載っている(http://www.nukepedia.com/expressions/dealing-with-nan-pixels)、この方法だと、広範囲だったり、数ピクセルの間で点在している場合は回避しづらいので、そういう場合はMergeExpressionなどを使って原因となるノードの一つ前のノードをAにコネクトして、



nukepediaでの手法と同じくisnan()関数をもちいて、

isnan(r)?Ar:r

とかやれば回避しやすいです。

2014-09-02

nuke.pluginAddPath

init.pyに


nuke.pluginAddPath(ディレクトリ)


を加えると、その指定したディレクトリのinit.py, menu.py, ToolSetsフォルダを読みにいく。
ちなみに、

nuke.pluginAddPath(./Gizmos)

とかにしておくと、そのinit.pyの存在するディレクトリにあるGizmosフォルダを追加する。

2014-09-01

viewing LUT に cineon を追加する。

init.py に


nuke.ViewerProcess.register("Cineon", nuke.createNode, ("ViewerProcess_1DLUT", "current Cineon"))


を追加。

2014-08-31

Grain

標準のGrainの式は・・・



max(minimum.r,r+(2*Ar-1)*(r*red_m+black.r))

となっており、noise(fBm)で作成されたほぼ0~1までの乱数がスクリーン上に配布されたモノ(Ar)に対して、



(2*Ar-1) とあるので、ここの値はほぼ -1 ~ 1 となる。



さらに、ソースのピクセル値(r)に対して (r*red_m + black.r) とあるので、これはソースのピクセル値(r)にGrainノードのintensityのところの値(red_m)を掛けて、同じくGrainノードのblackのところの値(black.r)を足している。つまり、(r*red_m + black.r)部分はソースのピクセル値(r)もしくはユーザー指定の強度係数(red_m)のどちらかが 0 であれば black.r のみを返す。
で、この(r*red_m + black.r)部分とさっきの画面全体にばらまかれた -1 ~ 1 の係数を掛けたものをソースのピクセル値に足したもの r+(2*Ar-1)*(r*red_m+black.r) とGrainノードのminmumのところで指定した値 (minmum.r)を比べて大きい方を採用するっての言うのがGrainノードのざっくりとした仕組み。



上記の面倒くさいともされる式を念頭において、もっとざっくりと見た目中心でいうと、intensityのところで入れた値を元に、ソースピクセル値から適当な数値を足したり引いたりしているが、ソースイメージの黒に近い暗い部分にはその影響は出ない、もしくはほとんど見えないので、black値でその暗い部分にも影響が出るようにする。



black値の用途を暗い部分への影響という風にとらえると、式から判断するににマイナス数値を入れようがプラス数値を入れようがあまり意味合いは変わらない。(2*Ar-1) が -1 ~ 1 なので。

black値 = 0.06
black値 = -0.06
ただし、



このように、black値 = -0.06 の方には不思議なバンドがでている。これは、

(r*red_m+black.r) の部分の値が 0 付近になるあたりことで、r+(2*Ar-1)*(r*red_m+black.r) が結局ほぼ r (元の値/ソースのピクセル値) になることで出てしまう。black値にマイナス値を入れるとこういうことが起こりうる可能性がある。ちなみに、(r*red_m+black.r) の部分の値が 0 というのは ソースのピクセル値(r)とintensity値(red_m)の乗算した結果がblack値のマイナスをとったものと同じ値にななる場合。

また、intensityに1とかをいれると、ソースピクセル値が0-1に収まっていても、場合によっては2近くの値が出る可能性もあるし、真っ白付近の値なのに、真っ黒付近の値のピクセルが出てしまう可能性もある。

curvetoolで右の白い部分のみで計測

さらに、プレートでの暗部がマイナス値の場合でこの暗部にノイズを入れたい場合にも注意が必要で、

この場合、暗い部分は -0.02

一見、これだけで見ると暗部にノイズが入っているが、オリジナルと比較すると・・・


こんな感じになり、大丈夫そうにも見えるが、viewing lut をcineonにしてみると・・・


明らかな差が見えてくる。
これを解消するために、minmum値に元の暗い部分の値、この場合 -0.02 をいれておくと



こんな感じで回避できる。

2013-01-14

maskのfringeオプション

ノード内にある、maskのfringeオプションを使用可にすると、指定したmaskのエッジにのみその効果が適応されます。
たとえば、グリーンでキーアウトしたんだけど、どうしても半透明部分のエッジにグリーンが残るとか。despillするため、hue correctなどでグリーンをキャンセルしたら、白っぽくなりすぎて、今度は背景色に対して浮いてしまったとか・・・
そういう時、このmaskのfringeオプションをもちいるといい感じにいけたりする場合があります。
適当な素材がないので、この部分の説明は省きますが、原理だけ説明を。


たとえば、真っ白のconstantノードにrampノードでアルファとして幅の少しある白から黒のグラデーションを与えます。




こんな感じです。
アルファを見ると


こんな感じです。
で、ここにcolor correctノードを追加し、maskにアルファを指定してfringeオプションにチェックを入れて、

適当に色をいじります。緑にしてみます。


と、こんな感じになります。アルファの0-1の幅で真ん中ぐらいにcolor correctの効果のピークがきているようです。
実際にカラーピックしてみると、

こんな感じで、0.5のときに、color correctが100%効いてます。

クロマキー等でアルファを作成して、エッジのみを修正したい場合は割りと使えるオプションです。原理がわかれば、アルファにblurを用いてもう少し幅をだすなど、いろいろと利用価値があります。