Exception with thread rendering
-
On 09/04/2013 at 10:53, xxxxxxxx wrote:
Thanks Sebastien,
I've got it working now. And it does render the scene while I'm also working on it.
But I'm having trouble with ending the thread properly.
I'm not 100 % ceratin. But it seems like the thread never ever stops?:import c4d from c4d import documents from c4d import utils, bitmaps, storage,plugins #get an ID from the plugincafe PLUGIN_ID = 1000001 class RenderThread(c4d.threading.C4DThread) : bmp = c4d.bitmaps.BaseBitmap() def Main(self) : doc = c4d.documents.GetActiveDocument() rdata = doc.GetActiveRenderData() rdata = rdata.GetClone(c4d.COPYFLAGS_NO_HIERARCHY) w = rdata[c4d.RDATA_XRES] h = rdata[c4d.RDATA_YRES] rdata[c4d.RDATA_SAVEIMAGE] = True bmp = c4d.bitmaps.BaseBitmap() bmp.Init(int(w), int(h), 32) bmp = c4d.documents.RenderDocument(doc, rdata.GetData(), bmp, c4d.RENDERFLAGS_EXTERNAL) class SceneRender(c4d.plugins.CommandData) : doc = c4d.documents.GetActiveDocument() thread = RenderThread() image = thread.bmp def Execute(self, doc) : self.thread.Start() self.thread.End(False) if self.thread and not self.thread.IsRunning() : print "Render Finished" #<------ This never happens!!! Thread never stops? return True if __name__ == "__main__": help = "The text shown at the bottom of C4D when the plugin is selected in the menu" plugins.RegisterCommandPlugin(PLUGIN_ID, "SceneRender", 0, None, help, SceneRender())
-ScottA
-
On 09/04/2013 at 14:51, xxxxxxxx wrote:
Hi Scott,
your thread is still running while the Execute() method has already reached its end. At the point
you check if the thread is still running, the thread is actually still running, and you never happen
to reach this statement again. Try this instead:if self.thread and self.thread.IsRunning() : print "Cannot start render, still running ..." else: self.thread.Start()
If you pressed the command in Cinema, it will start to render. If you then press it again and
rendering is not done at this point, it will tell you about this, otherwise it will start a new
render thread.You do not have to call End() on the thread object. If you wanted to wait until the thread is
finished, you would again block Cinema's main-thread resulting in a temporary freeze.PS: One usually explictly binds a thread to a context, it is rather unusual to create one thread
object and start it more than once.Best,
-NIklas -
On 09/04/2013 at 15:29, xxxxxxxx wrote:
Thanks Nik,
I did try it that way also. But it still doesn't give me any way check the thread for it's stopped state.
Per your comment on CGTalk. You made it sound like we can't get the stopped state due to a bug.
I'm not sure if that's what you meant?The way I normally use threads is:
-Create a thread class.
-Run a loop inside that class with some task being run per loop iteration
-Then ending the threadAll of this is done in the thread class.
To make the thread class code execute. I would use a call from one of the plugins methods. For example when a gui button is pressed.
I don't normally do any thread status checking from within the plugin's methods like in my example. So this is new territory for me.At this point. I can create a thread and render the scene out while still working on the scene. Which is sort of a success.
But there is no visual feedback as to what's going on. And no way to even tell when the thread has finished running.
And if I try to open the image viewer while rendering. All I get is a black image in the image viewer. Instead of the sequence of renders being rendered.You mentioned you had similar problems and had to find a completely different way to hack around this without using threads at all. So maybe what I'm trying to do can't be done?
-ScottA
-
On 09/04/2013 at 22:56, xxxxxxxx wrote:
Hi Scott,
What I said is, that when you start a render in the Picture Viewer using RenderDocument(), you can
not stop the render anymore (eg. closing the PV doesn't ask you to stop the render and the
"Stop Render" command in the PV is greyed out).I don't see where you are unable to check for its stopped state. IsRunning() is just fine for this job.
A thread ends automatically when it quits its Main() method, you do not have to call End() on it.
What End() does is stated in the docs: It enables you to interrupt the thread before it is actually
done (imagine, eg: When Cinema closes and your thread is still running, you want to tear it down,
either waiting for it to finish or even interrupt it).As for the visual feedback: What do you expect? You didn't implement any visual feedback
Since my PV Render Queue plugin is only rendering in the Picture Viewer and does not require
any reference to the rendered image, I've been using a simple CallCommand() to start the
Picture Viewer rendering (as I said @CGSociety). Although I'm not a fan of using CallCommand(),
it was necessary to get around this "I can't stop the rendering, what a sh*t plugin!" thing.Best,
-Niklas -
On 10/04/2013 at 04:14, xxxxxxxx wrote:
Thanks for all the answers!
I changed my code a bit to copy yours, but now I get this Exception after calling ShowBitmap() :
RuntimeError: illegal operation, invalid cross-thread callThis is my Thread:
class RenderThread(C4DThread) : def __init__(self, doc) : super(RenderThread, self).__init__() self.doc = doc def Main(self) : renderData = self.doc.GetActiveRenderData() xResolution = int(renderData[c4d.RDATA_XRES]) yResolution = int(renderData[c4d.RDATA_YRES]) renderBmp = c4d.bitmaps.BaseBitmap() renderBmp.Init(x=xResolution, y=yResolution, depth=32) result = documents.RenderDocument(self.doc, renderData.GetData(), renderBmp, c4d.RENDERFLAGS_EXTERNAL) print result if result == c4d.RENDERRESULT_OK: c4d.bitmaps.ShowBitmap(renderBmp)
And this is the call:
class CommandDataExecute(plugins.CommandData) : __dialog = None renderThread = None #plugin started by user def Execute(self, doc) : doc = documents.GetActiveDocument() if self.renderThread and self.renderThread.IsRunning() : print 'Thread is still running. Please try again later' else: self.renderThread = RenderThread(doc) print 'start Thread erfolgreich: ', self.renderThread.Start()
Any suggestions on this?
-
On 10/04/2013 at 06:13, xxxxxxxx wrote:
Hi Nachtmahr,
it has already been said: GUI Operations can not be invoked from a thread. ShowBitmap() opens
the Picture Viewer and is therefore a GUI operation. You will have to invoke it from the main thread.
Eg. all Message() and CoreMessage() are usually called from the main thread so it is safe to open the
bitmap from one of these methods.Best,
-Niklas -
On 10/04/2013 at 06:50, xxxxxxxx wrote:
Hi Niklas,
yes you said that before, I remember. But to call the PV from the main thread, I only see 2 possibilities:
- In the mainthread I wait for the renderthread to return, so I can open the PV with the picture. But in this case the thread is useless.
- I have to send a message from the renderthread, catch it with my Plugin and open the PV. But how? When I search for "SendMessage" I only get
GeDialog.SendMessage
which is not what I can use (I think) and to catch a message I'd use CommandData.Message. But here the API (only in the one for C++ -.-) states, that I only can use these two: MSG_COMMANDINFORMATION and MSG_BODYPAINTEXCHANGE. Is there any other Message I can catch, where to find the information, how to send usermessages, etc etc. So many questions and the documentation let them all be unanswered...
_<_t_>_
|
---|---
<_<_t_>_
-
On 10/04/2013 at 07:47, xxxxxxxx wrote:
Hi Nachtmahr,
no, GeDialog.SendMessage() is not what you need. Many ways will lead you to Rome, and so there
are many was this can be achieved. I think the best option would be to implement a MessageData
plugin and override its ~.CoreMessage() method. Then you can send EventAdd() from your
RenderThread and check for EVMSG_CHANGE in CoreMessage(). When this message is sent, you
simply check the thread for the bitmap and open it in the Picture Viewer. Make sure you have a
reference to the thread. You can either use global variables (not good design) or pass the thread to
the MessageData plugin.-Niklas
-
On 10/04/2013 at 08:14, xxxxxxxx wrote:
Thanks, I'll try that tomorrow! Looks like an interesting approach
-
On 10/04/2013 at 12:10, xxxxxxxx wrote:
Nik,
You're misunderstanding me.
I can run the thread just fine. But I could not find a way to test for it's finished condition.
Then it just hit me today like a ton of bricks that the reason I probably can't do this is because I'm using a CommandData() plugin.
Which means after the plugin is executed from the menu and the thread starts. The plugin then probably closes. So it makes sense to me now that there would be no way to check the Thread's finished status using a CommandData() plugin.Do you happen to have an old version of your plugin where it renders to the image viewer with a thread. But does not stop? Or have you deleted it?
I would like to see what type of plugin you used(GeDialog?) And how you called the c4d.bitmaps.ShowBitmap() method.If not don't sweat it.
-ScottA