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
    • Register
    • Login

    Multiple unique render files from same file?

    General Talk
    programming download
    2
    5
    853
    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.
    • G
      gsmetzer
      last edited by

      This concept of rendering multiple unique render paths was touched on here: https://developers.maxon.net/forum/topic/13061/adding-multiple-cameras-from-a-single-file-to-the-render-queue/22

      The solution works pretty well but duplicates the source file multiple times.

      My goal is to have a workflow where multiple objects in the same file can be rendered with their object name as their own jpeg. I am using an In/Ex User data and python generator to achieve this. The problem is the jpegs get overwritten each time.
      I am trying to figure out a way to add a batch render element that waits until the render completes then adds a new file with the next object iteration.

      I am posting my scene file and python here. MultiSavePath_01.c4d

      import c4d
      from c4d import gui, storage
      import os
      import fileinput
      
      #The goal is to render multiple files with unique render paths from this one file.   I have this code in a python generator
      #with and in/ex user data, the code iterates through in/ex updating the render path and starting the render.  The problem
      #is the render path and jpeg get overwritten to the same file.   How do I render four separete jpeg files named Cylinder, Sphere, Cube and Figure?
      
      #thank you for any help!
      
      def message(id,data) :   #Button listener
          if id == c4d.MSG_DESCRIPTION_CHECKUPDATE:
              if data["descid"][1].dtype == c4d.DTYPE_BUTTON or c4d.DTYPE_LONG:
                  buttonID = data["descid"][1].id
      
                  if buttonID == 2:
                     SendShotsToRender() #SEND TO RENDER
      
                 
      
      
      
      def main():
      
          return
      
      
      def SendShotsToRender():
      
          print("Send Shots To Render")
          doc = c4d.documents.GetActiveDocument()
          br = c4d.documents.GetBatchRender()
          rd = doc.GetActiveRenderData()
          
          
          br.Open() #Open the render queue window
          c4d.CallCommand(465003519) # Clear render queue of old render files
          inEx = op[c4d.ID_USERDATA,4] # In/Exclude User Data
          inExCount = inEx.GetObjectCount() #how many shots in our In/Exclude
          shot = op[c4d.ID_USERDATA,1] #The currently active shot
      
      
      
      
          for i in range(0,inExCount):  #Iterate through each shot based on our shot slider in user data
      
              activeObj = inEx.ObjectFromIndex(doc, i) #deterimine which object is active
              render_filename = inEx.ObjectFromIndex(doc, i).GetName()  #Gets the name of the currently active object
      
              rd[c4d.RDATA_PATH] = render_filename  #Set the render files name
              
              source_file = doc.GetDocumentPath() + "/" + doc.GetDocumentName() #get the source document path
              
              br.AddFile(source_file,0)  #Add the source file
              
              br.SetRendering(c4d.BR_START) #start rendering
              
              #print(br.GetElementStatus(c4d.RM_FINISHED))  #Is there a way I can wait for the render to finish then delete the file update the path and add a new one?
              
              #br.DelFile(source_file)
      
      
              if shot != i:
      
      
      
      
                      activeObj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = True  #turn visibility On
                      activeObj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = True
      
              else:
                      activeObj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = False  #turn visibility Off
                      activeObj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = False
      
              print(i,render_filename)
      
              op[c4d.ID_USERDATA,4] = inEx  #write back to the IN/EXCLUDE list
      
      
      
      
      
      
      
      
      
      
      
      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by m_adam

        Hi, within a script this will be complicated since there is no built-in way for listening to the end of a rendering in the BatchRender.

        But with a plugin, you could have a timer (see MessageData Documentation) that constantly check if the BatchRender is rendering with BatchRender.IsRendering and if it is not rendering then you can modify the file, save it and add it to the BatchRender again.
        You will also most likely need a CommandData plugin so this way the user can start the execution. This command data can just define a global boolean value that your Timer message always check and if the value is True, then it start the processing of a file.

        One stupid question, but at this point since you will need to do all the queues logic, why not directly render the document, using RenderDocument then you do not need a timer neither to save the doc each time.

        Cheers,
        Maxime.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 1
        • G
          gsmetzer
          last edited by

          Yes, I was able to make it work by pausing the script until IsRendering returns false. It is working really nice, naming my jpegs correctly and is very simple to setup by just dropping the objects I want rendered into the In/Ex list. This workflow is great when I have over 100 objects I want rendered on their own.

          I could use RenderDocument and the Take system but I have not developed a python way to iterate through scene objects - make object visible - assign a take with visibility settings - render with only that object visible. I do believe it is possible and another route I could take. I may try to develop this method as well to compare workflow but I find the Take system cumbersome for bigger jobs.

          Cheers,
          Gabriel

          1 Reply Last reply Reply Quote 1
          • G
            gsmetzer
            last edited by m_adam

            Ok, I ran into the issue of polling the BatchRender.IsRendering. I don't have the python skills to do multi-threading to check when a render is complete. I was able to hack in a time.sleep function but it is very problematic for longer renders and crashes a lot.

            Instead I went the route of Takes though Take are a bit cumbersome to setup but it is working nicely. I'll post the code here for anyone looking to do something similiar. I can just RenderAllTakes command and get each object rendered with its name using a $Take render token.

            def main():
                doc = c4d.documents.GetActiveDocument()
            
            
                inEx = op[c4d.ID_USERDATA,4] # In/Exclude User Data
            
            
            
                for i in range(0 , op[c4d.ID_USERDATA,4].GetObjectCount()):  #Iterate through each shot based on our shot slider in user data
            
                    activeObj = inEx.ObjectFromIndex(doc, i) #deterimine which object is active
            
                    if op[c4d.ID_USERDATA,1] == i:
                        activeObj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = False  #turn visibility On
                        activeObj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = False
                        render_filename = inEx.ObjectFromIndex(doc, i).GetName()  #Gets the name of the currently active object
                        op[c4d.ID_USERDATA,5] = render_filename
            
                    else:
                        activeObj[c4d.ID_BASEOBJECT_VISIBILITY_EDITOR] = True  #turn visibility Off
                        activeObj[c4d.ID_BASEOBJECT_VISIBILITY_RENDER] = True
            
                c4d.EventAdd()
            
            ################   SEND ALL
            
            def BuildTakes():
            
            
                #Sequencer()
                takedata = doc.GetTakeData()
                obj = doc.GetActiveObject()
                #print( Description.GetParameterI(op[c4d.ID_USERDATA,1], ar=None))
            
                inEx = op[c4d.ID_USERDATA,4] # In/Exclude User Data
            
            
            
                for i in range(0,op[c4d.ID_USERDATA,4].GetObjectCount()):
                    #Sequencer()
            
                    take = takedata.AddTake(inEx.ObjectFromIndex(doc, i).GetName(), None, None)
            
                    take.FindOrAddOverrideParam(takedata, obj                         , c4d.DescID(c4d.DescLevel(c4d.ID_USERDATA, c4d.DTYPE_SUBCONTAINER, 1),c4d.DescLevel(1)), i ,  backupValue=None, deleteAnim=False)
                    take.FindOrAddOverrideParam(takedata, inEx.ObjectFromIndex(doc, i), c4d.ID_BASEOBJECT_VISIBILITY_EDITOR, False, backupValue=None, deleteAnim=False)
                    take.FindOrAddOverrideParam(takedata, inEx.ObjectFromIndex(doc, i), c4d.ID_BASEOBJECT_VISIBILITY_RENDER, False, backupValue=None, deleteAnim=False)
                    #op[c4d.ID_USERDATA,1] = 0
                    #Sequencer()
                    #c4d.MSG_DESCRIPTION_CHECKUPDATE
            
            
                #Sequencer()
                #c4d.EventAdd()
            
            def ClearTakes():
                tk = doc.GetTakeData()
                tk.ResetSystem()
            
            1 Reply Last reply Reply Quote 0
            • G
              gsmetzer
              last edited by

              This post is deleted!
              1 Reply Last reply Reply Quote 0
              • First post
                Last post