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

    python plugin for every frame

    PYTHON Development
    0
    7
    2.2k
    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 04/12/2017 at 07:46, xxxxxxxx wrote:

      Hi All!

      I'm just new into making Python plugins in C4D and may be you can help me with some doubts I have:

      I was using a python expression in a null object to get info from the scene at each frame, so I could save a file with the information on each frame for the whole animation.

      I am now trying to make this into a plugin, but it's not clear to my what type of plugin should I use to execute this function at every frame. Is it a TagPlugin ?

      Also, I'm having some trouble finding documentation on how to define the GUI with description files. Is there specific documentation for that?

      Thanks a lot!

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

        On 05/12/2017 at 02:36, xxxxxxxx wrote:

        Welcome here !
        Tag are executed for each change and baking stage is pretty slow. So I would not recommand you to do this.

        But what you can do is register a CommandData plugin (basicly this is plugin listed into the plugin folder) and when you click on it it will Execute your code. Then in your Execute function you can iterate over the timeline to bake it.

        About GUI, personally if I do a GeDialog I create the dialog from CreateLayout and I don't use ressource file which are limited inside GeDialog. And the nice things you can still refer to some string stored into a ressource file using GeLoadString. 
        About Ressource file I can only suggest you to read the C++ Ressource File  manual

        More generaly I can suggest you to read Python Introduction into the GUI of Cinema4D, and also the C++ one.

        But if you still have question regarding GUI (And I'm sure you got), I guess you can open another topic since it's not related to your first question, it will be more easy for moderator to track your issue. 😉

        Hope it's helped !

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

          On 05/12/2017 at 03:09, xxxxxxxx wrote:

          Hi,

          As gr4ph0s already explained, a tag/expression is not the recommended place to process information from the scene and write a file.

          About evaluating each frame of a scene manually, using BaseDocument.SetTime()/ExecutePasses() is the way to go from a script or CommandData plugin.
          The following script loops through each frame of the active document and prints the position of the active object:

          import c4d
            
          def main() :
              # Backup original time
              originalTime = doc.GetTime()
            
              # Loop through all frames of active document
              fps = doc.GetFps()
              minFrame = doc.GetMinTime().GetFrame(fps)
              maxFrame = doc.GetMaxTime().GetFrame(fps)
              for frame in xrange(minFrame, maxFrame+1) :
                  
                  # Set current frame
                  time = c4d.BaseTime(frame, fps)
                  doc.SetTime(time)
                  # Animate document at current frame
                  doc.ExecutePasses(None, True, True, True, c4d.BUILDFLAGS_INTERNALRENDERER)
                  
                  # Print active object position at current frame
                  if op is not None:
                      pos = op.GetMg().off
                      print("Frame " + str(frame) + " Active Object Position: " + str(pos.x) + ", " + str(pos.y) + ", " + str(pos.z))
                  
                  c4d.EventAdd()
              
              # Restore to original time
              doc.SetTime(originalTime)
              doc.ExecutePasses(None, True, True, True, c4d.BUILDFLAGS_INTERNALRENDERER)
              c4d.EventAdd()
            
          if __name__=='__main__':
              main()
          

          The code in main() can be easily transferred to a CommandData.Execute().

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

            On 05/12/2017 at 03:17, xxxxxxxx wrote:

            What the difference beetwen, both work, but I used all the time the second code.

            doc.ExecutePasses(None, True, True, True, c4d.BUILDFLAGS_INTERNALRENDERER)
            

            And

            c4d.DrawViews(c4d.DRAWFLAGS_ONLY_ACTIVE_VIEW|c4d.DRAWFLAGS_NO_THREAD|c4d.DRAWFLAGS_NO_REDUCTION|c4d.DRAWFLAGS_STATICBREAK)
            c4d.GeSyncMessage(c4d.EVMSG_TIMECHANGED)
            

            EDIT: looking a bit, it's look like the second can only iterate over the active document while the first code can be executed in any BaseDocument, isn'it?

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

              On 05/12/2017 at 07:31, xxxxxxxx wrote:

              Originally posted by xxxxxxxx

              What the difference beetwen, both work, but I used all the time the second code.

              It depends on the context and the purpose of the script/plugin.

              From a script/plugin that needs to only process data, it's generally better to use BaseDocument.ExecutePasses() as the function just animates the passed document.

              DrawViews() does more operations and is slower (animates and draws the active document).
              GeSyncMessage(c4d.EVMSG_TIMECHANGED) updates managers/special dialogs and this is not necessary when only retrieving data.

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

                On 12/12/2017 at 06:09, xxxxxxxx wrote:

                Hey thanks all, this strategy seems to work fine, it iterates through all the frames!

                This saved me a lot of time. I am really grateful!

                Just a follow up question: while the plugin is processing everything, Cinema4d freezes. I guess it's OK, but I can't see the progress or any indicator of what's happening. I guess it is not ok to do all this in a thread?

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

                  On 12/12/2017 at 06:23, xxxxxxxx wrote:

                  You get two methods,
                  First one, don't care but inform user through a progress bar using c4d.StatusSetBar in order to set the bar and do not forget to call c4d.StatusClear to clean the bar after the use.

                  Or you can implement it into your dialog, I let you check my code here PivotMaster (sorry for the code quality, I guess it was my second scripts ^^')which use a CustomGUi_ProgressBar, and check methode above of CreateLayout to know how to handle this CustomGui.

                  About the second way, as you notice, to not freeze the UI you have to create another thread. For that make a clone of your document, using your document.GetClone(), create a derived class of C4DThread, store your cloned document as a member variable inside this class. Then run your function that will iterate the document from this thread.

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