Cannot Connect Xpresso Nodes in Python



  • I am using the Python script manager to try and automate a few things. I am creating a hierarchy and I want to create an xpresso tag where the z offset of one cloner is driven by the z size of another cloner. Here's my code:

    import c4d
    from c4d import gui
    import math
    
    def main():
        cloner = c4d.BaseObject(1018544) # cloner id
        
        cloner[c4d.MG_LINEAR_OBJECT_POSITION,c4d.VECTOR_Y] = 0
        cloner[c4d.MG_LINEAR_OBJECT_POSITION,c4d.VECTOR_Z] = 500
        cloner[c4d.MG_LINEAR_COUNT] = 10
        cloner[c4d.MGCLONER_VOLUMEINSTANCES] = True
        
        doc.InsertObject(cloner)
        newnull = c4d.BaseObject(c4d.Onull)
        newnull.InsertUnder(cloner)
        internal_cloner = c4d.BaseObject(1018544) # cloner id
        internal_cloner.InsertUnder(newnull)
        internal_cloner[c4d.ID_MG_MOTIONGENERATOR_MODE] = 3 # 3 is grid array
        internal_cloner[c4d.MG_GRID_SIZE] = c4d.Vector(300, 200, 100)
        
        cube = c4d.BaseObject(c4d.Ocube)
        cube.InsertUnder(internal_cloner)
        cube[c4d.PRIM_CUBE_LEN] = c4d.Vector(20, 10, 100)
        
        xtag = c4d.BaseTag(c4d.Texpresso) # create the xpresso tag
        cloner.InsertTag(xtag)
        
        # http://mograph.net/board/index.php?/topic/26338-creating-xpresso-nodes-with-python-script/
        nodemaster = xtag.GetNodeMaster()
        node1 = nodemaster.CreateNode(nodemaster.GetRoot(), c4d.ID_OPERATOR_OBJECT, None, 100, 100)
        node1[c4d.GV_OBJECT_OBJECT_ID] = internal_cloner
        node1out = node1.AddPort(c4d.GV_PORT_OUTPUT, (c4d.MG_GRID_RESOLUTION, c4d.VECTOR_Z))
        
        node2 = nodemaster.CreateNode(nodemaster.GetRoot(), c4d.ID_OPERATOR_OBJECT, None, 300, 100)
        node2[c4d.GV_OBJECT_OBJECT_ID] = cloner
        node2in = node2.AddPort(c4d.GV_PORT_INPUT, (c4d.MG_LINEAR_OBJECT_POSITION, c4d.VECTOR_Z))
        
        node1out.Connect(node2in)
        
        c4d.EventAdd() # refreshed viewport to see changes automatically
        # id = op.GetType()
    
    if __name__=='__main__':
        main()
    

    Unfortunately, this does not work and gives me an "AttributeError: 'NoneType' object has no attribute 'Connect'.
    When looking at the results, you can see that the first cloner never had its output port created:
    alt text
    What I'm wanting is this:
    alt text
    Can you please help me understand what I'm doing wrong in this code? Thank you.



  • "AttributeError: 'NoneType' object has no attribute 'Connect'

    means that the variable node1out is a NoneType; it is not what you think it is. That means that node1.AddPort() has returned None.

    Why AddPort() has returned None, I don't know. I can only speculate that one has to construct a more complex DescID handling MG_GRID_RESOLUTION.



  • Hi, here in Cinema 4D S22 defining the type of the cloner I don't have anymore an issue

    import c4d
    from c4d import gui
    import math
    
    def main():
        # Build Parent Cloner
        cloner = c4d.BaseObject(1018544)
        cloner[c4d.ID_MG_MOTIONGENERATOR_MODE] = c4d.ID_MG_MOTIONGENERATOR_MODE_LINEAR
        doc.InsertObject(cloner)
    
        # Build Null
        newnull = c4d.BaseObject(c4d.Onull)
        newnull.InsertUnder(cloner)
    
        # Build Children Cloner
        internal_cloner = c4d.BaseObject(1018544)
        internal_cloner[c4d.ID_MG_MOTIONGENERATOR_MODE] = c4d.ID_MG_MOTIONGENERATOR_MODE_GRIDARRAY
        internal_cloner.InsertUnder(newnull)
        internal_cloner.Message(c4d.MSG_MENUPREPARE, doc)
    
        # Cube
        cube = c4d.BaseObject(c4d.Ocube)
        internal_cloner.Message(c4d.MSG_MENUPREPARE, doc)
        cube.InsertUnder(internal_cloner)
    
        # Xpresso Tag
        xtag = c4d.BaseTag(c4d.Texpresso)
        cloner.InsertTag(xtag)
    
        # Setup Parent Cloner
        cloner[c4d.MG_LINEAR_OBJECT_POSITION, c4d.VECTOR_Y] = 0.0
        cloner[c4d.MG_LINEAR_OBJECT_POSITION, c4d.VECTOR_Z] = 500.0
        cloner[c4d.MG_LINEAR_COUNT] = 10
        cloner[c4d.MGCLONER_VOLUMEINSTANCES_MODE] = c4d.MGCLONER_VOLUMEINSTANCES_MODE_RENDERINSTANCE
    
        # Setup Children Cloner
        internal_cloner[c4d.MG_GRID_SIZE] = c4d.Vector(300, 200, 100)
    
        # Setup Cube
        cube[c4d.PRIM_CUBE_LEN] = c4d.Vector(20, 10, 100)
    
        # Setup Xpresso
        # http://mograph.net/board/index.php?/topic/26338-creating-xpresso-nodes-with-python-script/
        nodemaster = xtag.GetNodeMaster()
        node1 = nodemaster.CreateNode(nodemaster.GetRoot(), c4d.ID_OPERATOR_OBJECT, None, 100, 100)
        node1[c4d.GV_OBJECT_OBJECT_ID] = internal_cloner
        gridResParam = c4d.DescID(c4d.DescLevel(c4d.MG_GRID_RESOLUTION, c4d.DTYPE_VECTOR,0), c4d.DescLevel(c4d.VECTOR_Z, c4d.DTYPE_REAL,0))
        node1out = node1.AddPort(c4d.GV_PORT_OUTPUT, gridResParam)
    
        node2 = nodemaster.CreateNode(nodemaster.GetRoot(), c4d.ID_OPERATOR_OBJECT, None, 300, 100)
        node2[c4d.GV_OBJECT_OBJECT_ID] = cloner
        posParam = c4d.DescID(c4d.DescLevel(c4d.MG_LINEAR_OBJECT_POSITION, c4d.DTYPE_VECTOR,0), c4d.DescLevel(c4d.VECTOR_Z, c4d.DTYPE_REAL,0))
        node2in = node2.AddPort(c4d.GV_PORT_INPUT, posParam)
    
        # Connect
        if node1out is not None and node2in is not None:
            node1out.Connect(node2in)
    
        c4d.EventAdd() # refreshed viewport to see changes automatically
    
    if __name__=='__main__':
        main()
    

    And as pointed by @PluginStudent the problem was because the AddPort fails. And I guess it failed because at the time you ask for the port creation since no explicit mode was defined in the Cloner the XPresso description was not properly fed so this GvPort didn't exist.

    Cheers,
    Maxime.


Log in to reply