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...
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
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
##### ----- #####
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)
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://plugincafe.maxon.net/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.
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);
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)
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.
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.
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
Thanks a lot for your additional testing, I will for sure attach it to the bug report
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?
(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
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
if minSel < minSelIdx: minSelIdx = minSel
if minOff >= minSelIdx: return True
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.
Thx anyway, hope to hear from you one day... all the best for the next year
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.
without further questions or feedback, we will consider this thread as solved by Monday and flag it accordingly.