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).
@bentraje I misunderstood your question in my previous reply. This is my trial:
import c4d with open(r"Path\to\your\file.json") as f: c4d.CopyStringToClipboard(f.read()) # Paste command in Node Editor # Command ID can be got by Script Log c4d.CallCommand(465002305)
@mats
Maybe you should call the Set Inital State button of the tag and set the local offset vector as the target's negative vector. Here's the code:
Set Inital State
import c4d objList = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_SELECTIONORDER | c4d.GETACTIVEOBJECTFLAGS_CHILDREN) tag = c4d.BaseTag(c4d.Tcaconstraint) obj1, obj2 = objList[:2] obj1.InsertTag(tag) c4d.CallButton(tag, c4d.ID_CA_CONSTRAINT_TAG_SET_INITIAL_STATE) # SET INITIAL STATE tag[c4d.ID_CA_CONSTRAINT_TAG_PARENT] = True tag[30009, 1000] = obj2[c4d.ID_BASEOBJECT_REL_POSITION] * -1 # Local Offset P tag[30001] = obj2 # Target c4d.EventAdd()
There is a third-party module to serialize and deserialize the user data of any BaseList2D object in python dict format. Here's an example:
BaseList2D
c4d.ID_USERDATA: { (c4d.ID_USERDATA, 1): { c4d.DTYPE_: c4d.DTYPE_REAL, c4d.DESC_NAME: 'Data', c4d.DESC_SHORT_NAME: 'Data', c4d.DESC_MIN: 0, c4d.DESC_MAX: 1, c4d.DESC_STEP: 0.01, c4d.DESC_UNIT: c4d.DESC_UNIT_PERCENT, c4d.DESC_CUSTOMGUI: c4d.CUSTOMGUI_REAL, c4d.DESC_PARENTGROUP: (700, 5, 0), }, (c4d.ID_USERDATA, 2): { c4d.DTYPE_: c4d.DTYPE_GROUP, c4d.DESC_NAME: 'Group', c4d.DESC_SHORT_NAME: 'Group', c4d.DESC_ANIMATE: c4d.DESC_ANIMATE_OFF, c4d.DESC_COLUMNS: 1, c4d.DESC_TITLEBAR: 1, c4d.DESC_DEFAULT: 1, c4d.DESC_PARENTGROUP: (), }, (c4d.ID_USERDATA, 3): { c4d.DTYPE_: c4d.DTYPE_LONG, c4d.DESC_NAME: 'Data', c4d.DESC_SHORT_NAME: 'Data', c4d.DESC_UNIT: c4d.DESC_UNIT_INT, c4d.DESC_CUSTOMGUI: c4d.CUSTOMGUI_LONGSLIDER, c4d.DESC_MIN: 0, c4d.DESC_MAX: 100, c4d.DESC_STEP: 1, c4d.DESC_PARENTGROUP: ((700, 5, 0), (2, 1, 0)), }, }
The module is not fully tested, but it's enough for me for my daily scripting work. The processing of parameters is implemented in a way described by @ferdinand . Sort of like the .res file used by plugins developing, the json data defines the details of a parameter. If you feel like it, you can implement it yourself by refering to following functions: DumpParams DumpParamDetails DumpUserDataDetails LoadUserData ... Considering sometimes there's a huge amount of parameters, I spent a lot of time to judge and handle dirty parameters, namely the parameter has been changed, there is still no perfect way. If you don't care whether the parameter is dirty, problem goes easier. Maybe do some filters by restricting DescLevel.creator to a specific value etc.
.res
DescLevel.creator
Hello @vannipo , What you need may not a plugin, scripts is enough. In Command Manager, search your script's name, then assign the shortcut you like. Assign a shortcut key to each of your nine scripts, You can even drag the item out of the list tree view and turn it into a button.
Command Manager
Hi, @bentraje For each parameter input box, formula expressions are supported in c4d, x : represents the parameter's current value. If you want to change the intensity by 125% than their current value for each light, you can select all of them and simply input x * 1.25 . The document for Expanded Formula Entry by Multiple Selections is here:
x
x * 1.25
@ferdinand Thanks, you are the best. This is exactly the internal operation I'm finding.
@ferdinand The Constrain Tag may not only influence position, but also rotation, scale. I think the set inital state button should be called as mentioned in my first reply:
set inital state
c4d.CallButton(tag, c4d.ID_CA_CONSTRAINT_TAG_SET_INITIAL_STATE) # SET INITIAL STATE
tag[30009,1000] = -parent.GetRelPos() #? tag[30009,1001] = -parent.GetRelScale() #? tag[30009,1002] = -parent.GetRelRot() #?
@ferdinand I verified the scene again, the two methods do the same thing indeed. Forgive my mistakes last post. The problem is when the parent is not at original position, after apply the script, the offset arises. The selection order might also affect the result. I'm trying to figure it out.
@ferdinand @Mats I compared the two pieces of code and found the key diffence is the lines of creating the Constraint Tag: When you using MakeTag, c4d will do some internal operations I guess:
MakeTag
tag: c4d.BaseTag = child.MakeTag(c4d.Tcaconstraint)
While using BaseTag constructor, then InsertTag, no internal operations are done:
BaseTag
InsertTag
tag = c4d.BaseTag(c4d.Tcaconstraint) child.InsertTag(tag)
In my experience, for the most cases of tags, both of them work properly, apart from the above exception.
@joel What you mentioned now is available in c4d 2023 version. Here is the link: Cinema 4D SDK 2023.1.0 documentation
@joel The simplest way is to drag the parameter to the python console, then you could get desclevel id without dtype and creator. e.g.c4d.DescID(1500). If you want to get the DescID programmatically. I wrote a function to list all parameters and detail descriptions of an object. This may help you.
c4d.DescID(1500)
import c4d def find_ident(value: int, prefix=""): for key, val in c4d.__dict__.items(): if val == value and key.startswith(prefix): return f"c4d.{key}" def dump_params(obj: c4d.BaseList2D): def dump_param_desc(bc): for k, v in bc: ident = find_ident(k, "DESC_") if type(v) == str: v = repr(v) if not ident: continue if k == c4d.DESC_UNIT: v = find_ident(v, "DESC_") if k == c4d.DESC_CUSTOMGUI: v = find_ident(v, "CUSTOMGUI") or v if isinstance(v, c4d.Vector) and abs(v.x) > 1e10: v = "Vector" print('\t', ident, ":", v) description = obj.GetDescription(c4d.DESCFLAGS_DESC_0) descid: c4d.DescID for bc, descid, _ in description: name = bc[c4d.DESC_NAME] or bc[c4d.DESC_SHORT_NAME] if not name: continue if descid[descid.GetDepth() - 1].dtype == c4d.DTYPE_GROUP: print("---------") print(name, descid, ":", repr(obj[descid])) dump_param_desc(bc) if bc[c4d.DESC_CUSTOMGUI] == c4d.CUSTOMGUI_SUBDESCRIPTION: for subvector in [c4d.VECTOR_X, c4d.VECTOR_Y, c4d.VECTOR_Z]: subdescid = c4d.DescID(*[descid[i] for i in range(descid.GetDepth())]) subdescid.PushId(c4d.DescLevel(subvector)) subbc = description.GetParameter(subdescid) name = subbc[c4d.DESC_NAME] or subbc[c4d.DESC_SHORT_NAME] if not name: continue name = name.replace(" . ", ".") print(name, ":", obj[subdescid]) dump_param_desc(subbc) if __name__ == "__main__": obj = doc.GetActiveObject() dump_params(obj)
Following is the outputs to the end:
Effectors (2009, 1009290, 1018639) : <c4d.InExcludeData object at 0x00000198DD88E9C0> c4d.DESC_NAME : 'Effectors' c4d.DESC_SHORT_NAME : 'Effectors' c4d.DESC_VERSION : 3 c4d.DESC_ANIMATE : 0 c4d.DESC_CUSTOMGUI : c4d.CUSTOMGUI_INEXCLUDE_LIST c4d.DESC_ACCEPT : <c4d.BaseContainer object at 0x00000198DD88DE00> c4d.DESC_IDENT : 'ID_MG_MOTIONGENERATOR_EFFECTORLIST' Plain (1500, 19, 1018544) : 0.99 c4d.DESC_NAME : 'Plain' c4d.DESC_SHORT_NAME : 'Plain' c4d.DESC_VERSION : 3 c4d.DESC_MIN : -1e+20 c4d.DESC_MAX : 1e+20 c4d.DESC_MINEX : 0 c4d.DESC_MAXEX : 0 c4d.DESC_STEP : 0.01 c4d.DESC_ANIMATE : 1 c4d.DESC_UNIT : c4d.DESC_UNIT_PERCENT c4d.DESC_CUSTOMGUI : c4d.CUSTOMGUI_REALSLIDER c4d.DESC_MINSLIDER : 0.0 c4d.DESC_MAXSLIDER : 1.0 c4d.DESC_REMOVEABLE : 0 Plain.1 (1501, 19, 1018544) : 1.0 c4d.DESC_NAME : 'Plain.1' c4d.DESC_SHORT_NAME : 'Plain.1' c4d.DESC_VERSION : 3 c4d.DESC_MIN : -1e+20 c4d.DESC_MAX : 1e+20 c4d.DESC_MINEX : 0 c4d.DESC_MAXEX : 0 c4d.DESC_STEP : 0.01 c4d.DESC_ANIMATE : 1 c4d.DESC_UNIT : c4d.DESC_UNIT_PERCENT c4d.DESC_CUSTOMGUI : c4d.CUSTOMGUI_REALSLIDER c4d.DESC_MINSLIDER : 0.0 c4d.DESC_MAXSLIDER : 1.0 c4d.DESC_REMOVEABLE : 0
Then you can get the DescID: c4d.DescID(c4d.DescLevel(1500, 19, 1018544))
c4d.DescID(c4d.DescLevel(1500, 19, 1018544))