Cinema Freezes while rendering
-
On 14/03/2013 at 10:00, xxxxxxxx wrote:
Hey everyone,
Sorry for bothering you all so soon again, but i have some code in a python plugin, that starts several renders, and while it renders, cinema freezes. It doesn't become unresponsive per say, i just can't do anything until the rendering of the sequence is finished. If you have a scene rendering for like 15 mins or a sequence/animation, you have to wait forever. Is there a way to keep that from happening?
My code looks like this:
def renderDocument(self, layerName) : """ Taking the document and rendering it according to the normal rendersettings of the document. Ads '_LAYERNAME', LAYERNAME being the name of the layer, to the renderpath. """ doc = c4d.documents.GetActiveDocument() renderData = doc.GetActiveRenderData() xResolution = int(round(renderData[c4d.RDATA_XRES])) yResolution = int(round(renderData[c4d.RDATA_YRES])) pathChange = False if renderData[c4d.RDATA_PATH] != "": storedPath = renderData[c4d.RDATA_PATH] renderData[c4d.RDATA_PATH] =r'{0}_{1}'.format(renderData[c4d.RDATA_PATH], layerName) c4d.EventAdd() pathChange = True renderBmp = c4d.bitmaps.BaseBitmap() renderBmp.Init(x=xResolution, y=yResolution, depth=32, ) result = documents.RenderDocument(doc, renderData.GetData(), renderBmp, c4d.RENDERFLAGS_EXTERNAL) if pathChange == True: renderData[c4d.RDATA_PATH] = storedPath if result==c4d.RENDERRESULT_OK: c4d.bitmaps.ShowBitmap(renderBmp) # show image in pictureViewer return True
How could i tackle that?
Or is there even a way to create custom layers (like for example ao pass, just with custom content?), so that i could render everxthing at once?Thanks in advance
Aurel
-
On 14/03/2013 at 10:22, xxxxxxxx wrote:
You can execute your code in a threaded environment. Just Google for threads in Python. There's
a built-in threading facility in Python, but in this case it makes much sense to use Cinema 4D's
threading interface, since you can pass the thread-object to the RenderDocument() function and it
will allow you to interrupt rendering (when I understood it correctly).See the c4d.threading.C4DThread class.
I can show you an example when I find the time.
Best,
-Niklas -
On 15/03/2013 at 00:36, xxxxxxxx wrote:
I will google that, an example would be much appreciated though!
Aurel
-
On 15/03/2013 at 00:52, xxxxxxxx wrote:
To clarify:
I don't want to interrupt the render, i just want to let it render (preferably in the picture viewer as usual) and work on the scene at the same time. So that i can see the image as it's being rendered, so that a folder appears for an image sequence in the pictureViewer, and all the images appear in it.
Thanks
Aurel -
On 15/03/2013 at 02:02, xxxxxxxx wrote:
I read the sdk docs on threading, and i did the following:
I pasted the 'rendercode' into the main method of the C4DThread class:
class RenderThread(C4DThread) : def Main(self) : doc = c4d.documents.GetActiveDocument() renderData = doc.GetActiveRenderData() xResolution = int(round(renderData[c4d.RDATA_XRES])) yResolution = int(round(renderData[c4d.RDATA_YRES])) pathChange = False if renderData[c4d.RDATA_PATH] != "": storedPath = renderData[c4d.RDATA_PATH] renderData[c4d.RDATA_PATH] =r'{0}_{1}'.format(renderData[c4d.RDATA_PATH], layerName) c4d.EventAdd() pathChange = True renderBmp = c4d.bitmaps.BaseBitmap() renderBmp.Init(x=xResolution, y=yResolution, depth=32, ) result = documents.RenderDocument(doc, renderData.GetData(), renderBmp, c4d.RENDERFLAGS_EXTERNAL) if pathChange == True: renderData[c4d.RDATA_PATH] = storedPath if result==c4d.RENDERRESULT_OK: c4d.bitmaps.ShowBitmap(renderBmp) # show image in pictureViewer return True
then, in the renderDocument Method, i do the following:
def renderDocument(self, layerName) : """ Taking the document and rendering it according to the normal rendersettings of the document. Ads '_LAYERNAME', LAYERNAME being the name of the layer, to the renderpath. """ renderThread = RenderThread() renderThread.Start() return True
All i get from that is 3 TypeErrors:
TypeError: thread object is dead
TypeError: thread object is dead
TypeError: thread object is deadAnd thats it.
I am btw. aware of the fact that i should pass in layerName into the Main method, but Main() is always being called with only one argument, so don't know what to do about that. But that's for later, when the thread object doesn't just die on me all the time anymore
Help is always much appreciated,
Aurel
-
On 15/03/2013 at 05:52, xxxxxxxx wrote:
Hi Amadeo,
you must keep a reference to the thread, it will be garbage collected otherwise.
thread = RenderThread() thread.Start() # ... do some stuff # wait for the thread to finish. thread.Wait(False)
This is why threading is not (easily) done in a Script. When using a dialog or command-data plugin,
you can store the script in your plugin sub-class.class Command(c4d.plugins.CommandData) : thread = None def Execute(self, doc) : if self.thread and not self.thread.IsRunning() : # Thread is already/still running, what do you want to do # in this case? pass else: self.thread = RenderThread() return True
For the layerName: You can pass it on construction.
class RenderThread(c4d.threading.C4DThread) : def __init__(self, layerName) : super(RenderThread, self).__init__() self.layerName = layerName def Main(self) : # ... pass # ... thread = RenderThread(layerName)
Best,
-Niklas -
On 15/03/2013 at 08:58, xxxxxxxx wrote:
Hey NiklasR,
Thanks for the examples! I'm not really sure about the second example:
class Command(c4d.plugins.CommandData) : thread = None def Execute(self, doc) : if self.thread and not self.thread.IsRunning() : # Thread is already/still running, what do you want to do # in this case? pass else: self.thread = RenderThread() return True
Especially since i have an ObjectData Plugin - is that a problem?
I was able to get the threading working, but it doesn't really make a difference, cinema still freezes until the renders are done - I set it up like this:
class RenderThread(C4DThread) : def __init__(self, layerName) : super(RenderThread, self).__init__() self.layerName = layerName def Main(self) : doc = c4d.documents.GetActiveDocument() renderData = doc.GetActiveRenderData() xResolution = int(round(renderData[c4d.RDATA_XRES])) yResolution = int(round(renderData[c4d.RDATA_YRES])) pathChange = False if renderData[c4d.RDATA_PATH] != "": storedPath = renderData[c4d.RDATA_PATH] renderData[c4d.RDATA_PATH] =r'{0}_{1}'.format(renderData[c4d.RDATA_PATH], self.layerName) c4d.EventAdd() pathChange = True renderBmp = c4d.bitmaps.BaseBitmap() renderBmp.Init(x=xResolution, y=yResolution, depth=32, ) result = documents.RenderDocument(doc, renderData.GetData(), renderBmp, c4d.RENDERFLAGS_EXTERNAL) if pathChange == True: renderData[c4d.RDATA_PATH] = storedPath # if result==c4d.RENDERRESULT_OK: # c4d.bitmaps.ShowBitmap(renderBmp) # show image in pictureViewer
And then call it like this:
def renderDocument(self, layerName) : """ Taking the document and rendering it according to the normal rendersettings of the document. Ads '_LAYERNAME', LAYERNAME being the name of the layer, to the renderpath. """ renderThread = RenderThread(layerName) renderThread.Start() renderThread.Wait(False) return True
But cinema only becomes responsive again once the plugin is finished with all renders (makes sense in a way.)
One idea i have:
Is it possible to render the things exactly like cinema does usualy? meaning:
- save a copy of the scene somwhere temporarely, render it this way and therefor not influencing the scene in any way? and that in the picture viewer it updates all the images as they are being rendered with tiles and everything?
Thank you!
Aurel
-
On 15/03/2013 at 09:01, xxxxxxxx wrote:
Hi Amadeo,
it shouldn't be a problem, you just have to store the thread object somewhere until it is finished
(eg in your plugin subclass instance, like in the CommandData example).Read the documentation to C4DThread.wait(). It tells you that the function will wait until the thread
is done, and this of course blocks the main loop of Cinema (causing the freeze). Just don't call
Wait() on the thread. In the example above, I have done it since it was necessary to keep the
script running until the thread was finished, and this was achieved by calling Wait() which does
exactly this.Is it possible to render the things exactly like cinema does usualy?
I don't think so, could be wrong though.
-Niklas