Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    CSTO on a Cloner

    Scheduled Pinned Locked Moved PYTHON Development
    9 Posts 0 Posters 1.1k Views
    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 Offline
      Helper
      last edited by

      On 05/11/2017 at 07:20, xxxxxxxx wrote:

      I have a ObjectPlugin where I want to use a cloner.
      But CSTO returns a Null with only one child under it (and not 2 as I expected).

      Input objA = Cube, objB = Cloner with a cube and a count of 2.
      So, I expect a Null with 2 children.

      It does not help if I use a Clone or not.
      Here the test code.

          def GetVirtualObjects(self, op, hierarchyhelp) :
          
              doc = c4d.documents.GetActiveDocument()
        
              if op.GetDown() is None or op.GetDown().GetNext() is None:
                  return c4d.BaseObject(c4d.Onull)
        
              res = op.GetAndCheckHierarchyClone(hierarchyhelp, op.GetDown(), c4d.HIERARCHYCLONEFLAGS_0, True)
              if res['dirty'] == False:
                  return res['clone']
                  
              objA = res['clone'].GetDown()
              objB = objA.GetNext()
                   
              objList = c4d.utils.SendModelingCommand(
                  command = c4d.MCOMMAND_CURRENTSTATETOOBJECT,
                  list = [objB],					#using objB.GetClone() does not help		
                  mode = c4d.MODELINGCOMMANDMODE_ALL,
                  doc = doc)
              if objList == False:
                  #print "Error Current State to object MoGraph!"  
                  return None
              
              print "CSTOMoGraph: ", objB
              print "objList[0]: ", objList[0]
              print objList[0].GetChildren()  		#print all children      
              return c4d.BaseObject(c4d.Onull)
      
      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 05/11/2017 at 07:47, xxxxxxxx wrote:

        objB.GetCache() seems to return all children!

        But apparently GetVirtualObjects() makes life harder.

        Using the script manager I get the result I expected, but within GetVirtualObjects() objB.GetCache() returns None?

        Script

        import c4d
        from c4d import gui
        #Welcome to the world of Python
          
          
        def main() :
            obj = op.GetCache()
            print obj.GetChildren()
          
        if __name__=='__main__':
            main()
        

        Test code

            def GetVirtualObjects(self, op, hierarchyhelp) :
            
                doc = c4d.documents.GetActiveDocument()
          
                if op.GetDown() is None or op.GetDown().GetNext() is None:
                    return c4d.BaseObject(c4d.Onull)
          
                res = op.GetAndCheckHierarchyClone(hierarchyhelp, op.GetDown(), c4d.HIERARCHYCLONEFLAGS_0, True)
                if res['dirty'] == False:
                    return res['clone']
                    
                objA = res['clone'].GetDown()
                objB = objA.GetNext()
                     
                objCache = objB.GetCache()
                print "objCache: ", objCache
                
                print "CSTOMoGraph: ", objB
                print objCache.GetChildren()        
                return c4d.BaseObject(c4d.Onull) 
        

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

          On 05/11/2017 at 08:48, xxxxxxxx wrote:

          Or do I have to use GeGetMoData() to get all the children?

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

            On 07/11/2017 at 00:29, xxxxxxxx wrote:

            Solved it using a new doc.

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

              On 07/11/2017 at 03:22, xxxxxxxx wrote:

              Ok, I am using a new doc to do the csto for a MoGraph cloner.
              That works, but the materials - attached to the children of the cloner - are not included.
              Of course that is because I use a new doc without any materials.
              But then the question is then, how to get the materials back?

              Even if I use a doc.GetClone() for the new doc, it does not work.

              -Pim

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

                On 07/11/2017 at 05:46, xxxxxxxx wrote:

                Hi Pim,

                I'm terribly sorry for letting you alone with this for so long.

                First of all, even if it may not be the cause of your issues, it is so important, I must not forget: Never ever use GetActiveDocument() in a NodeData (or derived thereof) plugin! Never!

                Reason:
                Functions like Execute(), GetVirtualObjects() and alike get called during scene execution. But a scene/document does not only get executed, while the user is working with it in the editor, but also for example when rendering. But in the later case the scene is most likely not the active document (but at least a clone thereof). So by using GetActiveDocument() in a NodeData plugin you will end up in a situation, where you are working with the wrong document. Maybe not immediately, but once for sure. And even then you might not even notice, because the active scene and the one being rendered might be identical or identical enough for this not to cause immediate issues. But then one day it will cause problems and the issue then will be pretty hard to track down as things suddenly without warning start acting weird. So please, do not use GetActiveDocument() here, instead use op.GetDocument().

                Ok, forgive me for writing so much about this, but it's really important. I will see, that we improve our documentation in this regard.

                Now, back to your original issue.

                No, you don't need to use GeGetMoData().

                In the end you are dealing with caches of objects and if evaluated properly, these caches do finally contain the polygonal representation of a more or less complex object (-hierarchy). Just to visualize a more complex situation (and the one you are describing is not that different), see the notes and image on GetCache() and GetDeformCache(). This just to get a better understanding, in your case you don't need to iterate the caches yourself.

                Good news is, GetAndCheckHierarchyClone() takes care of this. It iterates the hierarchy of your input objects, takes care of dependency lists, retrieves clones(!) of the involved caches and also marks your input objects correctly as control objects.
                The important part for you: It retrieves clones of the involved caches. Meaning, you get a polygonal representation of the inputs.
                No need to do an extra "Current State to Object" via SendModelingCommand(), as you do in your first post.
                And also no need to try to get the cache of the returned cache objects as you do in your second post via objB.GetCache(). objB is already (part of) the cache.

                The thing is, GetAndCheckHierarchyClone() returns the cache, but you need to be aware that the cache may be a bit more complex, i.E. is a hierarchy of objects. In case of your MoGraph Cloner example as second input object, objB will be a Null object parenting the polygonal representations of the cube clones.

                So your code snippets are actually correct until the assignment of objA and objB. objB then being the Null object, where in the original object hierarchy the cloner was located. And objB.GetDown() will be the first cube.

                Also worth knowing that you can use GetType(), CheckType(), IsInstanceOf() or even GetName() to get an idea of what got returned to you in such situations.

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

                  On 07/11/2017 at 07:25, xxxxxxxx wrote:

                  Thanks for the detailed answer, I am beginning to see the light.

                  However, for me it does not return the polygonal representations of the cube clones, but the objects itself.

                  Here the console output:
                  objB:  <c4d.BaseObject object called 'Cloner/Cloner' with ID 1018544 at 0x0000016A9C11DB30>
                  [<c4d.BaseObject object called 'Cube/Cube' with ID 5159 at 0x0000016A9C11D9D0>, <c4d.BaseObject object called 'Cylinder/Cylinder' with ID 5170 at 0x0000016A9C11D8B0>]

                  This is the hierarchy:

                  - objectplugin
                    - cube
                    - MoGraph Cloner
                      - cube
                      - cylinder

                      def GetVirtualObjects(self, op, hierarchyhelp) :
                    
                          doc = op.GetDocument() #not needed here
                    
                          if op.GetDown() is None or op.GetDown().GetNext() is None:
                              return c4d.BaseObject(c4d.Onull)
                    
                          res = op.GetAndCheckHierarchyClone(hierarchyhelp, op.GetDown(), c4d.HIERARCHYCLONEFLAGS_0, True)
                          if res['dirty'] == False:
                              return res['clone']
                              
                          objA = res['clone'].GetDown()
                          objB = objA.GetNext()
                               
                          print "objB: ", objB
                          print objB.GetChildren()  		#print all children      
                          return c4d.BaseObject(c4d.Onull)
                  
                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 07/11/2017 at 08:19, xxxxxxxx wrote:

                    Ah, sorry!!!
                    I overlooked your flags. Please pass c4d.HIERARCHYCLONEFLAGS_ASPOLY to GetAndCheckHierarchyClone().

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

                      On 07/11/2017 at 08:35, xxxxxxxx wrote:

                      Thank you!

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