GVO PolygonObject inside NullObject untargetable

On 27/04/2018 at 13:02, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   R19.053 
Platform:   Windows  ;   
Language(s) :     C++  ;

Hi! I have a generator plugin that creates PolygonObjects and returns them collectively under a
single Null-Object.

It may choose to reuse some of the PolygonObjects from the previously generated  cache. it does
so using the cach e from op- >GetCache(hh); , then finding the res pectivePolygonObject, calling
Remove() and inserting it under the new Null-Object that will be returned with InsertUnderLast().

When it creates the PolygonObject from scratch, it allocates it, uses ResizeObject() , then sets
the polygons and points in GetPointW() and GetPolygonW() and calls Message(MSG_UPDATE);.

The reason why I think that the MSG_UPDATE message has no effect is because the bounding
box of the PolygonObject does not seem to be updated properly. Also the PolygonObject returned
by the generator can not be target with the "navigation pivot" in the C4D viewport.

Is there anything else that I need to do to "complete" the PolygonObject after I built it?


On 30/04/2018 at 02:08, xxxxxxxx wrote:

Hi Niklas,

Polygon objects within a cache are read-only.
You can't modify them, but you can clone it and then SetPoint/Polygon will work.

About your issue of the bounding box, make sure to override GetDimension.


On 03/05/2018 at 02:51, xxxxxxxx wrote:


not sure, this is already solved.
Still, I'd like to add a link to the extended number of ObjectData examples for future readers.

On 03/05/2018 at 06:01, xxxxxxxx wrote:

Hi Maxime & Andreas, thanks for the reply.

>> Polygon objects within a cache are read-only.

I am not making modifications to the polygon objects inside existing caches -- I am creating new
Polygon Objects. However when I recognize that the Polygon Object that I would build from scratch
already exists in the cache due to the previous call to GetVirtualObjects(), I want to re-use that.

Similar to returning the whole cache, as it can be seen in some of the example ObjectData plugins:

if (nothing changed) {  
  return op->GetCache(hh);  

I may want to select only some of the Polygon Objects in the cache.

AutoAlloc<BaseObject> root(Onull);  
BaseObject* cache = op->GetCache(hh);  
for (auto&& obj : input_objects) {  
  if (nothing_changed && cache) {  
  BaseObject* cache_obj = FindObjectInCache(cache, GetUuid(obj));  
  if (cache_obj) {  // Reuse the object  
  AutoAlloc<PolygonObject> poly(0, 0);  
  // ... build polygon object  

This works without problems as far as I can see. Just to check whether this causes the issue that
you can not navigate on top of the object, I tried cloning the object from the cache (which would
not be desirable) and I get the same problem.

    if (cache_obj) {  // Reuse the object  
    cache_obj = (BaseObject* ) cache_obj->GetClone(COPYFLAGS_0, nullptr);  
    if (cache_obj) {  

>> About your issue of the bounding box, make sure to override GetDimension.

Overriding GetDimension() will not solve the problem that I am facing.

I try to be more descriptive: When you have an object in the Viewport, you can press ALT and LEFT
MOUSE BUTTON to pivot around the object at the location where your cursor intersects with the

This does not work in my case. And I am wondering if you have any clues where this could be
coming from. My initial guess was that I needed to use MSG_UPDATE before I return the object,
but that didn't help.

Here is a small video that hopefully clarifies the issues: https://public.niklasrosenstein.com/_quickshare/2018-05-03-generator-polygonobject-navpivot.flv

The cube is a standard cube, the two cars are both Polygon Objects returned by my generator.

Any idea what could cause the Pivot to not recognize the geometry from my generator?

Thanks for looking into this.


On 04/05/2018 at 02:57, xxxxxxxx wrote:

Hi Niklas,

just as a test, can you please leave all optimizations aside. If you build the output of your generator from scratch, does it work properly then?

On 05/05/2018 at 03:02, xxxxxxxx wrote:

Hi Andreas,  I get the same problem without reusing the cache but building the PolygonObject
anew every time (although the geometry information does come from a different representation
fromanother SDK).

However from your suggestions, I tried to reproduce it my just building a simply triangle to be sure
that it's not an issue with the geometry that I get from the SDK. It seems like the culprit is actually
that the PolygonObject is inside a Null-Object. When I return the PolygonObject directly, it works

    AutoAlloc<BaseObject> root(Onull);  
  AutoAlloc<PolygonObject> poly(3, 1);  
  auto p = poly->GetPointW();  
  p[0] = Vector(100, 0, 0);  
  p[1] = Vector(100, 0, 100);  
  p[2] = Vector(0, 0, 100);  
  auto c = poly->GetPolygonW();  
  c[0] = CPolygon(0, 1, 2);  
  return root.Release();


On 05/05/2018 at 06:48, xxxxxxxx wrote:

Renamed from MSG_UPDATE for PolygonObject has no effect in GVO to GVO PolygonObject inside NullObject untargetable.

On 08/05/2018 at 08:16, xxxxxxxx wrote:

Hi Niklas,

I need to ask you for a bit of patience. I can reproduce the issue, but to be honest I don't get it. Take for example the Array object with a polygon object as input. The resulting cache structure is exactly the same and there it works as expected. Haven't been able to spot the difference, yet. Stay tuned.

On 14/05/2018 at 06:04, xxxxxxxx wrote:

Hi Niklas,

sorry, this took a bit longer. In the end it's a matter of proper use of the cache. The "pivot feature" relies on a somewhat constant cache.
By just adding these three lines to the top of your example, the pivot feature works just fine:

  Bool dirty = op->CheckCache(hh) || op->IsDirty(DIRTYFLAGS_DATA);
  if (!dirty)
    return op->GetCache(hh);

On 15/05/2018 at 09:26, xxxxxxxx wrote:

Thank you Andreas. Making sure that I keep returning the same Null-Object makes it work.
I pick certain objects from the cache and insert them under a new hierarchy. Now instead of
returning that new hierarchy, I simply replace the parent of the hierarchy with the previous

    // The navigation pivot in C4D seems to require a rather "constant cache"  
  // from the object if a Null-Object is used as root. We'll just reuse the  
  // previous cache null object if there is any.  
  if (cache) {  
    for (BaseObject* child = cache->GetDown(); child;) {  
      BaseObject* next = child->GetNext();  
      child = next;  
    for (BaseObject* child = root->GetDown(); child;) {  
      BaseObject* next = child->GetNext();  
      child = next;  
    return cache;  
  return root.Release();