Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
Hi @ferdinand, Learned a couple of new tricks, almost had a good solution, but in the end it still wasn't 100% safe.. So I decided to just disable the pyTags in such a way they never would be able to initialize again. Not the nicest solution, but anyhow.. Thx for your input - consider the topic closed.
Thx @ferdinand for the input, I'll look at it as soon as I can!
Hi @ferdinand, thx for your reply. Think I've got some more investigating to do... I've been looking for message-function examples, but there aren't that many (or I use the wrong search terms:).
If anyone has some examples to get me in the right direction, it would be very much appreciated. Otherwise, just close the topic & I'll have to study harder:) Thx, J
Hi @ferdinand, Indeed the above code is checked via the main function of 1 or 2 python tags.. I’m aware of things you’re not supposed to do with a pythonTag, but sometimes it just works. I’ve been testing for over a week now with the above code in py3 & literally not a single problem
Ok, so I understand you’re not supposed to give me advise on things I shouldn’t do, but perhaps you can point me in the right direction.. I use the message function all the time for user data buttons, but how would I proceed to “catch a python tag insert” from a message (id)?
Tia, Jochem
Hi, I've got a prototype/pythonTag running in py2 & py3, where all the basics are just working fine. The problem is that python2 crashes when I try to avoid multiple "MSG" pyTags in one scene/doc...
I can only have 1 tag per scene since the pyTag adjusts the timeLine where needed. Multiple tags would fight each other..
I thought of a workaround involving 2 items set to the document container (op & op.GetObject()). The basic principle is that I know what/where to delete if a new tag is copied/inserted by the user. (The pyTag itself is set to No_Delete & No_DragNDrop)
As said, this works fine in py3 (R23/24), but I don't understand why this isn't working in py2 - for I can just read the doc.GetDataInstance & ..GetData(..) etc.
Any clues on what's causing the crash in py2? (and as a sub-question - is there a smarter way to ensure 1 specific tag per scene?..)
See the check_single_pytag() func below. Tia, Jochem
def set_doc_bc(uniqueId): doc = op.GetDocument() docBC = doc.GetDataInstance() subBc = c4d.BaseContainer() subBc[123] = op subBc[124] = op.GetObject() docBC.SetContainer(uniqueId, subBc) doc.SetData(docBC) def check_single_pytag(): # check pyTag(s) - for there can be only one.. doc = op.GetDocument() docBC = doc.GetDataInstance() uniqueId = 12345 # not this :) def new_null(): # small local func to set pyTag to a new null.. nully = c4d.BaseObject(c4d.Onull) nully.InsertBefore(op.GetObject()) nully.SetName("MSG") nully[c4d.NULLOBJECT_DISPLAY] = 14 # none nully.InsertTag(op) op[c4d.ID_USERDATA,52] = nully op.Message(c4d.MSG_UPDATE) try: docBcTag = doc.GetDataInstance()[uniqueId].GetData(123) if docBcTag == op: pass # original tag, so skip elif not docBcTag.GetDocument(): # orginal tag deleted - set a new one new_null() set_doc_bc(uniqueId) else: # UD52 = linkfield on pyTag with op.GetObject() if op[c4d.ID_USERDATA,52] == None or op.GetObject() == doc.GetDataInstance()[uniqueId].GetData(124): op.Remove() # 2nd tag on original pyNull - remove return False else: # new/copied tag - remove all.. op.GetObject().Remove() return False except AttributeError: # no tag in doc yet.. new_null() set_doc_bc(uniqueId) return True
Hi @m_magalhaes,
No there's still a problem, but for now it seams to be unsolvable.. It would be nice if C4D would allow for priority changes on the skin deformer - for polygon objects.
Hi @ferdinand, I was working on a similar topic, trying to change the prio of skin deformers to "after dynamics"... (didn't want to start a new thread, thx for replying anyway:)
Hmmm… some extra notes: Although it’s possible to change the priority of skin deformers - it’s of no use. The documentation states that priorities only will be applied if the “Force” option under “Include” is turned on. But that’s not for polygon objects.
So in my case, I wanted to set skin deformers after dynamics had been applied, but that’s a no-go. The only alternative I found was to add an extra pythonTag (Gen.412), which updated all meshes. This means that on render time all works well, but in the viewport it will still lag 1 frame
Hi, @m_magalhaes & the rest, Joints & skins work a bit differently than setting priorities in the usual way.. Basically, only the first line changes @ the "declaration" of pd.
Hope this helps, Jochem
for item in items: # .. a list with objects or tags.. # prioGeneric pd = item[c4d.EXPRESSION_PRIORITY] pd.SetPriorityValue(c4d.PRIORITYVALUE_MODE, 4) # 4 = Generators (as an example..) pd.SetPriorityValue(c4d.PRIORITYVALUE_PRIORITY, 412) item[c4d.EXPRESSION_PRIORITY] = pd for j in joints: # .. a list with joints.. # prioJoints pd = j[c4d.ID_CA_JOINT_OBJECT_PRIORITY] pd.SetPriorityValue(c4d.PRIORITYVALUE_MODE, 4) pd.SetPriorityValue(c4d.PRIORITYVALUE_PRIORITY, 413) j[c4d.ID_CA_JOINT_OBJECT_PRIORITY] = pd for s in skins: # .. a list with skins.. # prioSkins pd = s[c4d.ID_CA_SKIN_OBJECT_PRIORITY] pd.SetPriorityValue(c4d.PRIORITYVALUE_MODE, 4) pd.SetPriorityValue(c4d.PRIORITYVALUE_PRIORITY, 414) s[c4d.ID_CA_SKIN_OBJECT_PRIORITY] = pd
So, now we have a maxon.Int :} Yes, the system is working - thx @m_adam Consider it solved // more info in general on the maxon framework - especially on the python side - would we be welcome..
Hi @m_adam, thx for your input, it does reset the WeightManager, but doesn’t do the autoWeighting accordingly..
_First thing I noticed: a difference between int 64 & 32. Not sure if this might be a problem.. Reading the GET> AutoWeight…base.jointcount : <int64> “number of joints” Reading the SET> AutoWeight…base.jointcount : <int32> “number of joints”
_After the WeightManager is being set (to 1 joint in my case), I can’t click on the “Calculate button” manually. Nothing happens, unless I change the joint count manually to another number. So something in the update hasn’t been applied.. Note that reading the dict says <int32>, until manually changed, than is says <int64> again..
_I also tried wmgr.SetDirty(doc) / wmgr.Update(doc) / followed by another c4d.EventAdd().. Perhaps these need a different approach as well? I tried to find something in the “maxon/frameworks” folders you linked to, but couldn’t find any info on how to tackle this issue.
So the current status is still that “default weighting” is applied. If you can please help in the right direction, it would be greatly appreciated, tia, Jochem
import c4d, maxon from maxon.frameworks import animation def main(): doc = c4d.documents.GetActiveDocument() wmgr = c4d.modules.character.CAWeightMgr #wmgr.SetDirty(doc) heatmap_id = wmgr.GetAutoWeightAlgoId(doc, 1) # heatmap settings = wmgr.GetAutoWeightDictionary(doc, heatmap_id) settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.JOINTCOUNT, 1) settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.SELECTEDPOINTS, False) settings.Set(maxon.frameworks.animation.AUTOWEIGHTPARAMETERS.ALLOWZEROLENGTH, False) wmgr.SetAutoWeightDictionary(doc, settings, heatmap_id) #doc.ExecutePasses(None,True,True,True,flags=c4d.BUILDFLAGS_NONE) c4d.EventAdd() # getWeightTag - setActive firstJoint = doc.GetFirstObject().GetDown().GetDown() # just in my testDoc.. weightTag = (firstJoint.GetWeightTag())["op"] doc.SetActiveTag(weightTag, c4d.SELECTION_NEW) #weightTag.GetObject().SetBit(c4d.BIT_ACTIVE) # update weightManager / doesn't make any difference.. #wmgr.SetDirty(doc) #wmgr.Update(doc) #c4d.EventAdd() # autoWeight func wmgr.SelectAllJoints(doc) bla = wmgr.AutoWeight(doc) print(bla) # prints True, but not in the right way :{ c4d.EventAdd() if __name__=='__main__': main()
Super, thx a lot! Will check first thing in the morning :}
For a particular setup in R23/24, I’m trying to restrict the auto weighting to 1 joint - to avoid blending between weights (which will save me trouble down the line..).
Since R21 the “ID_CA_WEIGHT_MGR_AUTOWEIGHT_JOINTS” is removed so I can’t set it directly (see the simplified code below).
I tried to figure out a workaround, with no luck. My thought was that if I could read the autoweightDictonary, I could also set it. The function “GetAutoWeightDictionary” needs a stringId (which is a maxon.Id, but that didn’t help me any further..)
So, the main question: How can I set the amount of Joints (to 1) when autoweighting? And of course I don’t mean mannualy :} tia, Jochem
import c4d, maxon def message(id, data): if id == c4d.MSG_DESCRIPTION_COMMAND: id2 = data['id'][0].id if id2 == c4d.ID_USERDATA: userDataId = data['id'][1].id if userDataId == 1: accessWM() c4d.EventAdd() def accessWM(): doc = op.GetDocument() for tag in op.GetObject().GetTags(): if tag.GetType() == 1019365: wTag = tag doc.SetActiveTag(wTag, c4d.SELECTION_NEW) wmgr = c4d.modules.character.CAWeightMgr wmgr.SetParameter(doc,c4d.ID_CA_WEIGHT_MGR_AUTOWEIGHT_MODE,1) # heatmap wmgr.SetParameter(doc,c4d.ID_CA_WEIGHT_MGR_AUTOWEIGHT_IN_BIND_POSE,True) # ID_CA_WEIGHT_MGR_AUTOWEIGHT_JOINTS // removed since R21 :{ wmgr.AutoWeight(doc) wmgr.Update(doc) """ hmmm1 = wmgr.GetAutoWeightDictionary(doc, maxon.Id("AutoWeight")) hmmm2 = wmgr.GetAutoWeightDictionary(doc, maxon.Id) print (hmmm1, type(hmmm1)) print (hmmm2, type(hmmm2)) # both print: <class 'maxon.reference.DataDictionary'> """ def main(): pass
Below gets the focus back on the first tab of the pyTag (after other objects have been selected), but it only works with/after a button click.. Perhaps this might be of use.
def message(id, data): if id == c4d.MSG_DESCRIPTION_COMMAND: id2 = data['id'][0].id if id2 == c4d.ID_USERDATA: userDataId = data['id'][1].id if userDataId == 1: # << just a button on the pyTag with ID 1 ### do some function... # GET FOCUS BACK on the pyTags's 1st Tab: op.GetObject().SetBit(c4d.BIT_ACTIVE) op.SetBit(c4d.BIT_ACTIVE) c4d.gui.ActiveObjectManager_SetObject(c4d.ACTIVEOBJECTMODE_TAG, op.GetObject(), c4d.ACTIVEOBJECTMANAGER_SETOBJECTS_OPEN, c4d.DescID(c4d.DescLevel(1))) op.GetObject().DelBit(c4d.BIT_ACTIVE) c4d.EventAdd()
@zipit Yes, thx - the system works :}
@m_adam Thx anyway, hope to hear from you one day... all the best for the next year
@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.
@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
@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.