VolumeBuilder Cache and AddDependence()
-
Hello, I'm trying to create and ObjectPlugin that is taking a VolumeBuilder in as a child object.
In general I'm able to get the information from the VolumeBuilder that I need, but I haven't be able to mark it as used and have it hidden in the viewport.
When I run this code it works as desired, but if I enable the NewDependenceList() through TouchDependenceList() then the VolumeBuilder is hidden as expected, but I can no longer retrieve the VolumeBuilder's cache.
This doesn't seem to be a problem with other objects in the same situation, but the VolumeBuilder doesn't seem to work here. Is there something I'm missing here?
BaseObject* ForumTest::GetVirtualObjects(BaseObject* op, const HierarchyHelp* hh) { BaseObject* down = op->GetDown(); BaseObject* object = down; /* op->NewDependenceList(); Bool dirtyBool; while (down != nullptr) { op->GetHierarchyClone(hh, down, HIERARCHYCLONEFLAGS::ASVOLUME , &dirtyBool, nullptr); op->AddDependence(down); down = down->GetNext(); } op->TouchDependenceList(); */ if (object == nullptr) { ApplicationOutput("Child object is nullptr"); return BaseObject::Alloc(Osphere);; } if (object->IsInstanceOf(Ovolumebuilder) == false) { ApplicationOutput("Not a volumebuilder"); return BaseObject::Alloc(Osphere);; } VolumeBuilder* const volumeBuilder = static_cast<VolumeBuilder*>(object); //if AddDependence() is used than the volumeBuilder is always a nullptr BaseObject* const cache = volumeBuilder->GetCache(); if (cache == nullptr) { ApplicationOutput("No cache, happens when marking Dependence"); return BaseObject::Alloc(Osphere);; } if(cache->IsInstanceOf(Ovolume) == false) { return BaseObject::Alloc(Osphere);; } const VolumeObject* const volumeObject = static_cast<VolumeObject*>(cache); maxon::Volume volume = volumeObject->GetVolume(); if(volume == nullptr) { } else { } ApplicationOutput("Successfully reached the end"); return BaseObject::Alloc(Osphere); }
-
Hi @d_schmidt ,
Sorry for the delayed answer.
The way you use Dependence-functions the observed result is expected, because this is how the TouchDependenceList() function works.
I assume you would like to process the Volume yourself in order to infer some geometry. If that's the case, I would recommend you to check if your dependence list is dirty, and return the cache (without expensive calculations) if that's the case. Otherwise, you can go ahead and perform your calculations.
Please check the attached script snippet for the GetVirtualObjects() function, which generates the cube that represents the volume bounding box.
Cheers,
IliaUpdated on 16/11/23:
- final TouchDependenceList() call
- improved isDirty flag initialization (check op cache and check is op is dirty too)
Updated on 10/01/24:
- fixed dirtiness check by removing the AddDependence() function call
- DIRTYFLAGS::DATA should be used instead of DIRTYFLAGS::CACHE
BaseObject* RoundedTube::GetVirtualObjects(BaseObject* op, const HierarchyHelp* hh) { BaseObject* opResult = nullptr; iferr_scope_handler { BaseObject::Free(opResult); return BaseObject::Alloc(Osphere); }; BaseObject* down = op->GetDown(); CheckState(down, "Child object is nullptr"); CheckState(down->IsInstanceOf(Ovolumebuilder), "Not a volumebuilder"); BaseObject* opVB = down; // VolumeBuilder object Bool isDirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS::DATA); op->NewDependenceList(); while (down != nullptr) { op->GetHierarchyClone(hh, down, HIERARCHYCLONEFLAGS::ASVOLUME , &isDirty, nullptr); down = down->GetNext(); } isDirty |= !op->CompareDependenceList(); if (!isDirty) { op->TouchDependenceList(); DiagnosticOutput("Returning CACHE"); return op->GetCache(); } DiagnosticOutput("Calculating NEW_OBJECT"); VolumeBuilder* const volumeBuilder = static_cast<VolumeBuilder*>(opVB); CheckState(volumeBuilder, "Couldn't retrieve volumeBuilder"); BaseObject* const cache = volumeBuilder->GetCache(); CheckState(cache && cache->IsInstanceOf(Ovolume), "Couldn't retrieve cache volume"); VolumeObject* const volumeObject = static_cast<VolumeObject*>(cache); CheckState(volumeObject, "Couldn't retrieve volumeObject"); maxon::Volume volume = volumeObject->GetVolume(); CheckState(volume, "Couldn't retrieve volume"); maxon::Range<Vector> bb = volume.GetWorldBoundingBox(); maxon::Range<Float> minMax = volume.GetMinMaxValues(); Vector size = bb.GetDimension() / 2 * minMax.GetDimension() / 2; opResult = BaseObject::Alloc(Ocube); CheckState(opResult, "Out of memory!"); opResult->SetParameter(CreateDescID(PRIM_CUBE_LEN), size, DESCFLAGS_SET::NONE); op->TouchDependenceList(); return opResult; }
-
Hello @i_mazlov Thanks for the reply!
This is the output I'm getting with your code:
It seems like the code is working in but the Volume Builder is still visible in the viewport.
Should op->TouchDependenceList(); also be called outside of this if statement?
if (!isDirty) { DiagnosticOutput("Returning CACHE"); op->TouchDependenceList(); // hide the original children return op->GetCache(); // return the previous hierarchy }
Dan
-
Hi Dan,
Yes, you're right. The Volume Builder is still visible in the viewport because the final TouchDependenceList() function call after calculating geometry cache is missing. This function call makes Volume Builder to loose its cache, hence we need to first calculate our stuff and only after that touch volume builder.
Please, refer to the updated script in my previous posting.
Cheers,
Ilia -
This post is deleted! -
Hi @i_mazlov
I recently returned to your code, and reading what you just wrote:This function call makes Volume Builder to loose its cache, hence we need to first calculate our stuff and only after that touch volume builder.
This means that even when checking if the Volume Builder is dirty or not, it's being rebuilt?
Wouldn't that be slow to perform? Especially if the idea with checking if its dirty or not is to skip unneeded building.
Dan
-
Hello again!
I recently began working from scratch again. In @i_mazlov 's code above here: https://developers.maxon.net/forum/post/73005 I'm always getting a dirty result and this seems to be incorrect.
My GVO Is purely the provided code and all I have in the scene is my test plugin, and Volume Builder as a child, and then a Cube a a child of the Volume Builder.
Even when nothing is changed in the scene the plugin is returning that's it's dirty and being rebuilt.
Dan
-
Hi Dan,
Yes, you're right, the cache part doesn't work right in the code snippet above. I had a look there and it looks that function GetHierarchyClone adds a dependency deep under the hood of its callstack, which in turn makes CompareDependenceList always set dirty to true. For the fix you can simply remove the
op->AddDependence(down);
line and it would do what you need. (I've updated the code above once again)However, if you actually don't really need using the dependency list here, then I can suggest you using the following part for recalculation check:
Bool isDirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS::DATA); op->GetAndCheckHierarchyClone(hh, firstChild, HIERARCHYCLONEFLAGS::ASVOLUME, &isDirty, nullptr, true); op->TouchDependenceList(); if (!isDirty) { DiagnosticOutput("Returning CACHE"); return op->GetCache(); }
Here, I'm using the GetAndCheckHierarchyClone() function, which actually automatically does everything as we did above but in a more convenient way (and with some more edge cases check).
Please note, that I also changed the dirty flags in IsDirty() function call from CACHE to DATA, as it was misused.
I'm sorry the answer to this thread took so much time.
Cheers,
Ilia -
Hi Illia,
I haven't been able to properly stress test the new code, but by the first look it seems to be working. Thanks!
Dan