Overriding `NodeData::GetAccessedObjects(..)` prevents cache generation of cloned hierarchy
-
Hi, I'm currently trying to implement the new
NodeData::GetAccessedObjects(..)
as described in this post. But something is not right, because after derived for one particular object, the objects in the cache are left without their caches.To give a bit more details - I have an object generator implementation, which is effectively cloning its child hierarchy and putting it under a Connector object. But after adding an override of
NodeData::GetAccessedObjects(..)
for this generator object, the cache is missing. A simplified version of my code below:maxon::Result<Bool> MyGenerator::GetAccessedObjects(const BaseList2D *node, METHOD_ID method, AccessedObjectsCallback &access) const { yield_scope; switch (method) { case METHOD_ID::GET_VIRTUAL_OBJECTS: { node->GetAccessedObjectsOfFirstChildHierarchy( ACCESSED_OBJECTS_MASK::ALL | ACCESSED_OBJECTS_MASK::GLOBAL_MATRIX, ACCESSED_OBJECTS_MASK::CACHE, METHOD_ID::GET_VIRTUAL_OBJECTS_AND_MODIFY_OBJECT, access ) yield_return; return access.MayAccess( node, ACCESSED_OBJECTS_MASK::DATA | ACCESSED_OBJECTS_MASK::GLOBAL_MATRIX, ACCESSED_OBJECTS_MASK::CACHE ); } } return ObjectBase::GetAccessedObjects(node, method, access); } BaseObject* MyGenerator::GetVirtualObjects(BaseObject *object, const HierarchyHelp *hierarchyHelp) { BaseObject *firstChild=object->GetDown(); if (!firstChild) { return nullptr; } bool dirtyInput=false; BaseObject *input=object->GetAndCheckHierarchyClone(hierarchyHelp, firstChild, HIERARCHYCLONEFLAGS::ASIS, &dirtyInput, nullptr, true); if (input) { if (!dirtyInput) { return object->GetCache(); } BaseObject *cacheRoot=BaseObject::Alloc(Oconnector); if (!cacheRoot) { return cacheRoot; } input->InsertUnder(cacheRoot); return cacheRoot; } return nullptr; }
I tried several different flags to be used in the
GetAccessedObjects(..)
implementation, but none seemed to work. Only usingacess.MayAccessAnything()
in the implementation results in the previous behavior, but that is not the point of actually using the function.Am I missing something obvious or there might be a problem with my approach as a whole?
-
Hi Deyan,
your code for GetAccessedObjects is correct. The problem is that you use the connect object, and this object doesn't implement GetAccessedObjects yet. There are a lot of objects in the C4D code base, and we at Maxon haven't had the time yet to implement GetAccessedObjects for all of them.
A GetAccessedObjects implementation has to tell about all access which GetVirtualObjects will make to the scene, and also about all access which the objects created by GetVirtualObjects will make to the scene when GetVirtualObjects is called on them. Also all objects created by GetVirtualObjects have to support GetAccessedObjects. The connect object doesn't, so your code fails.
The connect object will support GetAccessedObjects in 2024.4. So you have to wait a bit, I'm sorry.
-
There's no way for you to know if an object implements
GetAccessedObjects
or not. And even if there was a way, that wouldn't help in general because that implementation could still decide to callMayAccessAnything()
, e.g. based on the object's settings. You need the knowledge that the connect object supportsGetAccessedObjects
AND won't callMayAccessAnything()
in the configuration which you create in your code.The only clean way would be to call
GetAccessedObjects
on the connect object withinMyGenerator::GetAccessedObjects
. That's whatnode->GetAccessedObjectsOfFirstChildHierarchy()
does with the object's children. But you don't have the connect object yet inGetAccessedObjects
, so that's not feasible. -
Thank you for you answer @o_kniemeyer . Just to be clear about the proper implementation once
GetAccessedObjects(..)
is implemented for the Connector - what are the minimal read and write flags for the hierarchy call, ifGetVirtualObjects(..)
callsGetAndCheckHierarchyClone(hierarchyHelp, firstChild, HIERARCHYCLONEFLAGS::ASIS, &dirtyInput, nullptr, true);
. I'm asking because in my example I tried withACCESSED_OBJECTS_MASK::ALL | ACCESSED_OBJECTS_MASK::GLOBAL_MATRIX
for read andACCESSED_OBJECTS_MASK::CACHE
for write, but I have a suspicion this may not be optimal (the write flags even feel wrong). -
The function
GetAndCheckHierarchyClone
creates clones of all children, therefore it has to read everything from the children and you needACCESSED_OBJECTS_MASK::ALL
in the read part. It'll also mark the children as being consumed by your generator so that they don't create virtual objects on their own (only their clones in the cache of your generator will create virtual objects), and for this mark you needACCESSED_OBJECTS_MASK::CACHE
in the write part.GetAndCheckHierarchyClone
doesn't read global matrices, so theGLOBAL_MATRIX
flag isn't needed.The flags in the other call can be reduced to
access.MayAccess(node, ACCESSED_OBJECTS_MASK::NONE, ACCESSED_OBJECTS_MASK::CACHE)
. That's because yourGetVirtualObjects
doesn't read anything from the generator itself (NONE
), it'll only set up its virtual objects (CACHE
). As soon as you access the BaseContainer of your generator, you have to addDATA
. For the matrixMATRIX
or evenGLOBAL_MATRIX
etc. -
Thanks a lot for the clarification! It would be nice to include more usecase examples of
GetAccessedObjects(..)
implementation in the SDK examples in the future. I will try your suggestion once 2024.4 becomes available.