Jump to content

Sign in to follow this  
Cristobal

Create instance/s from selected object/s

Recommended Posts

Converting all my old simple (or relatively simple) scripts to work with C4D 20…

 

I'm very accustomed to simply press “i” to create an instance of selected object, thanks to an old COFFEE script (you can see it HERE, I don’t remember where I found it, years ago)

 

Now I have created this Python script to do the same thing (just copying from the Script Log, I have no idea of coding for C4D)

 

import c4d
#Welcome to the world of Python

def main():
    def tool():
        return c4d.plugins.FindPlugin(doc.GetAction(), c4d.PLUGINTYPE_TOOL)

    def object():
        return doc.GetActiveObject()

    def tag():
        return doc.GetActiveTag()

    def renderdata():
        return doc.GetActiveRenderData()

    def prefs(id):
        return c4d.plugins.FindPlugin(id, c4d.PLUGINTYPE_PREFS)

    c4d.CallCommand(200000067, 200000067) # Duplicate
    tool()[c4d.MDATA_DUPLICATE_COPIES] = 1
    tool()[c4d.MDATA_DUPLICATE_INSTANCES] = 1
    c4d.CallButton(tool(), c4d.MDATA_APPLY)


if __name__=='__main__':
    main()
    c4d.EventAdd()

 

And it works perfectly except for a small thing: it creates a single instance from my selected object (great) but it places it inside a NULL. And I don’t want that. I would prefer my instance to be created automatically just side by side the original object, without nulls.

 

Can you help me with this?

 

THANKS! :-)

Share this post


Link to post
Share on other sites

import c4d
from c4d import gui

def main():
    c4d.CallCommand(5126) # Instance

# Execute main()
if __name__=='__main__':
    main()

This doesn't work for you? :)


Free C4D trainings from MAXON professional on our youtube channel

 

https://www.youtube.com/c4dcafe

Share this post


