PythonのmitsubaでRenderJobのエラーを得る
RenderJob
やRenderQueue
辺りを使って多数の画像を複数同時に作れるが、RenderJobはメモリエラーか何かで画像の生成に失敗する時があるらしい。しかしクラス内にエラー処理するリスナーが見当たらない。
RenderJob
→ Mitsuba Renderer: mitsuba::RenderJob Class Reference
あまり良くわかってないけどたぶんRenderQueue内のregisterListener
を使えということなのだろう。
RenderQueue
→ Mitsuba Renderer: mitsuba::RenderQueue Class Reference
RenderListener
というものがあるらしい。数十MBもあるDocumentationのPython integration項目にこれを使ったサンプルはない。2015/09/12現在これがPython対応しているかどうか明記されてない気がするが、なんとかしてみる。
RenderListener
→ Mitsuba Renderer: mitsuba::RenderListener Class Reference
まずRenderListenerの存在を確認する。
from mitsuba.core import * from mitsuba.render import * RenderListener # <class 'mitsuba.render.RenderListener'>
続いてRenderListenerのクラス内メソッドを確認する。
参考: How do I get list of methods in a Python class? - Stack Overflow
inspect.getmembers(RenderListener, predicate=inspect.ismethod) # [('__init__', <unbound method RenderListener.__init__>), # ('__reduce__', <unbound method RenderListener.<unnamed Boost.Python function>>), # ('finishJobEvent', <unbound method RenderListener.finishJobEvent>), # ('refreshEvent', <unbound method RenderListener.refreshEvent>), # ('workBeginEvent', <unbound method RenderListener.workBeginEvent>), # ('workCanceledEvent', <unbound method RenderListener.workCanceledEvent>), # ('workEndEvent', <unbound method RenderListener.workEndEvent>)]
API Reference通りの実装がされていそうだ。とりあえずListenerを継承したクラスを作ってregisterしてみます。
from mitsuba.core import * from mitsuba.render import * queue = RenderQueue() class TestListener(RenderListener): def __init__(self): return testListener = TestListener() queue.registerListener( testListener ) # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # Boost.Python.ArgumentError: Python argument types in # RenderQueue.registerListener(RenderQueue, TestListener) # did not match C++ signature: # registerListener(N7mitsuba11RenderQueueE {lvalue}, PN7mitsuba14RenderListenerE)
oh...なんだこのエラー・・・とりあえずダメ元で全クラスメソッドをそれっぽく実装してみます。
from mitsuba.core import * from mitsuba.render import * queue = RenderQueue() class TestListener(RenderListener): def workBeginEvent (self, job, wu, worker): return def workEndEvent (self, job, wr, cancelled): return def workCanceledEvent (self, job, offset, size): return def refreshEvent (self, job): return def finishJobEvent (self, job, cancelled): return testListener = TestListener() queue.registerListener( testListener )
おっとエラー出ない。素直な実装に感謝しつつ、適当にprint文放り込んでRenderJobを動かしてみます。
import multiprocessing from mitsuba.core import * from mitsuba.render import * # Start up the scheduling system with one worker per local core scheduler = Scheduler.getInstance() for i in range(0, multiprocessing.cpu_count()): scheduler.registerWorker(LocalWorker(i, 'wrk%i' % i)) scheduler.start() queue = RenderQueue() class TestListener(RenderListener): def workBeginEvent (self, job, wu, worker): print 'workBeginEvent' return def workEndEvent (self, job, wr, cancelled): print 'workEndEvent' return def workCanceledEvent (self, job, offset, size): print 'workCanceledEvent' return def refreshEvent (self, job): print 'refreshEvent' return def finishJobEvent (self, job, cancelled): print 'finishJobEvent ' + 'cancelled : ' + str(cancelled) return testListener = TestListener() queue.registerListener( testListener ) pmgr = PluginManager.getInstance() # Create a simple scene containing a sphere sphere = pmgr.createObject(Properties("sphere")) sphere.configure() scene = Scene() scene.addChild(sphere) scene.configure() scene.setDestinationFile('test_file') # Create a render job and insert it into the queue job = RenderJob('myRenderJob', scene, queue) job.start() # Wait for the job to finish queue.waitLeft(0) # workBeginEvent # workBeginEvent # workBeginEvent # workEndEvent # workBeginEvent # ... # workEndEvent # workBeginEvent # workEndEvent # workEndEvent # workEndEvent # Rendering: [++++++++++++++++++++++++++++++++++++++++++++] (0.5s, ETA: -0.0s) # workEndEvent # INFO myRenderJob[RenderJob] Render time: 0.5410s # INFO myRenderJob[HDRFilm] Writing image to "test_file.exr" .. # finishJobEvent cancelled : False
たぶんRenderJob
がエラーでとまった時は、finishJobEvent
のcancelled
がTrue
になるんだと思います(未確認)