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

    instancing a deformer / copy all params

    Scheduled Pinned Locked Moved PYTHON Development
    8 Posts 0 Posters 839 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 30/04/2017 at 09:13, xxxxxxxx wrote:

      Hello,

      I am trying to figure out the best way to link all parameters of one object to another.

      More fundamentally, I would like to understand the syntax behind object parameters, more specifically, the base objects, like the deformers, hypernurbs etc.

      For any object, to address a parameter, you use square brackets.
      To me, this suggests the object is a list/array.

      Yet if I try to loop through it like this:

        
      link = op[c4d.ID_USERDATA,1] # this is a link to another object
        
      def main() :
          for a in link:
              print a
        
      
      

      I get TypeError: 'c4d.BaseObject' object is not iterable

      so whats the deal with this useage of square brackets?
      And what is a good approach to get/set all object parameters? 
      Maybe when I say "all" is a bit too vague, I assume they are categorised based on the tabs you see in the attribute manager, I don't know how/where this info is stored / accessed..

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

        On 02/05/2017 at 10:13, xxxxxxxx wrote:

        I guess you should read this relevant pdf from pgrooff
        http://www.grooff.eu/tutorials/Adding User Data using Python.pdf

        Basicly link is currently egal to an object. Not a link.
        For testing it just do print link. YOu will se it's egal to the object linked and not directly to the link ui.

        About object parameter I really encourage you to read and re-read to be sure to really understand what this mean about BaseContainer.
        Basicly BaseContainer is like a list (more precisly a non ordered list).
        So for exemple if we take a cube (create one yoo too, you will understand me way more by doing it yourself also than jsut by reading myself)

        Now open the console and drag the parameter Size .X into the console.
        You will saw Cube[c4d.PRIM_CUBE_LEN].
        If you press Enter you get the current value of the cube.
        Again in the console hit the top arrow key (like that you get your previous line executed).
        This time remove [c4d.PRIM_CUBE_LEN] and press enter. You will have something like
        <c4d.BaseObject object called 'Cube/Cube' with ID 5159 at adress in memory>
        So Cube is our object.

        Now again press the top arrow key and remove Cube and [] so we got c4d.PRIM_CUBE_LEN,c4d.VECTOR_X Press Enter.
        And you will see two number. (1100, 1000)

        Thoses two number are actually ID to acces parameter into the basecontainer(you remember the list?) of your object.

        Then I think you will understand my following code

        import c4d
          
        def main() :
            #Get current selected obj
            obj = op
            
            #abord if is not a cube. c4d.Ocube = 5159 as we saw before in the console
            if not obj.CheckType(c4d.Ocube) :
                return
            
            #Get the cube container instance.
            #it's an instance that mean any change we made into this container 
            # are automaticly replicated into the container of the object
            bc_cube = obj.GetDataInstance()
            
            #before we get 2 ID c4d.PRIM_CUBE_LEN which was egal to 1100 and c4d.VECTOR_X = 1000
            #In our case Since its Vector c4d divide his into multiple data like that we can retrieve only X parameter if we want.
            #But internally size Is an Vector(3 floats)
            #So for retrieve data we can do
            
            size = bc_cube.GetVector(1100) #or c4d.PRIM_CUBE_LEN is exactly the same just more visual than a number.
            size.x = 10 #we change the value of the vector, this is a variable, now we should update the container if we want to change obj properties
            
            bc_cube.SetVector(c4d.PRIM_CUBE_LEN, size)
            #Since we use GetDataInstance, and it's an instance we don't have to update the container of the object with'
            #obj.SetData(bc_cube)
            
            #trigger change
            c4d.EventAdd()
            
          
        if __name__=='__main__':
            main()
        

        Hope it's help you

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

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

          Hi NNenov, thanks for writing us.

          In addition to the extended explanation that gr4ph0s has gently provided I warmly suggest to have a look at the BaseObject Manual and to the BaseContainer Manual because, even though they both belong the C++ API, could help understanding the foundations of these two relevant Cinema classes.

          Last but not least, the Python examples available on GitHub might be of valuable support to ease the learning curve of the concepts above.

          Best, Riccardo

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

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

            Hey! Sorry for the delay.
            I think I understand, so GetDataInstance() will get an instance of all the settings stored for the object? like, position, generator parameters, etc. And to get their unique IDs, just put the id value in console, e.g. c4d.ID_MG_SHADER_SHADER returns 5000

            So is it possible if the source and target are of same O type, that you can take one object's DataInstance and set it "to" the other?

            I am trying to create a python generator with user data type link, so you can link to a deformer, and the python generator will "become" an "instance" of that deformer. Instance is perhaps the wrong word, I mean it would be generating a unique deformer, but that deformer will have all of it's parameters linked, and, actively updated, to those of the target in the user data field.

            So far I have created a python generator, with user data, and linked it to the deformer I would like to "instance".

            In the python code, I started by creating a base object using the type what has been linked

              
                oType = obj.GetType()
                clone = c4d.BaseObject(oType)
            

            where obj is the user data link to deformer I want to mimic

            now that I have this new generated deformer, I do:

                oDat = obj.GetDataInstance()
                clone.SetData(oDat)
            

            then return clone.
            I was hoping this would set the new base object to all the same parameter, including local coordinates, but this doesn't work, there is no deformation on the sphere and the coordinates are unchanged.

            Also if I make the python generator editable, it returns a Null object rather than the displace deformer base object. 
            I don't get an error message either..

            check screenshot:
            https://www.dropbox.com/s/3zl0pbuz3aobk7e/real instance.jpg?dl=0

            scenefile:
            https://www.dropbox.com/s/hlvlatc1nf4kkr0/RealInstance_0001.c4d?dl=0

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

              On 15/05/2017 at 01:26, xxxxxxxx wrote:

              Not really you can copy it only if it's really the same type.

              Understand Basecontainer just like a way for storing data. Is not because you store all the data from an object that he will act like another one. It have to be same.

              But in your case it should work but I guess it's a limitation from the python generator (maybe if you register you own deformer you can do it). But I'm not sure wait a, official reply.

              Anyway if you jsut want to get a clone why not make source.GetClone()

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

                On 15/05/2017 at 10:27, xxxxxxxx wrote:

                Hmm yeah I thought it would have to at least be the same type..
                Strange..
                when you say .GetClone(), do you mean something like this in the python generator?

                import c4d
                  
                obj = op[c4d.ID_USERDATA,1]
                  
                def main() :
                  
                    return obj.GetClone()
                

                this doesn't seem to work either.
                Maybe the reason this doesn't work is the same why an instance object referencing a deformer doesn't work either.. could it be something to do with the deformed point caches not being generated? Very curious about this.

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

                  On 16/05/2017 at 06:29, xxxxxxxx wrote:

                  Hi NNenov,

                  with reference to your request, consider that being the Python Generator (as properly pointed out by gr4ph0s) registered as OBJECT_GENERATOR, it impedes the generator to behave as a modifier since the  BaseObject::GetVirtualObjects() is actually implemented in the Python Generator itself. This goes beyond the fact that the data in your cloned object matches the one used in the source modifier object.

                  Last but not least, the Instance Object, as you have properly reported, doesn't work either since it's again registered as an OBJECT_GENERATOR as well. The official documentation on the generator states explicitly mention this behaviour.

                  Best, Riccardo

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

                    On 28/05/2017 at 13:42, xxxxxxxx wrote:

                    Hi KnickKnack,

                    Thanks for following up on this, I ended up making a python tag instead, with a link field user data.
                    It works with any object I've tried so far, instances all target parameters to whatever object the tag is applied to:

                    import c4d
                      
                    source = op[c4d.ID_USERDATA,1]
                    target = op.GetObject()
                      
                    def main() :
                        
                        oDat = source.GetDataInstance()
                        target.SetData(oDat)
                      
                    
                    
                    1 Reply Last reply Reply Quote 0
                    • First post
                      Last post