Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > PYTHON Development
  New Posts New Posts
  FAQ FAQ  Forum Search

Render to Picture Viewer and RenderDocument woes

Author
Message
  Topic Search Topic Search
Herbie View Drop Down
Member
Member


Joined: 2014 Oct 28
Online Status: Offline
Posts: 28
Direct Link To This Post Topic: Render to Picture Viewer and RenderDocument woes
    Posted: 2014 Nov 03 at 5:20pm
c4d.CallCommand(12099) # Render to Picture Viewer

 I would like to re-create the command above. However, this

doc = documents.GetActiveDocument ()
rd = doc.GetActiveRenderData ()
rdata = rd.GetData ()
xres = int ( rdata[ c4d.RDATA_XRES ] )
yres = int ( rdata[ c4d.RDATA_YRES ] )
bmp = bitmaps.BaseBitmap ()
bmp.Init ( x = xres, y = yres )
res = c4d.documents.RenderDocument( doc, rdata, bmp, renderflags = c4d.RENDERFLAGS_EXTERNAL, th = None )
if res == c4d.RENDERRESULT_OK:
        bitmaps.ShowBitmap ( bmp )

will lock up Cinema until the render finishes. I have tried the other options with the render flags, and can't seem to get more than a frame to render ( or save for that matter ). I have noticed with the c4d.RENDERFLAGS_EXTERNAL flag, it will render out the sequence, but it will look strange in the picture viewer ( also, no multipass files are shown ).

So I've decided to just use the CallCommand in the beginning of the script, then have the rest of the code run after that. At least it will render correctly. However, that CallCommand must run in a separate thread because the rest of my code will execute before the render even starts.

I would like:
Step 1: render
Step 2: run remaining code.

I've looked into c4d.CheckIsRunning ( c4d.CHECKISRUNNING_EXTERNALRENDERING )
and that doesn't seem to do anything with the CallCommand. It will return True, execute the rest of the code, then run the CallCommand.

I've scoured the internet looking for similar posts and have not run into any.

Sigh, I am at a loss. Maybe I'm missing something obvious or maybe I just don't understand.
Any help would be appreciated.
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2014 Nov 04 at 1:00am
Hi,

the callcommand should run in the main thread, but your other tasks (remaining code) can run in a separate user thread.
Therefore you need to let wait, until your rendering is finished.
You can use c4d.CheckIsRunning ( c4d.CHECKISRUNNING_EXTERNALRENDERING ).
Start your call command, check if it is running, if this is true start a new thread.
within this thread make a while loop where you again check if the render is running.
When you while loop is finished you can run the rest of your code inside the userthread.

Additionally you may have a look at this post.
There was the same problem with the bake texture command.
at crossroadtraffic
http://www.plugincafe.com/forum/forum_posts.asp?TID=10711

If this wont help you let me know, than I´ll post  a snippet.

Best wishes
Martin

"The higher that the monkey can climb, the more he shows his tail"
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Direct Link To This Post Posted: 2014 Nov 04 at 7:48am
I think that CallCommand() renders to a temp document. Which is why you can keep working on your current scene.
If you write this code by hand. Try using a temp doc (in memory) as the rendering document instead of your active document.
Be sure to target the temp doc in your code rather than using GetActiveDocument().
Most people make that mistake.


-ScottA
Back to Top
Herbie View Drop Down
Member
Member


Joined: 2014 Oct 28
Online Status: Offline
Posts: 28
Direct Link To This Post Posted: 2014 Nov 04 at 2:22pm
Alrighty!
Thank you guys for your help. I was able to get it working with the CallCommand() and running the rest of the script in a separate thread.
I'll post a truncated version of the working code, just in case someone else runs into this issue.


import c4d, thread, time

def someFunction ( renderCheck, time ):
    while renderCheck == True:
        time.sleep( 5 ) # waits 5 seconds before running rest of loop
        renderCheck = c4d.CheckIsRunning ( c4d.CHECKISRUNNING_EXTERNALRENDERING )
        print 'Checking if render is still rendering'    # still part of the while loop
    print 'Render is done'    # outside of the while loop

def main ():
    c4d.CallCommand (12099) # calls the renderer
        renderCheck = c4d.CheckIsRunning ( c4d.CHECKISRUNNING_EXTERNALRENDERING )
        if renderCheck == True:
            thread.start_new ( someFunction, ( renderCheck, time ) )

if __name__=='__main__':
    main()
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2014 Nov 04 at 2:49pm
Hi Herbie,

