Identify name of clone source at index

  • On 23/03/2017 at 14:02, xxxxxxxx wrote:

    I'm playing about with python effectors again, trying to figure out best approach to controlling clones based on their source object names..

    I made a cloner with a range of motext objects inside; 0 .. 9, a.. b, A.. B

    My end goal is to be able to set clones to specific characters at specific indices.

    So far I have found out about the MODATA_CLONE id value, which defines which cloner child object  to use at the specified index.

    This is sort of useful I think, but is it the best method for what I want; 
    Since I couldn't find any easy way to access the name (maybe I missed something obvious?)
    I am trying to figure out a way to do it with this MODATA_CLONE value:

    I could get all the childs of the cloner object, as an array, look up the letter which I would like to set at a specific index in the cloner, using something like:

    def getCValue(childArray, letter) :
        length = len(childArray)
        for i, L in enumerate(childArray) :
            if str(letter) in L.GetName() :
                return float(i)/length

    then to set the new values

        childs = clonerObj.GetChildren()
        value = getCValue(childs, "a")
        md.SetArray(c4d.MODATA_CLONE, fillArray(value, cnt),True)

    This works, but very dodgy-ly as you might imagine, most of the letters work and set the correct clones but sometimes it doesn't work and it's off by one character, I assume because its not quite matching up with the float value which the cloner uses.

    Is there a more surefire way to get/set which object is used at a specific index?
    Is this the best way to do this?
    Thanks for your time!

  • On 24/03/2017 at 06:53, xxxxxxxx wrote:


    The formula to get the index of a MoGraph generator's child object from a float value in MODATA_CLONE is:

    cloneIndex = floor(clamp(cloneValue * numChildren, 0, numChildren-1))

    Here is a Python effector code that prints these indices and the children names:

    import c4d
    from c4d import utils
    from c4d.modules import mograph as mo
    import math
    def main() :
        md = mo.GeGetMoData(op)
        if md is None: return
        children = gen.GetChildren()
        numChildren = len(children)
        if numChildren == 0: return
        mdCount = md.GetCount()
        mdClone = md.GetArray(c4d.MODATA_CLONE)
        for cloneIdx in xrange(mdCount) :
            childIdx = int(math.floor(utils.ClampValue(mdClone[cloneIdx] * numChildren, 0, numChildren-1)))
            print childIdx, children[childIdx].GetName()

    Note 'gen' variable is the generator object that uses the Python effector.
    Also the code has to be executed in a Python effector set to Full Control mode.

    About the offset by one character, add a half step to the new value to set in the MODATA_CLONE array. This half step value would be 1.0/numChildren.

  • On 24/03/2017 at 10:36, xxxxxxxx wrote:

    Hi Yannick!
    Thanks so much for the advice, this is excellent.
    Great idea to use ClampValue.

    I ended up doing +0.5 / numChildren, 1.0 seemed to make it worse, but 0.5 seems perfect..

    def clonerString(childArray, iString, cCount) : #cCount = clones count
        length = len(childArray)
        myList = [0.0] * cCount
        for i, c in enumerate(iString) :
            for j, L in enumerate(childArray) :
                if str(c) in L.GetName() :
                    myList[i] = float(j)/length + 0.5/length
        return myList

Log in to reply