はじめまして、開発室の山口です。
DFにはデザイナーとして入社し、4ヶ月ほど前に開発室へ異動しました。
デザイナーのころにNukeを触っていたのと、最近DFで導入したのをきっかけに
現在はNukeの開発を担当しています。
今回はNukeのターミナルモードを使用した簡易ツールを紹介したいと思います。
ターミナルモードとは?
ターミナルモードとは、GUIを立ち上げず、pythonコマンドを駆使してnukeを動かすモードの事です。
このターミナルモードを使う事で、GUIを立ち上げずにNukeファイルを作成したり編集したりすることが出来ます。
簡単に操作してみましょう。コマンドプロンプトを立ち上げ下記のコマンドを入力します。
[code]"C:\Program Files\Nuke7.0v1\Nuke7.0.exe" -t[/code]
※Nuke.exeファイルのパスはPCの環境に合わせて書き変えてください。
コマンドプロンプト上ではこんな感じです。
![batImages011]()
これでNukeをUI無しで立ち上げた状態になり、Pythonで操作できるようになりました。
ためしにReadノードとWriteノードを作成し、保存してみます。
下記のコマンドをコマンドプロンプトに一行ずつ実行してください。
Nukeファイルは自分の好きなところに保存してください。
[python]
nuke.createNode(‘Read’)
nuke.createNode(‘Write’)
nuke.scriptSave(‘D:/render.nk’)
[/python]
ちなみにコマンドプロンプトで全て実行すると、こんな感じになります。
![batImages031]()
確認のため保存されたNukeファイルを開いてみてください。
下図のようにReadノードとWriteノードが作成されれば成功です。
![Nuke01]()
このようにターミナルモードを使用すると,Pythonを使ってUIを立ち上げずにNukeファイルを構築することができます。
ターミナルモードを使って画像変換
ここまでで、ターミナルモードがどんなものか大体理解できたかと思います。
そこで今回はこのターミナルモードを使用し、画像ファイルをOpenExrファイルの圧縮形式Zip scanline 1へ
変換するツールを紹介したいと思います。
●なぜこのようなツールが必要か
NukeでOpenExrファイルを使う際にはZip scanline 1の圧縮形式が相性がよく
他のものと比べてもプレビュースピードが速いのですが、レンダラーによってはZip scanline 1で
出力できないものがあります。
例えばMayaのmentalrayでもZipは選択できますが、この圧縮形式はZip scanlines 16という形式で
Zip scanline 1ではありません。ですのでプレビュースピードを早くするためには、変換してあげる必要があります。
ちなみに現在弊社ではレンダリングにVrayを使用しているのですが、Vrayではscanline 1と
scanlines 16の両方が選べるので、変換の必要はありません。
●ではさっそくツールを作ってみましょう
今回紹介する方法は、ターミナルモードでPythonコマンドを入力するものではなく、外部のPythonファイルで
あらかじめコマンドを作成したものを読み込み使用する方法をとります。
1.適当な場所に変換用のPythonファイルを作成します。
まず適当な場所にPythonファイルを作成します。
D:\exr2zipScan1.py
Pythonファイルの中に以下を記述して下さい。
[python]
# -*- coding: utf-8 -*-
import os
import sys
import nuke
# フォルダのパスを取得
dirPath = sys.argv[1]
# フォルダからReadノードを作成
nuke.tcl(‘drop’, dirPath)
# 作成されたReadノードを取得
readNode = nuke.selectedNode()
# Readノードが作成されていれば次に進む
if readNode > 0:
# 作成されたReadノードからスタートフレームとラストフレームを取得
firstFrame = readNode['first'].value()
lastFrame = readNode['last'].value()
# 作成されたReadノードからファイルパスを取得し,書き出し用のファイルパスを作成
readFilePath = readNode['file'].value()
folderName = readFilePath.rsplit(‘/’,1)[0] + ‘_scan1′
saveName = readFilePath.rsplit(‘/’,1)[1].rsplit(‘.’,1)[0] + ‘.exr’
# フォルダを保存するためのフォルダの作成。すでにあれば作成しない
if not os.path.exists(folderName):
os.mkdir(folderName)
# Writeノードを作成し、書き出し用のファイルパスを入力
writeNode = nuke.createNode(‘Write’)
writeNode['file'].setValue(folderName + ‘/’ + saveName)
# ファイルタイプをexr、圧縮タイプをZip scanline 1 へ変換
writeNode['file_type'].setValue(‘exr’)
writeNode['compression'].setValue(‘Zip (1 scanline)’)
# Writeノードをレンダリング
nuke.execute(writeNode, firstFrame, lastFrame)
[/python]
2.Pythonファイルを実行するためのバッチファイルを作成します
ツールっぽくするためにPythonファイルと同階層にバッチファイルを作成します。
D:\exr2zipScan1.bat
バッチファイルの中身はこんな感じです
[code]"C:\Program Files\Nuke7.0v1\Nuke7.0.exe" -t "D:\exr2zipScan1.py" %1[/code]
これで変換したい連番が入ったフォルダをドラッグ&ドロップすることでツールが起動し
exrのZip scanline 1へ変換されるようになります。
ためしに連番の入ったフォルダをバッチファイルにドラッグしてみてください。
![dragImages01]()
どうでしょうか、下図のようにtest_scan1ディレクトリが作られ
画像ファイルが無事変換できていれば完成です。
![doragImage02]()
次に中で何が行われているのか説明します。
バッチファイルの解説
まずは、バッチファイルから説明します。
[code]"C:\Program Files\Nuke7.0v1\Nuke7.0.exe" -t "D:\exr2zipScan1.py" %1[/code]
1.EXEファイルを指定します
“C:\Program Files\Nuke7.0v1\Nuke7.0.exe” -t
上記で説明したように、Nukeをターミナルモードで立ち上げるためのコマンドです。
2.Pythonファイルを指定します
D:\exr2zipScan1.py
-t フラグの後ろにPythonファイルのパスを記述することで、Nukeをターミナルモードで立ち上げた後に
Pythonファイルが実行されます。
※下記のように記述すると相対パスで記述できます。バッチファイルと同階層にある場合に使用してください。
%~dp0exr2zipScan1.py
[例]
[code]"C:\Program Files\Nuke7.0v1\Nuke7.0.exe" -t "%~dp0exr2zipScan1.py" %1[/code]
3.ドラッグファイルのパスをPythonファイルに受け渡す
%1
Pythonファイルの次に%1を記述する事で、バッチファイルにドラッグ&ドラッグしたフォルダの
パスをPythonファイルに受け渡すことが出来ます。他にも渡したい情報があればスペースを入れて追加します。
Pythonファイルの解説
1.最初にモジュールをインポートします
[python]
# -*- coding: utf-8 -*-
import os
import sys
import nuke
[/python]
2.バッチファイルから情報を受け取ります
バッチファイルからドラッグ&ドロップされたフォルダのパスを受け取ります。
ここで気をつけなければいけないのが変数の”0番目”にはPythonファイル自身のパスが
入っていることです。したがって素材フォルダのパスは”1番目”に受け渡されます。
[python]
dirPath = sys.argv[1]
[/python]
sys.argv[0] ← pythonファイルのパスが入っています
sys.argv[1] ← 素材フォルダのパスが入っています
これでdirPathの中にフォルダのパスが受け渡されました。
3.フォルダパスからReadノードを作成
フォルダのパスからReadノードを作成します。
[python]
nuke.tcl(‘drop’, dirPath)
[/python]
※このコマンドはフォルダをNuke内にドラッグしたのと同じ操作になります。
フォルダの中に複数のシーケンスが入っている場合はReadノードが複数できてしまうので
注意してください。
4.選択されているReadノードを変数に代入、無事取得できれば次へ
ノードを作成すると、作成後に自動的に選択されるので、この特性を利用して作成したReadノードを取得します。
またif文を使用し選択されたReadノードが選択されている場合にのみツールが走るようにします。
[python]
readNode = nuke.selectedNode()
if readNode > 0:
[/python]
5.作成されたReadノードからスタートフレームとラストフレームを取得
“3″の操作でReadノードを作成すると、スタートフレーム、ラストフレームに連番から取得されたフレームレンジが
設定されるので、これを利用してレンダリングのフレームを取得します。
[python]
firstFrame = readNode['first'].value()
lastFrame = readNode['last'].value()
[/python]
6.Readノードのファイルパスから書き出しようのファイルパスを作成し、フォルダを作成します
現在Readノードには、ドラッグしたフォルダに入っていた連番のパスが入力されているので
ここから、レンダリングするためのフォルダパスと、連番の名前を作成します。
[python]
readFilePath = readNode['file'].value()
folderName = readFilePath.rsplit(‘/’,1)[0] + ‘_scan1′
saveName = readFilePath.rsplit(‘/’,1)[1].rsplit(‘.’,1)[0] + ‘.exr’
[/python]
例)上の変数にはこんな感じで代入されています。
readFilePath → D:/test/test.%04d.tif
folderName → D:/test_scan1
saveName → test.%04d.exr
Nukeで連番を書き出す際にはフォルダが無いとエラーになってしまうので出力先のフォルダを作成します。
ただし、すでにフォルダがあるとエラーになってしまうので、念のためif文を使用して、重複を避けます。
[python]
if not os.path.exists(folderName):
os.mkdir(folderName)
[/python]
こんな感じでレンダリングのフォルダが作成されます。
![doragImage02]()
7.Writeノードを作成し、書き出し用のファイルパスを入力
この時点ではReadノードが選択された状態ですので、Writeノードを作成すると
自動的にReadノードとコネクトされます。つづけてWriteノードへ出力パスを入力します。
[python]
writeNode = nuke.createNode(‘Write’)
writeNode['file'].setValue(folderName + ‘/’ + saveName)
[/python]
8.Writeノードのファイル形式をexr、圧縮形式をZip scanline 1 へ設定
[python]
writeNode['file_type'].setValue(‘exr’)
writeNode['compression'].setValue(‘Zip (1 scanline)’)
[/python]
※実はファイル形式をexrへ設定すると、圧縮形式はデフォルトでZip scanline 1へ設定されるので
二行目は必要ありません。ここでは分かりやすくするために記述しています。
9.Writeノードをレンダリング
作成したWriteノードに”5″の工程で取得したスタートフレームとラストフレームを設定してレンダリングします。
[python]
nuke.execute(writeNode, firstFrame, lastFrame)
[/python]
以上でツールの説明は終わりです。
その他の小ネタ
●Nukeファイルをターミナルモードで開いて変更する
ターミナルモード + PythonはNukeファイルに対しても有効です。
これを利用すると、Nukeファイルに対してPythonを実行できるので、複数のカットに対しPythonで一定の処理を
加えたいときには有効です。
記述方法はこんな感じ。
[code]"C:\Program Files\Nuke7.0v1\Nuke7.0.exe" -t "D:\testPython.py" "D:\testScene.nk"[/code]
Pythonに何かの値を受け渡したい場合はPythonファイルの後ろにスペースを入れて入力します。
最後に
初めてのDFtalkの記事ということもあって、初歩的な部分も多かったですが
最後まで読んでいただいてありがとうございます。
実はこれマニュアルに似たような例が乗ってたりするんですよね。記事を書き終えてから
気付いてしまい、あっ!っと思ったのですがもう遅かったです。
内容的には違う部分もあるので、見比べてみて何かのヒントにしていただければ幸いです。
やっぱりマニュアルは最後まで読まないといけないですねヾ(_ _*)ハンセイ・・・
次は、もうちょっと専門的なことを書けるように頑張ります。