great, that it is working for you!
Your code look like the suggestion, but there is no need to pass the rendercheck to your User Thread function.
A simpler version:

import c4d

import os,time, thread


def isRendering(time,os):

    print(time.ctime())

    while c4d.CheckIsRunning ( c4d.CHECKISRUNNING_EXTERNALRENDERING ):
        print("render in progress...")

        time.sleep(4)
   
    print(time.ctime())
    print("render complete.")


def main():

   
    c4d.CallCommand(12099)
   
    if c4d.CheckIsRunning ( c4d.CHECKISRUNNING_EXTERNALRENDERING ):
        thread.start_new(isRendering,(time,os))

if __name__=='__main__':
    main()



@scott
I´m also really interested in your suggestion!
I thought that the c4d.documents.RenderDocument command will render from a temp doc anyway?
Except you set RENDERFLAG_NODOCUMENTCLONE.
The problem is, that if you start the rendering from the main thread with c4d.documents.RenderDocument
the main thread is blocked and busy, too.
If you start it from a userthread, it´ll render in the background and you can edit your scene.
But if it comes to the bitmaps.ShowBitmap(bitmap) part, you´ll get this Error message.
RuntimeError: illegal operation, invalid cross-thread call.
It seems to me, that ShowBitmap must be called from the main thread?

If you or anybody else has an explanation or a working example to share, I´ll be very glad!
Best wishes
Martin


Edited by monkeytack - 2014 Nov 04 at 2:51pm
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Direct Link To This Post Posted: 2014 Nov 04 at 4:16pm
I'm not having any trouble running code in the script manager. Or editing the scene while the renderer is running without using a custom thread.
The only thing that happens is that the timeline scrubber and the ShowBitmap() output freezes in the PV window. But the renderer is still rendering the scene.

Is that what you're talking about?
Can you post an example of starting the render from a thread?

-ScottA
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2014 Nov 04 at 4:34pm
That sounds promissing ! Could you please show a working example?

This is what I´m trying with a userthread:

import c4d
from c4d import gui,bitmaps
from c4d.threading import C4DThread



class UserThread(C4DThread):
   
    def Main(self):
       
        doc = c4d.documents.GetActiveDocument ()
        doc2 = doc.GetClone()
        rd = doc2.GetActiveRenderData ()
        rdata = rd.GetData ()
        xres = int ( rdata[ c4d.RDATA_XRES ] )
        yres = int ( rdata[ c4d.RDATA_YRES ] )
   
        bmp = bitmaps.BaseBitmap ()
        bmp.Init ( x = xres, y = yres )
   
        print c4d.threading.GeGetCurrentThreadCount()
        print c4d.threading.GeGetCurrentThread()
        thr = c4d.threading.GeGetCurrentThread()
        res = c4d.documents.RenderDocument( doc2, rdata, bmp, renderflags = c4d.RENDERFLAGS_EXTERNAL, th = thr )
        print res
        if res == c4d.RENDERRESULT_OK:
            print res
            bitmaps.ShowBitmap ( bmp )

       
        pass


thread = UserThread()
thread.Start()
def main():

    print "the main"




if __name__=='__main__':
    main()




Thanks in advance
Martin
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Direct Link To This Post Posted: 2014 Nov 04 at 6:08pm
Originally posted by monkeytack

That sounds promissing ! Could you please show a working example?

What I'm saying is that I don't use custom threads when rendering and working at the same time.
They don't seem to be necessary.

When c4d.CallCommand (12099) is executed. I can still run scripts and work in the scene while it's rendering. There should be no problem doing both at the same time.
The only down side is that the scrubber and the image preview are frozen when doing that.
Rendering seems to be fully threaded and automatically handled by C4D.
However, things like the scrubber and the preview image don't.

The only code example I have is for C++. But it doesn't use threads or the RenderDocument() function.
Both of those things seem to be problematic when trying to render while working on the scene at the same time. Which is why I asked to see your code.
I haven't had much luck with using custom threads while rendering.

-ScottA
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2014 Nov 05 at 3:09am
Thanks Scott, if you like, you can send me a pm with the c++ code?

The call command handles all the threading operations and nothing is blocked and you can run your script, for sure. (not even the scrubber)

Herbie was asking for running his code after the rendering, I guess.

Originally posted by Herbie


So I've decided to just use the CallCommand in the beginning of the script, then have the rest of the code run after that.


And I was asking for manage it without using a call command with the RenderDocument() function.
But yea, you can get grafic driver errors and other fancy stuff, with trying that one in a Userthread.

On the other hand, if you try it in the main function of your script everything is blocked.

