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

    Wrong random clone displayed issue

    Cinema 4D SDK
    python r23 s22
    3
    11
    1.8k
    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.
    • jochemdkJ
      jochemdk
      last edited by

      Ok, here’s a thing you normally don’t notice when using a cloner with random clones, because random is random, right?.. Under certain circumstances the clones displayed in the viewport don’t correspond with the indices they are supposed to be.

      This is noticeable if you manually turn off & on a/the effector, hence giving only the correct display after the toggle.

      Well, this is not about manual things. For a lot of reasons it’s very important to me to know exactly which clone is which. So, I made a “hack” to get the right results…

      See preview below for a simple example with index 2 selected in the moSelectionTag which is used in the plainEffector to hide the clone. Notice the nrs in the console - which I think are correct & don’t correspond with the viewport in the last 2 images..

      _Left_image: all goes well because the cloners offset is smaller than the “hidden index 2”.
      _Middle_image: here is where it goes wrong. The cloners offset passes index 2 (offset >= 3) and incorrect clones are shown.
      _Right_image: going back to offset 2 also shows the incorrect children.
      Once going to offset 1 everything is fine again - or after dis-/enabling the effector...

      random_clone_effector_moselection_issue_01.jpg

      So, none of this happens if I apply my “hack” in the script below which turns every effector off/on to get the right result.

      Isn’t there a more elegant solution for this?
      Is it a bug, or is it me?..

      import c4d, math
      from c4d.modules import mograph
      from c4d import utils
      
      
      def main():
          moObj = op.GetObject() # cloner > with a pyTag
          
          ##### ----- #####
          useHack = True # use a "hack", turning effector(s) on/off to get the correct random results..
          if useHack == True:
              doc = op.GetDocument()
              inex = moObj[c4d.ID_MG_MOTIONGENERATOR_EFFECTORLIST]
              for i in range(inex.GetObjectCount()):
                  effector = inex.ObjectFromIndex(doc, i)
                  effector[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = False
                  effector[c4d.ID_BASEOBJECT_GENERATOR_FLAG] = True
                  effector.Message(c4d.MSG_UPDATE)
          ##### ----- #####
          
          moData = mograph.GeGetMoData(moObj)
          moCount = moData.GetCount()
          moFlags = moData.GetArray(c4d.MODATA_FLAGS)
          moChil = moData.GetArray(c4d.MODATA_CLONE)
          
          dirChil = len(moObj.GetChildren())
          dirMod = 1/float(dirChil)
      
          for i in range(moCount):
              if moFlags[i] != 1: print ("-fl->", moFlags[i])
              elif moFlags[i] == 1:
                  # method 1
                  dirInst = int(math.floor(moChil[i]/dirMod))
                  if dirInst == dirChil: dirInst -= 1
                  # method 2 
                  childIdx = int(math.floor(utils.ClampValue(moChil[i] * dirChil, 0, dirChil-1)))
                  print ("-fl->", moFlags[i], "-m1->", dirInst, "-m2->", childIdx)
          print ("-----")
      

      Note: there are 2 methods in the script to get the right index for the clone. The 2nd method I found on this page: https://developers.maxon.net/forum/topic/10032/13500_identify-name-of-clone-source-at-index/2 which I used as a sanity check. Both methods display the same indices, so effectively there’s no difference.

      Also, a simple c4d file attached for testing purposes (R23). By the way, the above happens exactly the same in S22.

      _tstCloneIdx_S23_01.c4d

      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by

        Hi @jochemdk, thanks a lot looks like you found a bug. I opened a bug report to our development team 🙂

        Another workaround is to use the effector not to define the visibility of an object but to define its scale to absolute 0.
        This is more efficient since you don't have to re-enable the effector (which can be an issue and cause other dirty issues) since the effector needs to change the data generated by the cloner.

        Cheers,
        Maxime.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        jochemdkJ 3 Replies Last reply Reply Quote 0
        • jochemdkJ
          jochemdk @m_adam
          last edited by

          @m_adam
          Thx 🙂 I thought it was a bug... I know how to control stuff myself, but this is about catching all kinds of things from "some" user's hierarchy - including cloners in cloners and animated moSelections/Weights.

          1 Reply Last reply Reply Quote 0
          • jochemdkJ
            jochemdk @m_adam
            last edited by

            This post is deleted!
            1 Reply Last reply Reply Quote 1
            • jochemdkJ
              jochemdk @m_adam
              last edited by

              @m_adam
              Hi, I did some more testing…

              Things only go wrong with a linearCloner’s offset if:
              _ any applied baseEffector has the visibility check turned on
              _ has a mograph selection/weight tag
              _ and if a linearCloner’s offset >= the smallest index of the selection
              _ (so random has nothing to do with it 🙂

              1 Reply Last reply Reply Quote 1
              • M
                m_adam
                last edited by

                Thanks a lot for your additional testing, I will for sure attach it to the bug report 🙂

                MAXON SDK Specialist

                Development Blog, MAXON Registered Developer

                jochemdkJ 1 Reply Last reply Reply Quote 0
                • jochemdkJ
                  jochemdk @m_adam
                  last edited by jochemdk

                  @m_adam
                  Hi Maxime, One additional remark + a question…

                  I’m trying to build a minimum set of rules to avoid the dis/enabling of effectors if not really necessary. I can’t use moFlags to check whether a clone is visible or not, and that’s where the issue might be:

                  1_ Given the example in the previous post (with offset 2), the moFlags read something like [2,2,2,1,0,1,…..]. Flag 2 being “permanently disabled”. If it means that behind the scenes index 2 is totally ignored, this is where the problem might be…

                  2A_ So reading moFlags doesn’t give me the info I need. For the moSelections I was able to find the first index of an invisible clone via “baseSelection.GetAll(count)”. So everything fine here…

                  2B_ I’ve spend many hours trying to find a formula to find the (first) invisible clone with moWeights. Given any weight float value between 0 & 1, a clone gets invisible based on the strength & maximum value sliders (which are not limited and can go way past +/- 100%..).

                  The question: What is the formula (with strength & maximum) to check whether a weighted clone gets invisible?

                  Tia, Jochem
                  (If you want I can start a new thread, but this is so closely related…)

                  One function added in the script below:

                  """ After some code I know which linearCloners have a moSel/Weight tag with the same name as the baseEffector selection string... 
                  Per effector - with visibility turned on - I run the func below to check what the minimal offset is (for multiple cloners) & 
                  return "update" True if the minOffset is >= the selection index where a clone gets invisible... 
                  The passed moSelDict has selection strings as keys & indices of an inexList as values.
                  """
                  def checkUpd(effector, moSelDict):
                      minOff = 999999
                      minSelIdx = 999998
                      for moInd in moSelDict[effector[c4d.ID_MG_BASEEFFECTOR_SELECTION]]:
                          moObj = op[c4d.ID_USERDATA,5].ObjectFromIndex(doc,moInd) # moObj = cloner / index from a linearCloner in-exclusion list..
                          if moObj[c4d.MG_LINEAR_OFFSET] < minOff: minOff = moObj[c4d.MG_LINEAR_OFFSET]
                          for tag in moObj.GetTags():
                              if tag.CheckType(1021338) and tag.GetName() == effector[c4d.ID_MG_BASEEFFECTOR_SELECTION]: # selection
                                  bs = mograph.GeGetMoDataSelection(tag)
                                  count = moObj[c4d.MG_LINEAR_COUNT] + moObj[c4d.MG_LINEAR_OFFSET]
                                  try: minSel = bs.GetAll(count).index(1) # << here is where I can find the correct (in)visible selection values for moSelections
                                  except ValueError: break # selectionTag with no selection..
                                  if minSel < minSelIdx: minSelIdx = minSel
                                  break
                              elif tag.CheckType(440000231) and tag.GetName() == effector[c4d.ID_MG_BASEEFFECTOR_SELECTION]: # weight
                                  strength = effector[c4d.ID_MG_BASEEFFECTOR_STRENGTH]
                                  maximum = effector[c4d.ID_MG_BASEEFFECTOR_MAXSTRENGTH]
                                  
                                  # WHAT IS THE FORMULA TO GET (IN)VISIBLE STATE OF A WEIGHTED CLONE, BASED ON THE 2 VALUES ABOVE?..
                                  
                                  bs = mograph.GeGetMoDataWeights(tag)
                                  minSel = 999999
                                  for w in range(len(bs)):
                                      if bs[w] > 0.0: # << this is of course not optimal :)
                                          minSel = w
                                          break
                                  if minSel < minSelIdx: minSelIdx = minSel
                                  break
                          if minOff >= minSelIdx: return True
                      return False
                  

                  Edit:
                  It turns out I need a formula for the strength/maximum values for the moSelection version as well. I plotted some values (in excel:) for various combinations of strength/maximum with moSelections/moWeights. All show an exponential growth(/decay) curve... I know you're not supposed to write scripts for others, but if you've got some code lying around - it would be brilliant.

                  1 Reply Last reply Reply Quote 0
                  • M
                    m_adam
                    last edited by m_adam

                    Hi sorry for the late reply,

                    Just to let you know I'm still on it.

                    For the moment I didn't found such a formula.
                    There are multiple passes to calculate the real strength then at the end there is SetBit(mdflags[i], MOGENFLAG_CLONE_ON, vis > 0.5_f);

                    But I will keep searching since for the moment I only looked at how Mograph works in general and not particularity to the linear Cloner.

                    Note that since workaround exists (aka setting clone scale to absolute -1), I do this research as low-priority (so when I get time)

                    Cheers,
                    Maxime.

                    MAXON SDK Specialist

                    Development Blog, MAXON Registered Developer

                    jochemdkJ 1 Reply Last reply Reply Quote 0
                    • jochemdkJ
                      jochemdk @m_adam
                      last edited by

                      @m_adam
                      Thx anyway, hope to hear from you one day... all the best for the next year

                      1 Reply Last reply Reply Quote 0
                      • M
                        m_adam
                        last edited by

                        Hi, unfortunately, I didn't get the time to get back to the topic, and I'm pretty doubtfully to find time for it, as a workaround exist (of course this is far from perfect but I can't do more)

                        There is no clear formula but it's a mixture of multiple layers of Addition + Removal according to some conditions, which makes it very hard to produce a clear formula over the result.

                        Sorry, I hope you didn't have too much hope regarding my investigation.
                        Cheers,
                        Maxime.

                        MAXON SDK Specialist

                        Development Blog, MAXON Registered Developer

                        1 Reply Last reply Reply Quote 0
                        • ferdinandF
                          ferdinand
                          last edited by

                          Hi @jochemdk,

                          without further questions or feedback, we will consider this thread as solved by Monday and flag it accordingly.

                          Cheers,
                          Ferdinand

                          MAXON SDK Specialist
                          developers.maxon.net

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