Link to post
Share on other sites
  • Topic Author
  • Dear HSrdelic,

     

    It works PERFECTLY FINE! :-)

     

    Now I feel a complete dumb…

     

    So many years using that COFFEE script to quickly create a single instance from an object… And in fact is NOT necessary a script for that simple operation. There is a native tool and you can simply search for “Instance” in the “Customize commands” and assign your prefered keymap to that command. So simple!

     

    Now I asked myself WHY I initially got that old script, then? And the response is this: that old script allowed to create individual instances for each selected objects (you select 5 objects and automatically get 5 instances)

     

    But that is not really so necesary for my workflows… I can live without that script…

     

    Thanks again, HSrdelic :-)

    Share this post


    Link to post
    Share on other sites

    a bit late but anyway :) 

    import c4d
    from c4d import gui
    #Welcome to the world of Python
    
    
    def main():
        doc.StartUndo()   # this generates an UNDO stack, every "AddUndo" between .StartUndo() and .EndUndo() will be "undoable" in a single "Ctrl+Z"
        objects = doc.GetActiveObjects(0)   # this get's currently active objects in a list. The "0" parameter means that we don't want to select the children of the objects and we don't care about the oreder of the returned selection
        for obj in objects:   # this iterates over the list of active objects. So for each object:
            instance = c4d.BaseObject(c4d.Oinstance)   # create a new instance object
            instance.SetName(obj.GetName() + '_instance')   # set it's name to the object's name + "_instance"
            instance[c4d.INSTANCEOBJECT_LINK] = obj   # set the instance's source object
            instance.InsertBefore(obj)   # insert the instance object in the object manager, right before the source object. You can use other options. Like .InsertAfter(obj), if you want it after the source object.
            doc.AddUndo(c4d.UNDOTYPE_NEW, instance)   # this adds the insertion of our new instance to the undo stack.
        doc.EndUndo()   # this ends the undo stack
        c4d.EventAdd()   # we infrom C4D that something has occured, otherwise it will not refresh until you click something or do something else
    if __name__=='__main__':
        main()

     

    Share this post


    Link to post
    Share on other sites

    ...never to late with this code examples, good job mate 

     (and small description of every line/blok would be amazing. This kind of scripts could be very simply "readable" for non-coder users to understand what those lines of code means.

     Directly from this script  how to handle with multiple selected objects instead of single one and perform some "actions" with them...)

    Thanks...

     

    Share this post


    Link to post
    Share on other sites

    @bezo Yeah, man, you are right. I usually do comment them, but this time I got lazy ;) FIXED

    Share this post


    Link to post
    Share on other sites
  • Topic Author
  • Thank you so much for sharing that scripts, Kalugin! And also for commenting: this will be of great help!

     

    Away from my computer now. But tomorrow I will install for sure!

     

    BIG THANKS :-)

    Share this post


    Link to post
    Share on other sites
  • Topic Author
  • Just a quick note to confirm that I installed your script, kalugin, and it works fantastically!

    Your comments will be also very useful, as I said.

     

    I'm very grateful :-)

    Best regards.

    Share this post


    Link to post
    Share on other sites

    Thank you Alex for description of all lines.

    From this description users could understand, which line of code means and "re-use"/grab for own scripts. Because maybe 85 percent of code is "reusable" for creating new scripts just changing few words in the code...

     

     

    Share this post


    Link to post
    Share on other sites
  • Topic Author
  • I have slightly modified the script to transfer the Relative Position, Scale and Rotation from each selected object to their correspondent instances (to better mimic what the native “Instance” tool does).

     

    I'm sure this could be done in a more smart way, but anyway it works pretty well :-)

     

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    # Created and shared by Kalugin here:
    # https://www.c4dcafe.com/ipb/forums/topic/104182-create-instances-from-selected-objects/
    
    def main():
        doc.StartUndo()   # this generates an UNDO stack, every "AddUndo" between .StartUndo() and .EndUndo() will be "undoable" in a single "Ctrl+Z"
        objects = doc.GetActiveObjects(0)   # this get's currently active objects in a list. The "0" parameter means that we don't want to select the children of the objects and we don't care about the oreder of the returned selection
    
        for obj in objects:                             # this iterates over the list of active objects. So for each object:
            instance = c4d.BaseObject(c4d.Oinstance)    # create a new instance object
            instance.SetName(obj.GetName() + '_inst')   # set it's name to the object's name + "_inst"
            instance.SetRelPos(obj.GetRelPos())         # set it's Relative Position to the object's Relative Position
            instance.SetRelScale(obj.GetRelScale())     # set it's Relative Scale to the object's Relative Scale
            instance.SetRelRot(obj.GetRelRot())         # set it's Relative Rotation to the object's Relative Rotation
            instance[c4d.INSTANCEOBJECT_LINK] = obj     # set the instance's source object
            instance.InsertAfter(obj)                   # insert the instance object in the object manager, right before the source object. You can use other options. Like .InsertBefore(obj), if you want it after the source object.
            doc.AddUndo(c4d.UNDOTYPE_NEW, instance)     # this adds the insertion of our new instance to the undo stack.
    
        doc.EndUndo()    # this ends the undo stack
        c4d.EventAdd()   # we infrom C4D that something has occured, otherwise it will not refresh until you click something or do something else
    
    if __name__=='__main__':
        main()

     

    Share this post


    Link to post
    Share on other sites

    thanks, nice script. is there a way to select the created instance automatically?

    Share this post


    Link to post
    Share on other sites

    here are some additions to the educational script :)

    @Eterea There actually is more simple way to transfer the PSR of the object

    @Hofmann Manuel Check out the part about holding "CTRL"

    import c4d
    from c4d import gui
    # Welcome to the world of Python
    # Created and shared by Kalugin here:
    # https://www.c4dcafe.com/ipb/forums/topic/104182-create-instances-from-selected-objects/
    
    def main():
        mod_key = getModKey()
        doc.StartUndo()   # this generates an UNDO stack, every "AddUndo" between .StartUndo() and .EndUndo() will be "undoable" in a single "Ctrl+Z"
        objects = doc.GetActiveObjects(0)   # this get's currently active objects in a list. The "0" parameter means that we don't want to select the children of the objects and we don't care about the oreder of the returned selection
    
        for obj in objects:                             # this iterates over the list of active objects. So for each object:
            instance = c4d.BaseObject(c4d.Oinstance)    # create a new instance object
            instance.SetName(obj.GetName() + '_inst')   # set it's name to the object's name + "_inst"
    
            # YOU CAN TRANSFER ALL OF THIS IN ONE LINE
            # instance.SetRelPos(obj.GetRelPos())         # set it's Relative Position to the object's Relative Position
            # instance.SetRelScale(obj.GetRelScale())     # set it's Relative Scale to the object's Relative Scale
            # instance.SetRelRot(obj.GetRelRot())         # set it's Relative Rotation to the object's Relative Rotation
            # LIKE THIS
            # instance.SetMl(obj.GetMl())                 # this uses the matrix of the object directly. It contains all the information about the PSR of an object.
            
            instance[c4d.INSTANCEOBJECT_LINK] = obj     # set the instance's source object
            instance.InsertAfter(obj)                   # insert the instance object in the object manager, right after the source object. You can use other options. Like .InsertBefore(obj), if you want it before the source object.
            doc.AddUndo(c4d.UNDOTYPE_NEW, instance)     # this adds the insertion of our new instance to the undo stack.
    
            # here is an example how to use the modifier keys. In this case, as Hofmann Manuel asked - holding ctrl while executing the script will deselect the source objects and select the instances.
            
            if 'ctrl' in mod_key:                       # if you are holding CTRL while executing the script
                doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)   # we add the deselection of the source object to the undo stack. Notice that different undo operations sometimes are called before the action and sometimes after that. Check the SDK.
                obj.DelBit(c4d.BIT_ACTIVE)              # we delete the BIT (actually sets it to 0), that tells cinema if the object is selected or not
                instance.SetBit(c4d.BIT_ACTIVE)         # and we set the BIT to 1 for the instance
    
            if 'shift' in mod_key:                      # here we test if shift is included in the combination, so this works with or without using other keys
                instance.SetMl(obj.GetMl())             # if shift was pressed, we transfer the object's matrix to the instance
    
        doc.EndUndo()                                   # this ends the undo stack
        c4d.EventAdd()                                  # we infrom C4D that something has occured, otherwise it will not refresh until you click something or do something else
    
    # some helper functions, this is really usefull for all kind of tasks, so I've decided to share it in this script :)
    
    def getModKey():
            bc = c4d.BaseContainer()                    # we create a container object to hold the data returned from the GetInputState()
            if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.BFM_INPUT_CHANNEL, bc): # we check if the keyboard has any keys pressed and return the result to the bc
                if bc[c4d.BFM_INPUT_QUALIFIER] == c4d.QSHIFT: # the c4d.BFM_INPUT_QUALIFIER is a the place in the bc where the key pressed is stored, we check if the key pressed was shift
                    return "shift"                      # if it was, we return that as a string. You can do it in different ways. I did it like this in this example to make it more readable
                if bc[c4d.BFM_INPUT_QUALIFIER] == (c4d.QSHIFT + c4d.QCTRL):
                    return "shift+ctrl"
                if bc[c4d.BFM_INPUT_QUALIFIER] == (c4d.QSHIFT + c4d.QALT):
                    return "shift+alt"
                if bc[c4d.BFM_INPUT_QUALIFIER] == (c4d.QSHIFT + c4d.QCTRL + c4d.QALT):
                    return "shift+ctrl+alt"
                if bc[c4d.BFM_INPUT_QUALIFIER] == c4d.QCTRL:
                    return 'ctrl'
                if bc[c4d.BFM_INPUT_QUALIFIER] == (c4d.QCTRL + c4d.QALT):
                    return 'ctrl+alt'
                if bc[c4d.BFM_INPUT_QUALIFIER] == c4d.QALT:
                    return 'alt'
                else:
                    return ''                           # if non of the keys that we are checking for was pressed, we return an empty result
    
    if __name__=='__main__':
        main()

     

    Share this post


    Link to post
    Share on other sites

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest
    Reply to this topic...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

    Sign in to follow this  

    • Recently Browsing   0 members

      No registered users viewing this page.

    ×
    ×
    • Create New...