Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Cinema Freezes while rendering

    PYTHON Development
    0
    8
    806
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      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

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        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

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 15/03/2013 at 00:36, xxxxxxxx wrote:

          I will google that, an example would be much appreciated though!

          Aurel

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            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

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              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 dead

              And 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

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                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

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  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

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    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

                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post