Could anyone please confirm that it is not possible in python to re-create the c4d.CallCommand (12099)?

Thanks in advance
Martin

"The higher that the monkey can climb, the more he shows his tail"
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Direct Link To This Post Posted: 2014 Nov 05 at 7:59am
Sure. I can post it here.
It's very small.
//This is how to render the scene to a temporary document while working on the scene
//Instead of loading a new document. You create a clone of it

    Filename name = doc->GetDocumentName();    //Gets the name & extension  of the document without the path
    Filename path = doc->GetDocumentPath();    //Gets the file's path, minus the file's name and extension
    String fullPath = path.GetString() + "\\" + name.GetString();   //Combine them to get the full file path

    //Save the scene before we open it back up and render it
    //This lets us change the scene and get accurate rendering results
    SaveDocument(doc, fullPath, SAVEDOCUMENTFLAGS_0, FORMAT_C4DEXPORT);

    //Open the scene
    BaseDocument *docCopy = LoadDocument(fullPath, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS, NULL);

    //Insert the scene into the CINEMA editor list of documents
    InsertBaseDocument(docCopy);
    SetActiveDocument(docCopy);
    CallCommand(12099);        //Render to picture viewer
    KillDocument(docCopy);


-ScottA
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2014 Nov 06 at 5:25am
Thanks Scott!

I thought you might have a c++ kernel level threading example, which shows what´s behind the callcommand Big smile,
Anyway, in this case and in python I´m fine with the callcommand.

Best wishes
Martin
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
SezamSky View Drop Down
Member
Member
Avatar

Joined: 2014 Nov 07
Online Status: Offline
Posts: 6
Direct Link To This Post Posted: 2014 Nov 07 at 4:35am
Hi
I ask the question here not to start a new topic.
I need begin rendering immediately after the start of C4D project.
I can't use c4d.CallCommand (12099) or bitmaps commands because in this case need to move the slider on the timeline. How to run a render immediately after opening the file?
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2014 Nov 07 at 5:41am
Hi,

I actually can´t see a reason, why this code should not run properly and why the callcommand should freeze your timeline.
Could you please give it a try and report if something goes wrong?

EDIT
sorry forgot the scenefilters, fixed.


import c4d,os


def main():

    filename = c4d.storage.LoadDialog(c4d.FILESELECTTYPE_SCENES)
    if not filename or not os.path.isfile(filename):
        return
 
    doc = c4d.documents.LoadDocument(filename, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS | c4d.SCENEFILTER_DIALOGSALLOWED | c4d.SCENEFILTER_PROGRESSALLOWED | c4d.SCENEFILTER_NONEWMARKERS | c4d.SCENEFILTER_SAVECACHES)

    c4d.documents.InsertBaseDocument(doc)
    c4d.documents.SetActiveDocument(doc)
    c4d.EventAdd()
    c4d.CallCommand (12099)

if __name__=='__main__':
    main()



Best wishes
Martin



Edited by monkeytack - 2014 Nov 07 at 12:31pm
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
ScottA View Drop Down
Member
Member


Joined: 2011 Jan 07
Online Status: Offline
Posts: 2288
Direct Link To This Post Posted: 2014 Nov 07 at 7:28am
The Picture Viewer window has it's own timeline.
And if you are changing your scene while rendering. The timeline in that PV window does indeed freeze. And so does the image history images. And so does the preview window image.
Basically. Everything in the PV freezes.

However. The rendering is still running in the background. And as soon as you stop changing the scene. All of the rendered images will be dumped from memory into the PV. And the PV timeline will unfreeze and jump to the same frame as the frame being rendered.

This is what I meant when I said that the rendering sems to be threaded, and handled automatically by C4D. But things like ShowBitmap() are not.

It might be possible to get each bitmap that is rendered by using a GeDialog plugin and a custom thread. Combined with SpecialEventAdd() to send out a signal to it's CoreMessage() method. Then ask for the bitmap in the CoreMessage() method.
This is the workaround mentioned in the C++ docs under: Important Threading Information 


-ScottA
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2014 Nov 07 at 12:35pm
Thanks again Scott!
for clarification this time
and the hint with the c++ docs, interesting.

Best wishes
Martin




"The higher that the monkey can climb, the more he shows his tail"
Back to Top
SezamSky View Drop Down
Member
Member
Avatar

Joined: 2014 Nov 07
Online Status: Offline
Posts: 6
Direct Link To This Post Posted: 2014 Nov 12 at 12:27am
Thanks for answers!
Back to Top

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.109 seconds.