• Content of PYTHONPATH not appended to sys.path

    python windows r20
    5
    1 Votes
    5 Posts
    2k Views
    bnsB
    @m_adam thanks for R23.110 C4DPYTHONPATH37 !
  • Zooming on object or scene invalidates object cache?

    c++ r23
    3
    0 Votes
    3 Posts
    335 Views
    fwilleke80F
    Scary 🥶 If the objects are already being displayed in the viewport, I don't see why their caches should be rebuilt, just to zoom on the objects (especially when using "O" to zoom on just one single object). Also, properly programmed generator objects should return their bounding box in BaseObject::GetRad() and BaseObject::GetMp(). As far as I see the zooming behavior with "O", only the bounding box is used anyway, so the cache shouldn't even be required for this. That's a pity. But thanks for the answer! Cheers, Frank
  • R23 update time?

    8
    0 Votes
    8 Posts
    988 Views
    fwilleke80F
    Thanks!
  • Rename object by filename

    Moved python
    10
    0 Votes
    10 Posts
    2k Views
    J
    @zipit @lasselauch thank you both for your time and knowledge!
  • PYTHON GENERATOR ISSUES

    r20 python
    3
    0 Votes
    3 Posts
    411 Views
    gheyretG
    @Cairyn Thank you for your reply. The "odd result" it's means the scene is empty , no objects were generated. According to your explanation, I have solved the problem. And it's just an exercise code. Thank you again !
  • 0 Votes
    4 Posts
    2k Views
    M
    @m_adam Thanks for the clarification. Regards, Georgi.
  • Option to wait for c4d to catch up with script ? Memory wise and EventAdd?

    10
    0 Votes
    10 Posts
    2k Views
    ferdinandF
    Hi @mogh, thanks, but I will probably only have a chance to look at it tomorrow. Happy coding and rendering in the mean time Cheers, Ferdinand
  • Help with Matrix Manipulation after c4d.MCOMMAND_JOIN

    python r23 r20
    16
    0 Votes
    16 Posts
    3k Views
    ferdinandF
    Hi, ten times slower sounds rough. It is probably because I was a bit lazy and used a lookup table (visited) to traverse the scene-graph, which is a rather expensive thing to do. Feel free to use the fixed traversal if performance becomes an issue here. Cheers, Ferdinand
  • Plugin not loaded in R23 on macOS

    14
    1 Votes
    14 Posts
    3k Views
    kbarK
    Python plugins do not work reliably in R23 on OSX 10.13.6. The C4D minimum spec is for 10.14.6 as Riccardo mentioned. And even if you try to debug a plugin on 10.13.6 what you will notice is that many calls (such as print) don't even work on this OS. So you can't even write anything out to the console to see what the problem might be. No amount of re-installing C4D will help you at all. You just have to let your customers know that the minimum spec for R23 is 10.14.6 and not guarantee any support for anything below that spec.
  • BaseLinkArray looses link? (was: Refreshing a nested BaseShader)

    r20 r21 s22 r23 c++
    19
    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
  • Cannot set ID_BASEOBJECT_USECOLOR to a child object.

    4
    0 Votes
    4 Posts
    663 Views
    M
    @m_adam Yay thank you very much! Was almost ready to compromise with the default color. Will use the Q&A functionality, excuse me for the posts so far. Warm regards, Georgi.
  • Does QUANTIZE_GRID actually do anything?

    r23 python
    3
    0 Votes
    3 Posts
    508 Views
    CairynC
    Thanks for the confirmation. (Follow-up questions moved to a separate post)
  • Vertex Maps on Generators

    r23 python
    5
    0 Votes
    5 Posts
    1k Views
    K
    Apologies, I thought my mention of the Voronoi Fracture's ability to generate vertex map tags (itself being a generator that deals with variable geometry) would be clear enough, but I suppose a casual mention doesn't suffice for an app this complex, haha! Yeah, it's really all about overcoming that immutable nature of the vertex map tag. I'm generating them on parametric objects and I need them to be able to adapt to changing point counts. Just like they're able to do on editable polygon objects. Which means I have to create a new tag each time the host object's geometry changes and update anywhere else it's linked. That's where TransferGoal() comes in. Where my function was failing was a result of TransferGoal() not only updating the BaseLinks, but also the variables within my code. So in my function, once TransferGoal()is called, both vmap and replacement_tag variables end up referencing the same tag (the new one), leaving me without a variable filled with the old tag to delete. Passing True as the second argument left my variables alone and only updated the links, essentially making it work perfectly. So passing True or False to TransferGoal() didn't make any difference as far as the BaseLinks were concerned. Those always updated correctly. If I had to guess I would say it has to do with the memory addresses of the objects being transferred... which is just more reason to avoid ignoring that little instruction in the sdk;) I'll trust the devs on matters of memory handling lol. Turns out it's quite easy to work around. Since I insert the new tag directly after the old tag I can simply use GetPred() to find the old tag and successfully delete it. As far as your question as to whether I would consider this desirable or expected behavior, I would say no. I would much prefer that my in-code variables remain as they were before calling TransferGoal, because as it currently is I'm left with two distinct variables that hold the same object. In other words, I'm left with redundancy and it ends up preventing me from doing more to the old BaseList2D object. In my case, it happens to be relatively easy to re-find and re-reference that BaseList2D object, but that might not always be the case. But yeah, now I have a working skeleton function (that doesn't break the rules lol). Just gotta bulk it up with appropriate checks and I should be good to go! Thanks for your help @zipit! Cheers! Kevin
  • Finding Control ID in ObjectData Plugin Message() Override

    r23 python windows
    9
    0 Votes
    9 Posts
    1k Views
    ?
    @zipit Hi, thank you for the message. Yes, I believe I already understood everything you explained and I do appreciate your efforts. I knew I wasn't doing anything with the descid in my code, I was just confused as to why when I change one attribute, I was getting MSG_DESCRIPTION_POSTSETPARAMETER messages from all of the attributes as opposed to just the one attribute. Perhaps it is something else in my code that is sending those. Regardless, it isn't hugely important, I was trying to be as efficient as possible. Thank you.
  • Creating NGONs low level with NgonBase::BuildNgon() ?

    r23 sdk c++
    8
    0 Votes
    8 Posts
    2k Views
    WTools3DW
    @m_magalhaes Thanks Manuel! When I fill-in only Inner edges in NgonBase::BuildNgon, then it surprisingly works I don't know why I tested all combinations except this one There are still some minor glitches, some inner edges are randomly not hidden, but ngons created are valid for all the cases I have tested. Random glitches are easily fixable with forcing all inner edges to be hidden. I will test it more, but this seems to be reliable for now. NGONS import - read outer edges directly from Pgon::*m_Edge array NGONS export - with NgonBase::BuildNgon(), filling Inner edges only, and force hide inner edges on quads. Thanks a lot Manuel, Your help has been very valuable to me. Regards, Viktor.
  • Drawing large amounts of billboarded triangles in the viewport

    c++ r23 sdk
    16
    2
    0 Votes
    16 Posts
    2k Views
    r_giganteR
    As already told by @zipit, I'm terribly sorry for coming so late here. I've prepared a full example showing how to fill a VertexColorTag in the ObjectData::GetVirtualObjects() and use this values to color the triangles shown up in the ObjectData::Draw() method. My code actually uses the VertexColorTag::SetColor()/GetColor(). [image: 1605105495571-5b4213d8-e4b4-434a-ad71-5ef0d69be6ea-image.png] The VertexColorTag in this case is not specify to each vertex of the triangle but specifies the color for the whole triangle: this is because the tag is created in the ObjectData::GetVirtualObjects() and store color for each point of the cloud, but then it's used in the ObjectData::Draw() method to specify the ObjectColorProperty used to color the drawn PolygonObject. As far as I know the BaseDraw::DrawPolygonObject() ignores any VertexColorTag assigned to the PolygonObject to be drawn. BaseObject* PC_12974::GetVirtualObjects(BaseObject* op, HierarchyHelp* hh) { // check cache before continue BaseObject* cache = op->GetCache(); if (cache) return cache; // init the random gen and get a arbitrary number of tris _rndGen.Init(GeGetTimer()); _randomTrisCnt = (SAFEINT32(_rndGen.Get01() * (1 + _max - _min)) + _min); // allocate a PolygonObject and fill it with points randomly PolygonObject* po = PolygonObject::Alloc(_randomTrisCnt, 0); if (!po) return BaseObject::Alloc(Onull); // fill the points array with random positions Vector* points = po->GetPointW(); for (Int32 i = 0; i < _randomTrisCnt; i++) points[i] = Vector (100.0 * _rndGen.Get11(), 100.0 * _rndGen.Get11(), 100.0 * _rndGen.Get11()); // look for VertexColor tag BaseTag* tag = po->GetTag(Tvertexcolor); // if not existing just create a new one VertexColorTag* vcTag = nullptr; if (!tag) { tag = VertexColorTag::Alloc(_randomTrisCnt); po->InsertTag(tag); } vcTag = static_cast<VertexColorTag*>(tag); vcTag->SetPerPointMode(true); VertexColorHandle handle = vcTag->GetDataAddressW(); // fill the vertexcolor tag with random values for (Int32 i = 0; handle && i < _randomTrisCnt; i++) VertexColorTag::SetColor(handle, nullptr, nullptr, i, maxon::Color32(_rndGen.Get01(), _rndGen.Get01(), _rndGen.Get01())); // update host object po->Message(MSG_UPDATE); return po; } Bool PC_12974::TriangleOnPoint(const Vector &pos, PolygonObject& po) { // given a point create a triangle centered over there. Vector* points = po.GetPointW(); const Matrix poMG = po.GetMg(); const Vector posMG = poMG * pos; if (!points) return false; // set vertexes positions for the triangle. points[0] = Vector(0, 0, _triangleRad) + posMG; points[1] = Vector(_triangleRad * Cos(-PI / 6), 0, _triangleRad * Sin(-PI / 6)) + posMG; points[2] = Vector(_triangleRad * Cos(-PI * 5 / 6), 0, _triangleRad * Sin(-PI * 5 / 6)) + posMG; // create the polygon CPolygon* polys = po.GetPolygonW(); if (!polys) return false; polys[0] = CPolygon(0, 1, 2); return true; } DRAWRESULT PC_12974::Draw (BaseObject *op, DRAWPASS drawpass, BaseDraw *bd, BaseDrawHelp *bh) { // skip anything but OBJECT drawpass if (drawpass != DRAWPASS::OBJECT) return DRAWRESULT::SKIP; // check for the object and its cache if (op && op->GetCache()) { // get the PolygonObject from the cache PolygonObject* opPO = static_cast<PolygonObject*>(op->GetCache()); // look for the attached VertexColor Tag BaseTag* const tag = opPO->GetTag(Tvertexcolor); if (!tag) return DRAWRESULT::SKIP; VertexColorTag* const vcTag = static_cast<VertexColorTag*>(tag); // retrieve the read-only handle ConstVertexColorHandle vcTagHandleR = vcTag->GetDataAddressR(); // get the points and iterate over the VertexColor to set the color // of each triangle drawn maxon::Int pointCnt = opPO->GetPointCount(); Vector const *points = opPO->GetPointR(); for (maxon::Int i = 0; i < pointCnt; i++) { maxon::Color32 vtxCol(0.0); // get the color if (vcTagHandleR && vcTag->IsPerPointColor()) vtxCol = VertexColorTag::GetColor(vcTagHandleR, nullptr, nullptr, (Int32)i); // set the color in the ObjectColorProperties ObjectColorProperties colProp; colProp.usecolor = ID_BASEOBJECT_USECOLOR_ALWAYS; colProp.color.x = vtxCol.r; colProp.color.y = vtxCol.g; colProp.color.z = vtxCol.b; colProp.xray = false; // allocate the temp triangle PolygonObject* tri = PolygonObject::Alloc(3, 1); // set the color prop, create the tri and draw! tri->SetColorProperties(&colProp); if (TriangleOnPoint(op->GetMg() * points[i], *tri)) bd->DrawPolygonObject(bh, tri, DRAWOBJECT::NONE, nullptr); // free the tri PolygonObject::Free(tri); } } return DRAWRESULT::OK; } Feel free to comment and again sorry for the silence. Riccardo
  • How to enforce StatusBar redraws

    r21 python windows
    11
    0 Votes
    11 Posts
    1k Views
    M
    I am also having trouble to get the Status bar to update while a script is running. My old scripts using Callcomand nevertheless update the Status bar fine ...?!? nevermind got it working again ... mistake on my end. (passed a small flot to the statusbar instead of 0-100. kind regards mogh
  • Using Icons with Integer Cycle in a Plugin

    python windows r23
    3
    1
    0 Votes
    3 Posts
    394 Views
    ?
    @kbar Thank you for the reply and helpful link. And for anyone look to get this working with your Description files: (from https://c4dprogramming.wordpress.com/2013/05/10/long-cycles-with-icons-and-separator/), put the plugin ids in your Description header and this in your Description resource file: CONTAINER Omyobject { NAME Omyobject; INCLUDE Obase; GROUP ID_OBJECTPROPERTIES { LONG MYOBJECT_ICONCYCLE { CYCLE { MYOBJECT_ICONCYCLE_ITEM_0; -1; MYOBJECT_ICONCYCLE_ITEM_1~Ocube; MYOBJECT_ICONCYCLE_ITEM_2~Opyramid; MYOBJECT_ICONCYCLE_ITEM_3~1021433; } } } } -1 creates a separator.
  • This topic is deleted!

    1
    0 Votes
    1 Posts
    9 Views
    No one has replied
  • Find BaseMaterial that owns a BaseShader?

    r20 r21 r23 s22 c++
    4
    0 Votes
    4 Posts
    492 Views
    ManuelM
    hi, Confirmed, thanks @mp5gosu. That also work if the shader is inside another shader. Cheers, Manuel