2014-11-03

ColorMatrix

ColorMatrixノードはピクセルのrgb値に対して指定したmatrixを掛けてくれるものだ。
たとえば、world spaceのnormalパスがあるとして、これをcamera spaceのnormalパスに変換したい場合、world spaceのnormalにカメラの回転マトリクスの逆行列をかければいい。

CameraMatrix allow us to multiply a "matrix" by the value of rgb.
For example, here is kinda normal pass which was rendered in CG as normal in world space, and then we will convert it to one in camera space. How? We can do this with multiplication the value of rgb of normal in world space and the inverse matrix which is "rotation matrix" of camera.






また、カメラの回転マトリクスは、カメラのスケールが(1,1,1)であれば、"Camera"ノードのworld matrixの((0,1,2),  (4,5,6), (8,9,10)) として得ることができる。

Well, when scale of Camera node is (1, 1, 1), you can handle as the world matrix of Camera node as the "rotation matrix" of camera. Actually it should be in m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9] and m[10].



なので、これをColorMatrixノードに代入する。逆行列ってのはこのColorMatrixのinverseにチェックをいれればOKです。

And then, put them in ColorMatrix node. Because we use it as inverse matrix, just check "inverse" box.




その後、このColorMatrixノードをworld spaceのnormalパスにつなげると

After that, we connect the input of this ColorMatrix to the Read node which has normal pass in world space......





normal pass(world space) > normal pass(camera space) の変換ができる。
逆に、camera space を world space に変えたい場合は、inverseのチェックをはずせばいい。

And We can get the normal pass in camera space!
In case that camera space one would be converted to world space one, we don't need to check "inverse" box.




この方法で、normal pass の回転も可能です。

You can rotate your normal pass in this way.

pyAlembic

You can find pyAlembic for windows in the following link.

http://pyalembic.sourceforge.net/
http://sourceforge.net/projects/pyalembic/files/


Actually in my Environment,

AlembicPyIex.dll
AlembicPyImath.dll
awBoost_python-1_52.dll

alembic.pyd
iex.pyd
imath.pyd

I have these files in the folder which is contained in result of "nuke.pluginPath()"



2014-10-22

matrix


matrixに値を入れたいとき、
node['matrix'].setValueAt(value, frame, index) 
matrixの値を取得したいとき、
node['matrix'].getValueAt(frame)[index]



When you want to set the value into matrix,
node['matrix'].setValueAt(value, frame, index) 
When you want to get the value of matrix,
node['matrix'].getValueAt(frame)[index]


2014-10-15

ノードグラフ上でノードを移動するツール

あれ?これって標準であったりする?
ノードグラフ上でグリッドの値だけノードをオフセットするツール。

NodeShift.py
import nuke def shiftHP():     shiftH = nuke.toNode('preferences')['GridWidth'].value()     sn = nuke.selectedNodes()     for n in sn:         posX = n['xpos'].value()         newPosX = posX + shiftH         n['xpos'].setValue(newPosX) def shiftHN():     shiftH = nuke.toNode('preferences')['GridWidth'].value()     sn = nuke.selectedNodes()     for n in sn:         posX = n['xpos'].value()         newPosX = posX - shiftH         n['xpos'].setValue(newPosX) def shiftVP():     shiftV = nuke.toNode('preferences')['GridHeight'].value()     sn = nuke.selectedNodes()     for n in sn:         posY = n['ypos'].value()         newPosY = posY - shiftV         n['ypos'].setValue(newPosY) def shiftVN():     shiftV = nuke.toNode('preferences')['GridHeight'].value()     sn = nuke.selectedNodes()     for n in sn:         posY = n['ypos'].value()         newPosY = posY + shiftV         n['ypos'].setValue(newPosY)


でmenu.pyに

menu.py
import NodeShift m.addCommand("shiftHP", "NodeShift.shiftHP()", "ctrl+shift+Right") m.addCommand("shiftHN", "NodeShift.shiftHN()", "ctrl+shift+Left") m.addCommand("shiftVP", "NodeShift.shiftVP()", "ctrl+shift+Up") m.addCommand("shiftVN", "NodeShift.shiftVN()", "ctrl+shift+Down")

の記述を加えれば。ctrl + shift + カーソルキー(矢印キー)で選んだノードを矢印方向に1グリッドだけ動かせる。複数選択でもOK。

2014-10-09

キーフレームにアクセスする

今回も、果たして誰かの役にたっているのだろうか・・・ というかなり備忘録的なpythonに関してです。

あるattributeにアニメーションがついているとして、そのキーフレームにアクセスして値を取得したり、シフトしたりしたいとします。
たとえばその場合、Transform1ノードのtranslateにx,yについている2個目のキーフレームの値を取得したい場合。



nuke.toNode('Transform1')['translate'].animation(0).keys()[1].y
となり、これが、xのアニメーション( animation(0) )の2個目のキーフレーム( keys()[1] )の値( y ) となります。
また、その2番目のキーフレームが何フレーム目に存在しているかってのは、

nuke.toNode('Transform1')['translate'].animation(0).keys()[1].x

となります。実行すると、そのフレームナンバーが返ってきます。
Graph Editor上でのxとy、つまり時間軸とその値です。

また、そのキーフレームの値を変更する場合は・・・

nuke.animation("Transform1.translate.x" , "x", ("2", "10"))

これで、Transform1 ってノードのattribute "translate.x" ( 位置のx座標 ) をフレームナンバー的( x ) に3個目のキーフレーム ( "2" ) を10フレーム目 ( "10" ) に移動させるといったことになります。

nuke.animation("Transform1.translate.x" , "y", ("2", "-30"))

これで、Transform1 の translate.x の3個目のキーフレームの値を( GraphEditor的にy値を )、-30 にするってことになります。

値を取得する場合は、

animation(i).keys() 

で、値を変更したい場合は、

nuke.animation("ノード名.アトリビュート名" , "コマンド名", (コマンドの種類に応じた引数))

となります。
後者はココが参考になるかと。
http://www.nukepedia.com/python/using-nukeanimation-without-tearing-your-hair-out


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()

だけでよい。