• Priority Delay on Stacking Skin Deformers

    Cinema 4D SDK r21 python
    16
    0 Votes
    16 Posts
    2k Views
    B
    Hi, Just checking if this is now resolved in the current version of C4D (2023).
  • Unable to Set Priority Data for Skin Deformer

    Cinema 4D SDK r21 python
    6
    0 Votes
    6 Posts
    690 Views
    ManuelM
    @zipit said in Unable to Set Priority Data for Skin Deformer: probably overlooked correct, friday evening
  • Unusual "NoneType" Error for GetDeformCache()

    Cinema 4D SDK r21 python
    12
    0 Votes
    12 Posts
    2k Views
    B
    Hi @m_magalhaes Ah gotcha. I guess I can't change the deformer's priority. Anyhow. Thanks for the confirmation.
  • 0 Votes
    5 Posts
    1k Views
    B
    Thank you very much, Manuel! This is a working solution for the issue and it helped me a lot! Best regards, Tim
  • 0 Votes
    19 Posts
    2k Views
    ManuelM
    hi, never say never. Sorry for the delay, this is a "unusual" case ^^ I did try several options (observable, notification, message etc) I finished using the function AddEventNotification witch is private. (so i had to figure out how it was working) The shader and the viewport is updated but with a small latency. We can try to improve that solution if you want or you can go with your own. Below the code for both the ObjectData and the Shader. The shader need to register to be notified. (this is automatic, nothing to add on the ObjectData's side) Than you need to check the message in Message I feel that the important part is to remove the notification and re/add it. (not sure what it can do if you don't do it ^^) class pc12019_object : public ObjectData { INSTANCEOF(pc12019_object, ObjectData); public: static NodeData* Alloc() { return NewObjClear(pc12019_object); } BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) override { return BaseObject::Alloc(Ocube); } Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) override { if (!description->LoadDescription(Obase)) return false; const DescID* singleid = description->GetSingleDescID(); const DescID cid = DescLevel(OBJ_COLOR, DTYPE_COLOR, 0); if (!singleid || cid.IsPartOf(*singleid, nullptr)) { BaseContainer bc = GetCustomDataTypeDefault(DTYPE_COLOR); bc.SetString(DESC_NAME, "Color"_s); bc.SetData(DESC_GUIOPEN, true); description->SetParameter(cid, bc, DescLevel(ID_OBJECTPROPERTIES)); } flags |= DESCFLAGS_DESC::LOADED; return SUPER::GetDDescription(node, description, flags); } }; class pc12019_shader : public ShaderData { INSTANCEOF(pc12019_shader, ShaderData); public: static NodeData* Alloc() { return NewObjClear(pc12019_shader); } Vector Output(BaseShader* sh, ChannelData* cd) override { return color; } Bool Read(GeListNode* node, HyperFile* hf, Int32 level) override { // need to read the color return true; } Bool Write(GeListNode* node, HyperFile* hf) override { // need to write the color return true; } Bool CopyTo(NodeData* dest, GeListNode* snode, GeListNode* dnode, COPYFLAGS flags, AliasTrans* trn) override { pc12019_shader* destShader = static_cast<pc12019_shader*>(dest); destShader->color = color; return true; } Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) override { if (!description->LoadDescription(Xbase)) return false; const DescID* singleid = description->GetSingleDescID(); DescID cid = DescLevel(SH_OBJECTLINK, DTYPE_BASELISTLINK, 0); if (!singleid || cid.IsPartOf(*singleid, nullptr)) { BaseContainer bc = GetCustomDataTypeDefault(DTYPE_BASELISTLINK); bc.SetString(DESC_NAME, "Link"_s); bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_LINKBOX); BaseContainer ac; ac.SetInt32(Obase, 1); bc.SetContainer(DESC_ACCEPT, ac); description->SetParameter(cid, bc, DescLevel(ID_SHADERPROPERTIES)); } flags |= DESCFLAGS_DESC::LOADED; return SUPER::GetDDescription(node, description, flags); } INITRENDERRESULT InitRender(BaseShader* sh, const InitRenderStruct& irs) override { iferr_scope_handler { err.DiagOutput(); return INITRENDERRESULT::UNKNOWNERROR; }; if (irs.doc == nullptr) return INITRENDERRESULT::OK; BaseContainer* bcShader = sh->GetDataInstance(); if (bcShader == nullptr) return INITRENDERRESULT::UNKNOWNERROR; BaseObject * linkedObject = bcShader->GetObjectLink(SH_OBJECTLINK, irs.doc); if (linkedObject == nullptr) return INITRENDERRESULT::OK; RemoveNotification(sh, linkedObject); AddNotification(sh, linkedObject); GeData data; linkedObject->GetParameter(OBJ_COLOR, data, DESCFLAGS_GET::NONE); color = data.GetVector(); return INITRENDERRESULT::OK; } Bool Init(GeListNode* node) override { BaseMaterial* mat = static_cast<BaseMaterial*>(node); BaseContainer* bc = mat->GetDataInstance(); bc->SetLink(SH_OBJECTLINK, nullptr); return true; } void Free(GeListNode* node) override { GeData data; BaseObject* op = static_cast<BaseObject*>(node); if (op == nullptr) return; BaseDocument* doc = node->GetDocument(); if (doc == nullptr) return; op->GetParameter(SH_OBJECTLINK, data, DESCFLAGS_GET::NONE); BaseList2D* linkedObject = data.GetLink(doc); RemoveNotification(node, linkedObject); } Bool RemoveNotification(GeListNode* node, BaseList2D* linkedObject) { if ((node == nullptr) || (linkedObject == nullptr)) return false; BaseObject* op = static_cast<BaseObject*>(node); if (op == nullptr) return false; BaseDocument* doc = op->GetDocument(); if (doc == nullptr) return false; if (linkedObject->FindEventNotification(doc, op, NOTIFY_EVENT::CACHE)) { return linkedObject->RemoveEventNotification(doc, op, NOTIFY_EVENT::CACHE); } return true; } Bool AddNotification(GeListNode* node, BaseList2D* linkedObject) { BaseObject* op = static_cast<BaseObject*>(node); if (op == nullptr) return false; BaseDocument* doc = op->GetDocument(); if (doc == nullptr) return false; if (!linkedObject->FindEventNotification(doc, op, NOTIFY_EVENT::MESSAGE)) { return linkedObject->AddEventNotification(op, NOTIFY_EVENT::MESSAGE, NOTIFY_EVENT_FLAG::NONE, nullptr); } return true; } Bool Message(GeListNode* node, Int32 type, void* data) override { if (type == MSG_NOTIFY_EVENT) { NotifyEventData *eventData = static_cast<NotifyEventData*>(data); // as we can add several notification we check if we received the right one if (eventData->eventid == NOTIFY_EVENT::MESSAGE) { NotifyEventMsg* eventMsg = static_cast<NotifyEventMsg*>(eventData->event_data); // Checks if the message that the object is fowarding us if the right one. (MSG_DESCRIPTION_POSTSETPARAMETER) if (eventMsg->msg_id == MSG_DESCRIPTION_POSTSETPARAMETER) { DescriptionPostSetValue* dpsv = static_cast<DescriptionPostSetValue*>(eventMsg->msg_data); const Int32 id = dpsv->descid[0][0].id; // Checks if the parameter that have been change is part of the message. if (id == OBJ_COLOR) { // ask the shader to update itself. node->SetDirty(DIRTYFLAGS::ALL); node->Message(MSG_DESCRIPTION_POSTSETPARAMETER); // this will trigger the mat update and the viewport update. (with a small delay) } } } return true; } return SUPER::Message(node, type, data); } private: Vector color = Vector(1); }; Cheers, Manuel
  • FieldList, and how to properly use it

    Cinema 4D SDK r20 r21 s22 r23 c++
    8
    0 Votes
    8 Posts
    953 Views
    fwilleke80F
    Thank you!
  • Compare only parts of two BaseContainers()

    Cinema 4D SDK r20 r21 s22 r23 c++
    6
    0 Votes
    6 Posts
    632 Views
    fwilleke80F
    Nice, Manuel, thank you! I guess, I'll try the SetDParameter() approach, too, in good time. Cheers, Frank
  • What is Vector.GetLengthSquared() really meant for?

    Cinema 4D SDK r21 python
    5
    0 Votes
    5 Posts
    864 Views
    CairynC
    @zipit said in What is Vector.GetLengthSquared() really meant for?: My major point was that there are certain programming assumptions (multiplication is better than division, never take the square root if avoidable, cubic complexity is uncomputable, etc.) that should be taken with a grain of salt due to the fact that they rely on a certain "state" of hardware. I.e. all these three do not really hold true anymore to the extent they once did. (...) That goes without saying... ultimately, any effort towards optimization needs to be checked for effectivity. Nevertheless, I was curious and abused a plugin of mine to execute some timer checks in C++, just for comparison (code excerpt only): using namespace std::chrono; Vector v(100.0, 100.0, 100.0); float f; milliseconds ms1, ms2, diff; ms1 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); for (int i = 0; i < 100000000; i++) { f = 0; // v.GetLength(); } ms2 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); diff = ms2 - ms1; GePrint(maxon::String("Time counter Empty:") + maxon::String::IntToString(diff.count())); ms1 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); for (int i = 0; i < 100000000; i++) { f = v.GetLength(); } ms2 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); diff = ms2 - ms1; GePrint(maxon::String("Time counter GetLength:") + maxon::String::IntToString(diff.count())); ms1 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); for (int i = 0; i < 100000000; i++) { f = v.GetSquaredLength(); } ms2 = duration_cast<milliseconds>( system_clock::now().time_since_epoch() ); diff = ms2 - ms1; GePrint(maxon::String("Time counter GetSquaredLength:") + maxon::String::IntToString(diff.count())); Switching off all optimizations, I get (for multiple button presses): Time counter Empty:185 Time counter GetLength:921 Time counter GetSquaredLength:228 Time counter Empty:184 Time counter GetLength:922 Time counter GetSquaredLength:228 Time counter Empty:183 Time counter GetLength:921 Time counter GetSquaredLength:228 Time counter Empty:183 Time counter GetLength:922 Time counter GetSquaredLength:228 Time counter Empty:185 Time counter GetLength:921 Time counter GetSquaredLength:228 Time counter Empty:183 Time counter GetLength:921 Time counter GetSquaredLength:227 That is far more like what I expected (double so if you consider that the loop with a constant assignment already takes 185ms). Considering that I had to up the loop count to a hundred million to get measurable results, it is practically guaranteed that any difference between GetLength and GetLengthSquared in the Python sample is drowned in the Python interpreter's overhead, and any result from my initial tests must be attributed to sheer randomness.
  • Possibility of using ExecuteSubID with ToolData.

    General Talk r21 c++
    2
    1
    0 Votes
    2 Posts
    458 Views
    r_giganteR
    Hi @Danchyg1337, thanks for reaching out to us. The approach you've pointed out can work to activate a ToolData with a specific preset. You've to register a CommanData for every preset you'd like your ToolData to use and, if needed, you can register your ToolData passing the PLUGINFLAG_HIDEPLUGINMENU to avoid that the generic ToolData appears among the menus. Best, Riccardo
  • UVW values inconsistency

    Cinema 4D SDK r21 s22 c++ python
    4
    0 Votes
    4 Posts
    897 Views
    rsodreR
    @r_gigante good to know, thanks!
  • Can't add plugin name into cinema4d

    General Talk r21
    5
    0 Votes
    5 Posts
    6k Views
    ferdinandF
    Hi, without further feedback, we will consider this thread as solved by Wednesday and flag it accordingly. Cheers, Ferdinand
  • The slider tool returns False.

    General Talk r21 python
    2
    0 Votes
    2 Posts
    568 Views
    M
    Hi @x_nerve the ID used is not the correct one you should use: 431000021 for edge mode and 431000030 for point mode, unfortunately, there are no symbols for these tools. Cheers, Maxime.
  • Select several files in LoadDialog()

    Cinema 4D SDK r21 python
    3
    0 Votes
    3 Posts
    357 Views
    B
    @r_gigante Ah gotcha. Thanks for the confirmation.
  • 0 Votes
    4 Posts
    505 Views
    B
    Thanks for the response @m_magalhaes Oh thanks. It now works on native c4d emitter but not in xparticles emitter. No worries, the solution by @zipit works @zipit Thanks. It works as expected. Here's the code I used added in a python tag orig = doc.SearchObject("original") dup = doc.SearchObject("duplicate") orig_container = orig.GetDataInstance() orig_container.CopyTo(dup.GetDataInstance(), flags= c4d.COPYFLAGS_PRIVATE_CONTAINER_COPY_IDENTICAL, trans=None) c4d.EventAdd()
  • Get the Next Object of doc.SearchObject() Method?

    Cinema 4D SDK r21 python
    3
    0 Votes
    3 Posts
    595 Views
    B
    @m_adam Ah gotcha. Thanks for the confirmation and the sample code.
  • C4D R21.207 Console don't do anything

    Cinema 4D SDK r21 python
    10
    1
    0 Votes
    10 Posts
    2k Views
    C
    Finally fix it! I reinstalled c4d and everything goes well! Thank you for all you helps!
  • Access C4D Objects outside C4D?

    Cinema 4D SDK r21 python
    10
    0 Votes
    10 Posts
    974 Views
    M
    VS Code and Sublime Text are not so well designed and simply spawn a bunch of python interpreters to retrieve the information they need, In contrast, pycharm does use only one and the same python interpreter its spawn. So that's why you got these issues.
  • c4dpy.exe asking for credentials?

    General Talk r21 python
    3
    0 Votes
    3 Posts
    454 Views
    M
    Hi @bentraje as you already figured out in the documentation for R21+ this is necessary because each version (c4dpy, CommandLine, TRS, TRC) now have their own preference folder and doesn't share anymore the one from c4d. Cheers, Maxime.
  • PySide2 for Python 2.7 Windows Version?

    General Talk r21 python
    15
    0 Votes
    15 Posts
    4k Views
    ferdinandF
    Hello @bentraje, no need to be sorry and thanks for closing it Cheers, Ferdinand
  • 0 Votes
    5 Posts
    860 Views
    ManuelM
    hi, I'm a bit surprised that your render can be triggered from a NodeData (but why not) But i don't understand why you can't use GetDDescription to update your node. That's what i did (in a probably too naive way) but you got the idea. I just got a boolean display_aboard on my ObjectData and i switch it as i needed. If i presse the button, i switch and i set dirty my node, if i receive the message that the render is finished (or stopped) i set my bool to false and i SetDirty my node. static const Int32 g_pc12584ButtonID = 1000; class pc12584_object : public ObjectData { INSTANCEOF(pc12584_object, ObjectData); public: static NodeData* Alloc() { return NewObjClear(pc12584_object); }; Bool Init(GeListNode* node) override { display_aboard = false; return true; } BaseObject* GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) override { BaseObject* null = BaseObject::Alloc(Onull); return null; } Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) override { if (!description->LoadDescription(Obase)) return false; const DescID* singleid = description->GetSingleDescID(); const Int32 ID = g_pc12584ButtonID; const DescID cid = DescLevel(ID, DTYPE_BUTTON, 0); if (!singleid || cid.IsPartOf(*singleid, nullptr)) { BaseContainer bc = GetCustomDataTypeDefault(DTYPE_BUTTON); bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON); if (display_aboard) bc.SetString(DESC_NAME, "Aboard Render"_s); else bc.SetString(DESC_NAME, "Render"_s); bc.SetInt32(DESC_ANIMATE, DESC_ANIMATE_OFF); bc.SetInt32(DESC_SCALEH, 1); description->SetParameter(cid, bc, DescLevel(ID_OBJECTPROPERTIES)); } flags |= DESCFLAGS_DESC::LOADED; return SUPER::GetDDescription(node, description, flags); } Bool Message(GeListNode* node, Int32 type, void* data) override { switch (type) { case MSG_DESCRIPTION_COMMAND: { DescriptionCommand* dc = (DescriptionCommand*)data; const Int32 id = dc->_descId[0].id; if (id == g_pc12584ButtonID) { display_aboard = !display_aboard; node->SetDirty(DIRTYFLAGS::DESCRIPTION); } break; } case g_pc12584Message: { display_aboard = false; node->SetDirty(DIRTYFLAGS::DESCRIPTION); break; } } return SUPER::Message(node, type, data); }; private: Bool display_aboard = false; }; // function to send a message to the ObjectData. static maxon::Result<void> PC12854_Message(BaseDocument* doc) { iferr_scope; // update the first object BaseObject* op = doc->GetFirstObject(); if (op == nullptr) return maxon::NullptrError(MAXON_SOURCE_LOCATION); op->Message(g_pc12584Message); return maxon::OK; } Cheers, Manuel